"""
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