def __new__(cls, name, parents, attrs): if 'resource_type' not in attrs: return super(QueryMeta, cls).__new__(cls, name, parents, attrs) if 'filter_registry' not in attrs: attrs['filter_registry'] = FilterRegistry('%s.filters' % name.lower()) if 'action_registry' not in attrs: attrs['action_registry'] = ActionRegistry('%s.actions' % name.lower()) if attrs['resource_type']: m = ResourceQuery.resolve(attrs['resource_type']) # Generic cloud watch metrics support if m.dimension: attrs['filter_registry'].register('metrics', MetricsFilter) # EC2 Service boilerplate ... if m.service == 'ec2': # Generic ec2 resource tag support if getattr(m, 'taggable', True): register_ec2_tags(attrs['filter_registry'], attrs['action_registry']) if getattr(m, 'universal_taggable', False): register_universal_tags(attrs['filter_registry'], attrs['action_registry']) return super(QueryMeta, cls).__new__(cls, name, parents, attrs)
def __new__(cls, name, parents, attrs): if 'resource_type' not in attrs: return super(QueryMeta, cls).__new__(cls, name, parents, attrs) if 'filter_registry' not in attrs: attrs['filter_registry'] = FilterRegistry( '%s.filters' % name.lower()) if 'action_registry' not in attrs: attrs['action_registry'] = ActionRegistry( '%s.actions' % name.lower()) if attrs['resource_type']: m = ResourceQuery.resolve(attrs['resource_type']) # Generic cloud watch metrics support if m.dimension: attrs['filter_registry'].register('metrics', MetricsFilter) # EC2 Service boilerplate ... if m.service == 'ec2': # Generic ec2 resource tag support if getattr(m, 'taggable', True): register_ec2_tags( attrs['filter_registry'], attrs['action_registry']) if getattr(m, 'universal_taggable', False): register_universal_tags( attrs['filter_registry'], attrs['action_registry']) return super(QueryMeta, cls).__new__(cls, name, parents, attrs)
@resources.register('glue-dev-endpoint') class GlueDevEndpoint(QueryResourceManager): class resource_type(TypeInfo): service = 'glue' enum_spec = ('get_dev_endpoints', 'DevEndpoints', None) id = name = 'EndpointName' date = 'CreatedTimestamp' arn_type = "devEndpoint" permissions = ('glue:GetDevEndpoints', ) augment = universal_augment register_universal_tags(GlueDevEndpoint.filter_registry, GlueDevEndpoint.action_registry) @GlueDevEndpoint.action_registry.register('delete') class DeleteDevEndpoint(BaseAction): """Deletes public Glue Dev Endpoints :example: .. code-block:: yaml policies: - name: delete-public-dev-endpoints resource: glue-dev-endpoint filters: - PublicAddress: present
name = 'TableName' date = 'CreationDateTime' dimension = 'TableName' config_type = 'AWS::DynamoDB::Table' permissions = ('dynamodb:ListTagsOfResource',) def get_source(self, source_type): if source_type == 'describe': return DescribeTable(self) elif source_type == 'config': return ConfigTable(self) raise ValueError('invalid source %s' % source_type) register_universal_tags(Table.filter_registry, Table.action_registry, False) class ConfigTable(query.ConfigSource): def load_resource(self, item): resource = super(ConfigTable, self).load_resource(item) resource['CreationDateTime'] = datetime.fromtimestamp(resource['CreationDateTime'] / 1000.0) if 'LastUpdateToPayPerRequestDateTime' in resource['BillingModeSummary']: resource['BillingModeSummary'][ 'LastUpdateToPayPerRequestDateTime'] = datetime.fromtimestamp( resource['BillingModeSummary']['LastUpdateToPayPerRequestDateTime'] / 1000.0) sse_info = resource.pop('Ssedescription', None) if sse_info is None: return resource
patch={ 'type': 'array', 'items': OP_SCHEMA }, required=['patch']) def process(self, resources): client = utils.local_session( self.manager.session_factory).client('apigateway') for r in resources: client.update_rest_api(restApiId=r['id'], patchOperations=self.data['patch']) register_universal_tags(RestApi.filter_registry, RestApi.action_registry, compatibility=False) @RestApi.action_registry.register('delete') class DeleteApi(BaseAction): """Delete a REST API. :example: contrived example to delete rest api .. code-block:: yaml policies: - name: apigw-delete
dimension = 'LogGroupName' date = 'creationTime' def augment(self, resources): resources = universal_augment(self, resources) for r in resources: r['creationTime'] = r['creationTime'] / 1000.0 return resources def get_arns(self, resources): # log group arn in resource describe has ':*' suffix, not all # apis can use that form, so normalize to standard arn. return [r['arn'][:-2] for r in resources] register_universal_tags(LogGroup.filter_registry, LogGroup.action_registry) @LogGroup.action_registry.register('retention') class Retention(BaseAction): """Action to set the retention period (in days) for CloudWatch log groups :example: .. code-block:: yaml policies: - name: cloudwatch-set-log-group-retention resource: log-group actions: - type: retention
name = 'TableName' date = 'CreationDateTime' dimension = 'TableName' config_type = 'AWS::DynamoDB::Table' permissions = ('dynamodb:ListTagsOfResource', ) def get_source(self, source_type): if source_type == 'describe': return DescribeTable(self) elif source_type == 'config': return ConfigTable(self) raise ValueError('invalid source %s' % source_type) register_universal_tags(Table.filter_registry, Table.action_registry, False) class ConfigTable(query.ConfigSource): def load_resource(self, item): resource = super(ConfigTable, self).load_resource(item) resource['CreationDateTime'] = datetime.fromtimestamp( resource['CreationDateTime'] / 1000.0) if 'LastUpdateToPayPerRequestDateTime' in resource[ 'BillingModeSummary']: resource['BillingModeSummary'][ 'LastUpdateToPayPerRequestDateTime'] = datetime.fromtimestamp( resource['BillingModeSummary'] ['LastUpdateToPayPerRequestDateTime'] / 1000.0) sse_info = resource.pop('Ssedescription', None)
@property def generate_arn(self): if self._generate_arn is None: self._generate_arn = functools.partial( generate_arn, 'elasticfilesystem', region=self.config.region, account_id=self.account_id, resource_type='file-system', separator='/') return self._generate_arn register_universal_tags( ElasticFileSystem.filter_registry, ElasticFileSystem.action_registry) @resources.register('efs-mount-target') class ElasticFileSystemMountTarget(ChildResourceManager): class resource_type(object): service = 'efs' parent_spec = ('efs', 'FileSystemId', None) enum_spec = ('describe_mount_targets', 'MountTargets', None) name = id = 'MountTargetId' date = None dimension = None filter_name = 'MountTargetId' filter_type = 'scalar'
if e.response['Error'][ 'Code'] == 'AWS.SimpleQueueService.NonExistentQueue': return if e.response['Error']['Code'] == 'AccessDenied': self.log.warning("Denied access to sqs %s" % r) return raise return queue with self.executor_factory(max_workers=2) as w: return universal_augment( self, list(filter(None, w.map(_augment, resources)))) register_universal_tags(SQS.filter_registry, SQS.action_registry, compatibility=False) @SQS.filter_registry.register('metrics') class MetricsFilter(MetricsFilter): def get_dimensions(self, resource): return [{ 'Name': 'QueueName', 'Value': resource['QueueUrl'].rsplit('/', 1)[-1] }] @SQS.filter_registry.register('cross-account') class SQSCrossAccount(CrossAccountAccessFilter): """Filter SQS queues which have cross account permissions
@property def generate_arn(self): self._generate_arn = functools.partial( generate_arn, 'glue', region=self.config.region, account_id=self.config.account_id, resource_type='devEndpoint', separator='/') return self._generate_arn def get_arns(self, resources): return [self.generate_arn(r['EndpointName']) for r in resources] register_universal_tags(GlueDevEndpoint.filter_registry, GlueDevEndpoint.action_registry) @GlueDevEndpoint.action_registry.register('delete') class DeleteDevEndpoint(BaseAction): """Deletes public Glue Dev Endpoints :example: .. code-block: yaml policies: - name: delete-public-dev-endpoints resource: glue-dev-endpoint filters: - PublicAddress: present
return DescribeCertificate(self) elif source_type == 'config': return ConfigSource(self) raise ValueError("Unsupported source: %s for %s" % (source_type, self.resource_type.config_type)) class DescribeCertificate(DescribeSource): def augment(self, resources): return universal_augment( self.manager, super(DescribeCertificate, self).augment(resources)) register_universal_tags(Certificate.filter_registry, Certificate.action_registry, compatibility=False) @Certificate.action_registry.register('delete') class CertificateDeleteAction(BaseAction): """Action to delete an ACM Certificate To avoid unwanted deletions of certificates, it is recommended to apply a filter to the rule :example: .. code-block:: yaml policies: - name: acm-certificate-delete-expired resource: acm-certificate
name = id = dimension = 'WorkspaceId' filter_name = None augment = universal_augment _generate_arn = None @property def generate_arn(self): if self._generate_arn is None: self._generate_arn = functools.partial( generate_arn, 'workspaces', region=self.config.region, account_id=self.account_id, resource_type='workspace', separator='/') return self._generate_arn register_universal_tags(Workspace.filter_registry, Workspace.action_registry) @Workspace.filter_registry.register('connection-status') class WorkspaceConnectionStatusFilter(ValueFilter): """Filter Workspaces based on user connection information :example: .. code-block:: yaml policies: - name: workspaces-abandoned resource: workspaces filters:
augment = universal_augment _generate_arn = None @property def generate_arn(self): if self._generate_arn is None: self._generate_arn = functools.partial(generate_arn, 'workspaces', region=self.config.region, account_id=self.account_id, resource_type='workspace', separator='/') return self._generate_arn register_universal_tags(Workspace.filter_registry, Workspace.action_registry) @Workspace.filter_registry.register('connection-status') class WorkspaceConnectionStatusFilter(ValueFilter): """Filter Workspaces based on user connection information :example: .. code-block:: yaml policies: - name: workspaces-abandoned resource: workspaces filters:
queue['QueueUrl'] = r except ClientError as e: if e.response['Error']['Code'] == 'AWS.SimpleQueueService.NonExistentQueue': return if e.response['Error']['Code'] == 'AccessDenied': self.log.warning("Denied access to sqs %s" % r) return raise return queue with self.executor_factory(max_workers=2) as w: return universal_augment( self, list(filter(None, w.map(_augment, resources)))) register_universal_tags( SQS.filter_registry, SQS.action_registry, compatibility=False) @SQS.filter_registry.register('metrics') class MetricsFilter(MetricsFilter): def get_dimensions(self, resource): return [ {'Name': 'QueueName', 'Value': resource['QueueUrl'].rsplit('/', 1)[-1]}] @SQS.filter_registry.register('cross-account') class SQSCrossAccount(CrossAccountAccessFilter): """Filter SQS queues which have cross account permissions
def augment(self, dbs): return universal_augment( self.manager, super(DescribeRDS, self).augment(dbs)) class ConfigRDS(ConfigSource): def load_resource(self, item): resource = super(ConfigRDS, self).load_resource(item) resource['Tags'] = [{u'Key': t['key'], u'Value': t['value']} for t in item['supplementaryConfiguration']['Tags']] return resource register_universal_tags( RDS.filter_registry, RDS.action_registry) def _db_instance_eligible_for_backup(resource): db_instance_id = resource['DBInstanceIdentifier'] # Database instance is not in available state if resource.get('DBInstanceStatus', '') != 'available': log.debug( "DB instance %s is not in available state", db_instance_id) return False # The specified DB Instance is a member of a cluster and its # backup retention should not be modified directly. Instead, # modify the backup retention of the cluster using the
name = 'logGroupName' id = 'arn' filter_name = 'logGroupNamePrefix' filter_type = 'scalar' dimension = 'LogGroupName' date = 'creationTime' augment = universal_augment def get_arns(self, resources): # log group arn in resource describe has ':*' suffix, not all # apis can use that form, so normalize to standard arn. return [r['arn'][:-2] for r in resources] register_universal_tags(LogGroup.filter_registry, LogGroup.action_registry) @LogGroup.action_registry.register('retention') class Retention(BaseAction): """Action to set the retention period (in days) for CloudWatch log groups :example: .. code-block:: yaml policies: - name: cloudwatch-set-log-group-retention resource: log-group actions: - type: retention
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import absolute_import, division, print_function, unicode_literals from c7n.manager import resources from c7n.query import QueryResourceManager, TypeInfo from c7n.tags import register_universal_tags, universal_augment @resources.register('storage-gateway') class StorageGateway(QueryResourceManager): class resource_type(TypeInfo): service = 'storagegateway' enum_spec = ('list_gateways', 'Gateways', None) arn = id = 'GatewayARN' name = 'GatewayName' augment = universal_augment register_universal_tags( StorageGateway.filter_registry, StorageGateway.action_registry, compatibility=False)
id = 'FileSystemId' name = 'Name' date = 'CreationTime' dimension = 'FileSystemId' arn_type = 'file-system' arn_service = 'elasticfilesystem' filter_name = 'FileSystemId' filter_type = 'scalar' def augment(self, resources): return universal_augment( self, super(ElasticFileSystem, self).augment(resources)) register_universal_tags(ElasticFileSystem.filter_registry, ElasticFileSystem.action_registry) @resources.register('efs-mount-target') class ElasticFileSystemMountTarget(ChildResourceManager): class resource_type(TypeInfo): service = 'efs' parent_spec = ('efs', 'FileSystemId', None) enum_spec = ('describe_mount_targets', 'MountTargets', None) name = id = 'MountTargetId' filter_name = 'MountTargetId' filter_type = 'scalar' arn = False @ElasticFileSystemMountTarget.filter_registry.register('subnet')
if source_type == 'describe': return DescribeCertificate(self) elif source_type == 'config': return ConfigSource(self) raise ValueError("Unsupported source: %s for %s" % (source_type, self.resource_type.config_type)) class DescribeCertificate(DescribeSource): def augment(self, resources): return universal_augment( self.manager, super(DescribeCertificate, self).augment(resources)) register_universal_tags(Certificate.filter_registry, Certificate.action_registry) @Certificate.action_registry.register('delete') class CertificateDeleteAction(BaseAction): """Action to delete an ACM Certificate To avoid unwanted deletions of certificates, it is recommended to apply a filter to the rule :example: .. code-block:: yaml policies: - name: acm-certificate-delete-expired resource: acm-certificate filters: