Repository: aws-cloudformation/cfn-lint

Issue:
NoValue support missing for BlockDeviceMappings
*cfn-lint version: *`0.22.1`

*Description of issue.*

```
        "BlockDeviceMappings": {
          "Ref": "AWS::NoValue"
        }
```
results in:
```
E3002 Property is an object instead of List at Resources/EcsInstanceLaunchConfig/Properties/BlockDeviceMappings
```
Since it's not a required property, `NoValue` should be supported.


Discussion:
Yea agreed with that.  Let me look into this one.

Resolving patch:
diff --git a/src/cfnlint/rules/resources/ectwo/Ebs.py b/src/cfnlint/rules/resources/ectwo/Ebs.py
--- a/src/cfnlint/rules/resources/ectwo/Ebs.py
+++ b/src/cfnlint/rules/resources/ectwo/Ebs.py
@@ -64,16 +64,17 @@ def match(self, cfn):
         results.extend(cfn.get_resource_properties(['AWS::AutoScaling::LaunchConfiguration', 'BlockDeviceMappings']))
         for result in results:
             path = result['Path']
-            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]$', 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']))
+            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]$', 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
diff --git a/src/cfnlint/rules/resources/properties/Properties.py b/src/cfnlint/rules/resources/properties/Properties.py
--- a/src/cfnlint/rules/resources/properties/Properties.py
+++ b/src/cfnlint/rules/resources/properties/Properties.py
@@ -150,7 +150,7 @@ def check_list_for_condition(self, text, prop, parenttype, resourcename, propspe
                                 if not (resource_type == 'AWS::CloudFormation::CustomResource' or resource_type.startswith('Custom::')):
                                     message = 'Property is an object instead of List at %s' % ('/'.join(map(str, path)))
                                     matches.append(RuleMatch(path, message))
-                        else:
+                        elif not (sub_key == 'Ref' and sub_value == 'AWS::NoValue'):
                             message = 'Property is an object instead of List at %s' % ('/'.join(map(str, path)))
                             matches.append(RuleMatch(path, message))
                     else:


Test patch:
diff --git a/test/fixtures/templates/bad/generic.yaml b/test/fixtures/templates/bad/generic.yaml
--- a/test/fixtures/templates/bad/generic.yaml
+++ b/test/fixtures/templates/bad/generic.yaml
@@ -209,6 +209,15 @@ Resources:
       RuleNumber: 1
       Protocol: 1
       RuleAction: allow
+  MyEc2BlockDevice:
+    Type: "AWS::EC2::Instance"
+    Properties:
+      ImageId: "ami-2f726546"
+      InstanceType: t1.micro
+      KeyName: testkey
+      BlockDeviceMappings: !Ref 'AWS::NoValue'
+      NetworkInterfaces:
+        - DeviceIndex: "1"
 Outputs:
   myOutput:
     Value: !GetAtt ElasticLoadBalancer.CanonicalHostedZoneName