Architecture
Big picture
A Cloud Custodian policy is a YAML block with four parts: a resource type, a set of filters, a set of actions, and an optional mode. The core in c7n/ reads that block, resolves each string key (the resource type, each filter name, each action name) to a registered Python class, queries the cloud provider for resources, applies the filters in order, and runs the actions on what survives. Everything is wired through string-keyed plugin registries, which is what lets the same engine grow to roughly 120 AWS resource types and multiple providers without touching the run loop.
Components
CLI and commands
c7n/cli.py builds the argparse parser and dispatches subcommands such as run, report, schema, and validate. c7n/commands.py holds the implementations. commands.run loops over the loaded policies, calls each one, captures exceptions so one failure does not stop the rest, and exits with code 2 if any policy errored (c7n/commands.py:290, c7n/commands.py:306-320).
Policy and execution modes
c7n/policy.py defines the Policy class (c7n/policy.py:1168) and the execution registry of run modes (c7n/policy.py:303). pull is the default: if a policy declares no mode, execution_mode resolves to pull (c7n/policy.py:1230). Serverless modes such as cloudtrail, periodic, and config-rule subclass ServerlessExecutionMode and deploy the policy as a Lambda function instead of running it inline.
Resource managers and queries
c7n/query.py holds QueryResourceManager (c7n/query.py:452), TypeInfo (c7n/query.py:796), and ResourceQuery (c7n/query.py:38). The resource manager owns the lifecycle: fetch, augment, filter, and limit-check. ResourceQuery performs the actual provider API call. c7n/manager.py defines the ResourceManager base whose filter_resources applies filters in sequence (c7n/manager.py:102).
Filters and actions
c7n/filters/core.py defines the Filter base and its process(resources, event) contract (c7n/filters/core.py:198, c7n/filters/core.py:206), plus the generic ValueFilter (c7n/filters/core.py:589). c7n/actions/core.py defines the Action base (c7n/actions/core.py:46). The AWS resource implementations live in c7n/resources/.
Registry
c7n/registry.py defines PluginRegistry (c7n/registry.py:5), a string-to-class map. Resources, filters, actions, execution modes, and sources are all registered through it.
How a request flows
A custodian run policy.yml in the default pull mode flows as follows:
c7n.cli:mainparses arguments and resolves therunsubcommand.commands.runiterates the policies and calls eachPolicyobject (c7n/commands.py:290).Policy.__call__selects the execution mode; for a non-serverless mode it callsmode.run()(c7n/policy.py:1374,c7n/policy.py:1388).runis an alias of__call__(c7n/policy.py:1392).PullMode.runchecks the policy is runnable, fetches resources, writesresources.json, skips actions on dry run, then runs each action (c7n/policy.py:307,c7n/policy.py:330,c7n/policy.py:351,c7n/policy.py:357,c7n/policy.py:364).QueryResourceManager.resourceschecks the cache, fetches via the source, augments with tags, filters, then applies the resource limit (c7n/query.py:526).ResourceManager.filter_resourcesapplies each filter in order and stops early when the set is empty (c7n/manager.py:102).ResourceQuery._invoke_client_enumruns the describe call with a boto3 paginator and extracts the array with jmespath (c7n/query.py:49).
Key design decisions
The policy validation schema is generated at runtime, not written by hand. schema.generate() walks every registered resource, filter, and action and assembles a Draft 7 JSON Schema (c7n/schema.py:359), and schema.validate() checks a policy against it with jsonschema.Draft7Validator (c7n/schema.py:56). Adding a plugin extends both the DSL and the schema that validates it.
Resource enumeration is declarative. A resource binds to a provider API through an enum_spec tuple of (describe_op, jmespath_path, extra_args), and one generic routine pages and extracts for every type. EC2 declares enum_spec = ('describe_instances', 'Reservations[]', None) (c7n/resources/ec2.py:128). This is why a new resource type is a thin declaration rather than new query code.
Extension points
- New resource types: subclass
QueryResourceManagerwith aresource_type(TypeInfo) and register it (c7n/query.py:452,c7n/query.py:796). - New filters and actions: subclass
FilterorActionand register them on a resource's filter or action registry (c7n/filters/core.py:198,c7n/actions/core.py:46). - New execution modes: register on the
executionregistry (c7n/policy.py:303). - New providers: the
tools/c7n_*packages (Azure, GCP, OCI, Tencent, Kubernetes) load through Python entry points.