in src/cfnlint/rules/resources/Configuration.py [0:0]
def _check_resource(self, cfn, resource_name, resource_values):
""" Check Resource """
valid_attributes = [
'Condition',
'CreationPolicy',
'DeletionPolicy',
'DependsOn',
'Metadata',
'Properties',
'Type',
'UpdatePolicy',
'UpdateReplacePolicy',
]
valid_custom_attributes = [
'Condition',
'DeletionPolicy',
'DependsOn',
'Metadata',
'Properties',
'Type',
'UpdateReplacePolicy',
'Version',
]
matches = []
if not isinstance(resource_values, dict):
message = 'Resource not properly configured at {0}'
matches.append(RuleMatch(
['Resources', resource_name],
message.format(resource_name)
))
return matches
# validate condition is a string
condition = resource_values.get('Condition', '')
if not isinstance(condition, six.string_types):
message = 'Condition for resource {0} should be a string'
matches.append(RuleMatch(
['Resources', resource_name, 'Condition'],
message.format(resource_name)
))
resource_type = resource_values.get('Type', '')
if not isinstance(resource_type, six.string_types):
message = 'Type has to be a string at {0}'
matches.append(RuleMatch(
['Resources', resource_name],
message.format('/'.join(['Resources', resource_name]))
))
return matches
# Type is valid continue analysis
if resource_type.startswith('Custom::') or resource_type == 'AWS::CloudFormation::CustomResource':
check_attributes = valid_custom_attributes
else:
check_attributes = valid_attributes
for property_key, _ in resource_values.items():
if property_key not in check_attributes:
message = 'Invalid resource attribute {0} for resource {1}'
matches.append(RuleMatch(
['Resources', resource_name, property_key],
message.format(property_key, resource_name)))
if not resource_type:
message = 'Type not defined for resource {0}'
matches.append(RuleMatch(
['Resources', resource_name],
message.format(resource_name)
))
elif not isinstance(resource_type, six.string_types):
message = 'Type has to be a string at {0}'
matches.append(RuleMatch(
['Resources', resource_name],
message.format('/'.join(['Resources', resource_name]))
))
else:
self.logger.debug('Check resource types by region...')
for region, specs in cfnlint.helpers.RESOURCE_SPECS.items():
if region in cfn.regions:
if resource_type not in specs['ResourceTypes'] and resource_type not in [s['typeName'] for s in REGISTRY_SCHEMAS]:
if not resource_type.startswith(('Custom::', 'AWS::Serverless::')) and not resource_type.endswith('::MODULE'):
message = 'Invalid or unsupported Type {0} for resource {1} in {2}'
matches.append(RuleMatch(
['Resources', resource_name, 'Type'],
message.format(resource_type, resource_name, region)
))
if 'Properties' not in resource_values:
resource_spec = cfnlint.helpers.RESOURCE_SPECS[cfn.regions[0]]
if resource_type in resource_spec['ResourceTypes']:
properties_spec = resource_spec['ResourceTypes'][resource_type]['Properties']
# pylint: disable=len-as-condition
if len(properties_spec) > 0:
required = 0
for _, property_spec in properties_spec.items():
if property_spec.get('Required', False):
required += 1
if required > 0:
if resource_type == 'AWS::CloudFormation::WaitCondition' and 'CreationPolicy' in resource_values.keys():
self.logger.debug('Exception to required properties section as CreationPolicy is defined.')
else:
message = 'Properties not defined for resource {0}'
matches.append(RuleMatch(
['Resources', resource_name],
message.format(resource_name)
))
return matches