Skip to content

Commit

Permalink
When using aurora dbinstance make sure certain properties aren't spec…
Browse files Browse the repository at this point in the history
…ified (#1409)
  • Loading branch information
kddejong committed Mar 9, 2020
1 parent ec366bb commit 331be5c
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/cfnlint/rules/resources/rds/AuroraDBInstanceProperties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""
import six
from cfnlint.rules import CloudFormationLintRule
from cfnlint.rules import RuleMatch


class AuroraDBInstanceProperties(CloudFormationLintRule):
"""Aurora DB instances have a lot properties that can't be set and vice and versa"""
id = 'E3029'
shortdesc = 'Aurora instances don\'t require certain properties'
description = 'Certain properties are not reuqired when using the Aurora engine for AWS::RDS::DBInstance'
source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html'
tags = ['resources', 'rds']
aurora_not_required_props = [
'AllocatedStorage',
'BackupRetentionPeriod',
'CopyTagsToSnapshot',
'DeletionProtection',
'EnableIAMDatabaseAuthentication',
'MasterUserPassword',
'StorageEncrypted',
]
aurora_engines = [
'aurora',
'aurora-mysql',
'aurora-postgresql',
]

def __init__(self):
"""Init"""
super(AuroraDBInstanceProperties, self).__init__()
self.resource_property_types = ['AWS::RDS::DBInstance']

def check(self, properties, path, cfn):
"""Check itself"""
matches = []
property_sets = cfn.get_object_without_conditions(
properties, ['Engine'] + self.aurora_not_required_props)
for property_set in property_sets:
properties = property_set.get('Object')
scenario = property_set.get('Scenario')
engine_sets = properties.get_safe('Engine', type_t=six.string_types)
for engine, _ in engine_sets:
if engine in self.aurora_engines:
for prop in properties:
if prop in self.aurora_not_required_props:
path_prop = path[:] + [prop]
message = 'You cannot specify {} for Aurora AWS::RDS::DBInstance at {}'
if scenario is None:
matches.append(
RuleMatch(path_prop, message.format(prop, '/'.join(map(str, path_prop)))))
else:
scenario_text = ' and '.join(
['when condition "%s" is %s' % (k, v) for (k, v) in scenario.items()])
matches.append(
RuleMatch(path_prop, message.format(prop, '/'.join(map(str, path_prop)) + ' ' + scenario_text)))
return matches

def match_resource_properties(self, properties, _, path, cfn):
"""Match for sub properties"""
matches = []
matches.extend(self.check(properties, path, cfn))
return matches
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
AWSTemplateFormatVersion: 2010-09-09
Description: "RDS Storage Encrypted"
Parameters:
Engine:
Type: String
UseAurora:
Type: String
AllowedValues:
- "true"
- "false"
Conditions:
IsAurora:
Fn::Or:
- !Equals [!Ref Engine, "aurora"]
- !Equals [!Ref Engine, "aurora-mysql"]
- !Equals [!Ref Engine, "aurora-postgresql"]
IsAurora2: !Equals [!Ref UseAurora, "true"]
Resources:
MyDBSmall:
Type: "AWS::RDS::DBInstance"
Properties:
Engine: aurora
AllocatedStorage: "100"
DBInstanceClass: db.r3.2xlarge
StorageEncrypted: true
MyDbInstance2:
Type: "AWS::RDS::DBInstance"
Properties:
Engine: !Ref Engine
DBInstanceClass: db.r3.2xlarge
# While this is bad we can't determine the Engine so skipping
AllocatedStorage: !If [IsAurora, "100", !Ref "AWS::NoValue"]
MySqlInstance:
Type: "AWS::RDS::DBInstance"
Properties:
Engine: !If [IsAurora2, aurora-mysql, mysql]
DBInstanceClass: db.r3.2xlarge
# Since we can figure out the engine this one should fail
AllocatedStorage: !If [IsAurora2, "100", !Ref "AWS::NoValue"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
AWSTemplateFormatVersion: 2010-09-09
Description: "RDS Storage Encrypted"
Parameters:
Engine:
Type: String
UseAurora:
Type: String
AllowedValues:
- "true"
- "false"
Conditions:
IsAurora:
Fn::Or:
- !Equals [!Ref Engine, "aurora"]
- !Equals [!Ref Engine, "aurora-mysql"]
- !Equals [!Ref Engine, "aurora-postgresql"]
IsAurora2: !Equals [!Ref UseAurora, "true"]
Resources:
MyDbInstance1:
Type: "AWS::RDS::DBInstance"
Properties:
Engine: mysql
AllocatedStorage: "100"
DBInstanceClass: db.r3.2xlarge
StorageEncrypted: true
MyDbInstance2:
Type: "AWS::RDS::DBInstance"
Properties:
Engine: !Ref Engine
DBInstanceClass: db.r3.2xlarge
AllocatedStorage: !If [IsAurora, !Ref "AWS::NoValue", "100"]
MySqlInstance:
Type: "AWS::RDS::DBInstance"
Properties:
Engine: !If [IsAurora2, aurora-mysql, mysql]
DBInstanceClass: db.r3.2xlarge
AllocatedStorage: !If [IsAurora2, !Ref "AWS::NoValue", "100"]
27 changes: 27 additions & 0 deletions test/unit/rules/resources/rds/test_auroa_dbinstance_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""
from test.unit.rules import BaseRuleTestCase
from cfnlint.rules.resources.rds.AuroraDBInstanceProperties import AuroraDBInstanceProperties # pylint: disable=E0401


class TestAuroraDBInstanceProperties(BaseRuleTestCase):
"""Test RDS Auror Auto Scaling Configurartion"""

def setUp(self):
"""Setup"""
super(TestAuroraDBInstanceProperties, self).setUp()
self.collection.register(AuroraDBInstanceProperties())
self.success_templates = [
'test/fixtures/templates/good/resources/rds/aurora_dbinstance_properties.yaml'
]

def test_file_positive(self):
"""Test Positive"""
self.helper_file_positive()

def test_file_negative_alias(self):
"""Test failure"""
self.helper_file_negative(
'test/fixtures/templates/bad/resources/rds/aurora_dbinstance_properties.yaml', 3)

0 comments on commit 331be5c

Please sign in to comment.