Revolver works with a pluggable interface for drivers
and plugins
that are executed per cloud account.
drivers
implement cloud API calls, both query and update.plugins
implement logic for generating actions (start/stop/tag etc)
Main entry is revolver.ts
, which determines what accounts it will run on.
For each account, Revolver does the following (see lib/accountRevolver.ts
):
- Obtain account authentication role.
- For each active driver, query the account for a list of resources.
- For each plugin, pass the discovered resources to generate a list of actions to perform.
- Pass actions to the drivers for execution.
Note: YAML and schema only need updating if adding/changing config.
- Add feature/fix bug
- Update schema in
lib/config-schema.ts
- Update unit tests and the config YAML test:
npm run test
- Update the bundle test YAML:
npm run bundleTest
- Update example YAML
- Update README.md
Create revolver-config.yaml
in the root directory. Configure as necessary.
npm install
npm run build # or 'npm run watch' for a continuous build
npm run start
start
utilizes invoke.ts/js
to call the true revolver.ts
with an event. This is necessary for local execution.
When developing revolver, it's useful to configure it to run entirely locally with the settings:
localResourcesJson: resources.json
: Load resources from a JSON instead of calling cloud APIspretend: true
: Set on each driver, stops the driver from actually performing any actionsrevolverRoleName: none
: Disable obtaining an account role and use whatever credentials are already configured.- For local testing, this just bypasses an attempt to get a role when it doesn't make sense.
- For single account testing, this allows for usage of locally configured credentials where you might not be able to change role.
Generate the resources.json
from a real execution once (using the setting resourceLog.json
) and then run locally
for faster development feedback.
This will create a bundled js under dist
and a complete zip under root as revolver.zip
npm run bundle
Unit tests can be run with:
npm run test
Also, the bundle is sanity checked with the following command. This is used to validate the bundle runs successfully.
npm run bundleTest
Plugins work by being passed a list of all specified supported resources discovered by the drivers and returning a list of actions that need to be performed on those resources. They don't actually interact with any cloud APIs.
See plugins/powercycle.ts
for an example.
To add a plugin:
- Extend
RevolverPlugin
fromplugins/pluginInterface.ts
. Important things to implementinitialise(): Promise<PluginClass>
: Called by revolver during startup. Use for config parsing, setup, etc.generateActions(resource: ToolingInterface): Promise<any>
: Main plugin interface. Plugin needs to interpret all the resources passed and return a list of actions to perform on those resources.supportedResources
: List ofdrivers
that this plugin supports.
- Add the plugin name to
supportedPlugins
inlib/accountRevolver.ts
- Update
lib/config-schema.ts
to support the new plugin.
rivers discover particular resources from the cloud and support specific actions on those resources.
See drivers/ec2.ts
for an example.
To add a driver:
- Extend
ToolingInterface
fromdrivers/instrumentedResource.ts
. This class will represent the driver's resource type and isn't typically used outside the driver itself. - Extend
DriverInterface
fromdrivers/driverInterface.ts
. Implement:collect(): Promise<ToolingInterface[]>
: This should return a list of resources as defined from the newly implementedToolingInterface
resource(obj: InstrumentedResource): ToolingInterface
: This needs to translate an interface reference ofInstrumentedResource
to the concrete class that implementsToolingInterface
- Implement supported actions. These are called by
DriverInterface.processActions
and work via looking for a method with the same string name as the action inactions/actions.ts
. e.g. TheStartAction
uses the stringstart
so to support this action add a method calledstart()
to yourDriverInterface
subclass. The method is passed a list of resources (which should be typed according to your subclass ofToolingInterface
) and the action itself.
Filters need to implement interfaces Filter
and FilterCtor
in plugins/filters/index.ts
.
ready()
is a promise returning the filter itself to allow the constructor to use async. Filters will haveready()
called before being used.matches(resource: ToolingInterface): boolean
performs the actual filtering logic on a resource.
Filters also need to support both value and array inputs and string comparison option settings. It's easier to simply copy an existing filter and adjust unless you have a particularly complicated filter configuration.
- Create new filter file under
plugins/filters
. CopyaccountId.ts
for a basic template ortag.ts
for a filter with several options. - Update names in new file and change the implementation of
matches()
to support your filter logic. - Add tests to
test/filters/filters.spec.ts
to check the new filter. See existing tests for examples. - Update
BaseFilters
inlib/config-schema.ts
to recognize the new filter. - Update
test/bundle-test-config.yaml
and the YAML intest/config
to use the new filter. These don't need to be logical. - Update
README.md
filter table with the new filter and optionally add a reference inrevolver-config-example.yaml