""" Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 """ import regex as re from cfnlint.rules import CloudFormationLintRule, RuleMatch class Ebs(CloudFormationLintRule): """Check Ec2 Ebs Resource Properties""" id = "E2504" shortdesc = "Check Ec2 Ebs Properties" description = "See if Ec2 Ebs Properties are valid" source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-blockdev-template.html" tags = ["properties", "ec2", "ebs"] def _checkEbs(self, cfn, ebs, path): matches = [] if isinstance(ebs, dict): volume_types_obj = cfn.get_values(ebs, "VolumeType") iops_obj = cfn.get_values(ebs, "Iops") if volume_types_obj is not None: for volume_type_obj in volume_types_obj: volume_type = volume_type_obj.get("Value") if isinstance(volume_type, str): if volume_type in ("io1", "io2"): if iops_obj is None: pathmessage = path[:] + ["VolumeType"] message = "VolumeType {0} requires Iops to be specified for {1}" matches.append( RuleMatch( pathmessage, message.format( volume_type, "/".join(map(str, pathmessage)) ), ) ) elif volume_type in ("gp2", "st1", "sc1", "standard"): if iops_obj is not None: pathmessage = path[:] + ["Iops"] message = ( "Iops shouldn't be defined for type {0} for {1}" ) matches.append( RuleMatch( pathmessage, message.format( volume_type, "/".join(map(str, pathmessage)) ), ) ) return matches def match(self, cfn): """Check Ec2 Ebs Resource Parameters""" matches = [] results = cfn.get_resource_properties( ["AWS::EC2::Instance", "BlockDeviceMappings"] ) results.extend( cfn.get_resource_properties( ["AWS::AutoScaling::LaunchConfiguration", "BlockDeviceMappings"] ) ) for result in results: path = result["Path"] if isinstance(result["Value"], list): for index, properties in enumerate(result["Value"]): virtual_name = properties.get("VirtualName") ebs = properties.get("Ebs") if virtual_name: # switch to regex if not re.match( r"^ephemeral([0-9]|[1][0-9]|[2][0-3])$", virtual_name ): pathmessage = path[:] + [index, "VirtualName"] message = "Property VirtualName should be of type ephemeral(n) for {0}" matches.append( RuleMatch( pathmessage, message.format("/".join(map(str, pathmessage))), ) ) elif ebs: matches.extend( self._checkEbs(cfn, ebs, path[:] + [index, "Ebs"]) ) return matches