We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Condition: <list> on Resource triggers "Unknown exception while processing rule"
*cfn-lint version: (`cfn-lint --version`)*
cfn-lint 0.21.4

*Description of issue.*
A resource with a Condition property defined as a list triggers:
```
E0002 Unknown exception while processing rule E8002: unhashable type: 'list_node'
/tmp/cfn-lint-condition-list-error.yaml:1:1
```
I believe that the use of lists / multiple values for a Condition property of a Resource is probably not legal (although I was unable to find clear confirmation of that in the documentation during a quick scan), but it should probably trigger a lint error rather than an exception.

It would also be helpful, if possible, to include the template line-number where the exception was triggered, rather than line:char 1:1 to make tracking the cause of such problems easier.

I have also seen the same exception, but for rule W1001, I though it was the same cause, but my reproduce test didn't re-trigger the W1001 case.

*Reproduce example*
```
AWSTemplateFormatVersion: 2010-09-09
Description: "cfn-lint condition list error"

Conditions:
    Cond1: !Equals [ !Ref 'AWS::Region', 'us-east-1' ]
    Cond2: !Equals [ !Ref 'AWS::Region', 'eu-west-1' ]

Resources:

    EIP1:
        Type: AWS::EC2::EIP
        Condition:
          - Cond1
          - Cond2
        Properties:
            Domain: 'vpc'

    EIP2:
        Type: AWS::EC2::EIP
        Condition: Cond1
        Properties:
            Domain: 'vpc'

    EIP3:
        Type: AWS::EC2::EIP
        Condition: Cond2
        Properties:
            Domain: 'vpc'
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cfnlint/rules/conditions/Exists.py`
Content:
```
1 """
2   Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy of this
5   software and associated documentation files (the "Software"), to deal in the Software
6   without restriction, including without limitation the rights to use, copy, modify,
7   merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8   permit persons to whom the Software is furnished to do so.
9 
10   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 """
17 import six
18 from cfnlint import CloudFormationLintRule
19 from cfnlint import RuleMatch
20 
21 
22 class Exists(CloudFormationLintRule):
23     """Check if used Conditions are defined """
24     id = 'E8002'
25     shortdesc = 'Check if the referenced Conditions are defined'
26     description = 'Making sure the used conditions are actually defined in the Conditions section'
27     source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html'
28     tags = ['conditions']
29 
30     def match(self, cfn):
31         """Check CloudFormation Conditions"""
32 
33         matches = []
34         ref_conditions = {}
35 
36         # Get all defined conditions
37         conditions = cfn.template.get('Conditions', {})
38 
39         # Get all "If's" that reference a Condition
40         iftrees = cfn.search_deep_keys('Fn::If')
41         for iftree in iftrees:
42             if isinstance(iftree[-1], list):
43                 ref_conditions[iftree[-1][0]] = iftree
44             else:
45                 ref_conditions[iftree[-1]] = iftree
46 
47         # Get resource's Conditions
48         for resource_name, resource_values in cfn.get_resources().items():
49             if 'Condition' in resource_values:
50                 path = ['Resources', resource_name, 'Condition']
51                 ref_conditions[resource_values['Condition']] = path
52 
53         # Get conditions used by another condition
54         condtrees = cfn.search_deep_keys('Condition')
55 
56         for condtree in condtrees:
57             if condtree[0] == 'Conditions':
58                 if isinstance(condtree[-1], (str, six.text_type, six.string_types)):
59                     path = ['Conditions', condtree[-1]]
60                     ref_conditions[condtree[-1]] = path
61 
62         # Get Output Conditions
63         for _, output_values in cfn.template.get('Outputs', {}).items():
64             if 'Condition' in output_values:
65                 path = ['Outputs', output_values['Condition']]
66                 ref_conditions[output_values['Condition']] = path
67 
68         # Check if all the conditions are defined
69         for ref_condition, ref_path in ref_conditions.items():
70             if ref_condition not in conditions:
71                 message = 'Condition {0} is not defined.'
72                 matches.append(RuleMatch(
73                     ref_path,
74                     message.format(ref_condition)
75                 ))
76 
77         return matches
78
```

Path: `src/cfnlint/rules/resources/Configuration.py`
Content:
```
1 """
2   Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy of this
5   software and associated documentation files (the "Software"), to deal in the Software
6   without restriction, including without limitation the rights to use, copy, modify,
7   merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8   permit persons to whom the Software is furnished to do so.
9 
10   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
11   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
12   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
14   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 """
17 from cfnlint import CloudFormationLintRule
18 from cfnlint import RuleMatch
19 import cfnlint.helpers
20 
21 
22 class Configuration(CloudFormationLintRule):
23     """Check Base Resource Configuration"""
24     id = 'E3001'
25     shortdesc = 'Basic CloudFormation Resource Check'
26     description = 'Making sure the basic CloudFormation resources ' + \
27                   'are properly configured'
28     source_url = 'https://github.com/aws-cloudformation/cfn-python-lint'
29     tags = ['resources']
30 
31     def match(self, cfn):
32         """Check CloudFormation Resources"""
33 
34         matches = []
35 
36         valid_attributes = [
37             'CreationPolicy',
38             'DeletionPolicy',
39             'DependsOn',
40             'Metadata',
41             'UpdatePolicy',
42             'UpdateReplacePolicy',
43             'Properties',
44             'Type',
45             'Condition'
46         ]
47 
48         valid_custom_attributes = [
49             'Version',
50             'Properties',
51             'DependsOn',
52             'Metadata',
53             'Condition',
54             'Type',
55         ]
56 
57         resources = cfn.template.get('Resources', {})
58         if not isinstance(resources, dict):
59             message = 'Resource not properly configured'
60             matches.append(RuleMatch(['Resources'], message))
61         else:
62             for resource_name, resource_values in cfn.template.get('Resources', {}).items():
63                 self.logger.debug('Validating resource %s base configuration', resource_name)
64                 if not isinstance(resource_values, dict):
65                     message = 'Resource not properly configured at {0}'
66                     matches.append(RuleMatch(
67                         ['Resources', resource_name],
68                         message.format(resource_name)
69                     ))
70                     continue
71                 resource_type = resource_values.get('Type', '')
72                 check_attributes = []
73                 if resource_type.startswith('Custom::') or resource_type == 'AWS::CloudFormation::CustomResource':
74                     check_attributes = valid_custom_attributes
75                 else:
76                     check_attributes = valid_attributes
77 
78                 for property_key, _ in resource_values.items():
79                     if property_key not in check_attributes:
80                         message = 'Invalid resource attribute {0} for resource {1}'
81                         matches.append(RuleMatch(
82                             ['Resources', resource_name, property_key],
83                             message.format(property_key, resource_name)))
84 
85                 resource_type = resource_values.get('Type', '')
86                 if not resource_type:
87                     message = 'Type not defined for resource {0}'
88                     matches.append(RuleMatch(
89                         ['Resources', resource_name],
90                         message.format(resource_name)
91                     ))
92                 else:
93                     self.logger.debug('Check resource types by region...')
94                     for region, specs in cfnlint.helpers.RESOURCE_SPECS.items():
95                         if region in cfn.regions:
96                             if resource_type not in specs['ResourceTypes']:
97                                 if not resource_type.startswith(('Custom::', 'AWS::Serverless::')):
98                                     message = 'Invalid or unsupported Type {0} for resource {1} in {2}'
99                                     matches.append(RuleMatch(
100                                         ['Resources', resource_name, 'Type'],
101                                         message.format(resource_type, resource_name, region)
102                                     ))
103 
104                 if 'Properties' not in resource_values:
105                     resource_spec = cfnlint.helpers.RESOURCE_SPECS[cfn.regions[0]]
106                     if resource_type in resource_spec['ResourceTypes']:
107                         properties_spec = resource_spec['ResourceTypes'][resource_type]['Properties']
108                         # pylint: disable=len-as-condition
109                         if len(properties_spec) > 0:
110                             required = 0
111                             for _, property_spec in properties_spec.items():
112                                 if property_spec.get('Required', False):
113                                     required += 1
114                             if required > 0:
115                                 if resource_type == 'AWS::CloudFormation::WaitCondition' and 'CreationPolicy' in resource_values.keys():
116                                     self.logger.debug('Exception to required properties section as CreationPolicy is defined.')
117                                 else:
118                                     message = 'Properties not defined for resource {0}'
119                                     matches.append(RuleMatch(
120                                         ['Resources', resource_name],
121                                         message.format(resource_name)
122                                     ))
123 
124         return matches
125
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/cfnlint/rules/conditions/Exists.py b/src/cfnlint/rules/conditions/Exists.py
--- a/src/cfnlint/rules/conditions/Exists.py
+++ b/src/cfnlint/rules/conditions/Exists.py
@@ -46,9 +46,10 @@
 
         # Get resource's Conditions
         for resource_name, resource_values in cfn.get_resources().items():
-            if 'Condition' in resource_values:
+            condition = resource_values.get('Condition')
+            if isinstance(condition, six.string_types):  # make sure its a string
                 path = ['Resources', resource_name, 'Condition']
-                ref_conditions[resource_values['Condition']] = path
+                ref_conditions[condition] = path
 
         # Get conditions used by another condition
         condtrees = cfn.search_deep_keys('Condition')
diff --git a/src/cfnlint/rules/resources/Configuration.py b/src/cfnlint/rules/resources/Configuration.py
--- a/src/cfnlint/rules/resources/Configuration.py
+++ b/src/cfnlint/rules/resources/Configuration.py
@@ -14,6 +14,7 @@
   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 """
+import six
 from cfnlint import CloudFormationLintRule
 from cfnlint import RuleMatch
 import cfnlint.helpers
@@ -82,6 +83,15 @@
                             ['Resources', resource_name, property_key],
                             message.format(property_key, resource_name)))
 
+                # 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 resource_type:
                     message = 'Type not defined for resource {0}'

{"golden_diff": "diff --git a/src/cfnlint/rules/conditions/Exists.py b/src/cfnlint/rules/conditions/Exists.py\n--- a/src/cfnlint/rules/conditions/Exists.py\n+++ b/src/cfnlint/rules/conditions/Exists.py\n@@ -46,9 +46,10 @@\n \n         # Get resource's Conditions\n         for resource_name, resource_values in cfn.get_resources().items():\n-            if 'Condition' in resource_values:\n+            condition = resource_values.get('Condition')\n+            if isinstance(condition, six.string_types):  # make sure its a string\n                 path = ['Resources', resource_name, 'Condition']\n-                ref_conditions[resource_values['Condition']] = path\n+                ref_conditions[condition] = path\n \n         # Get conditions used by another condition\n         condtrees = cfn.search_deep_keys('Condition')\ndiff --git a/src/cfnlint/rules/resources/Configuration.py b/src/cfnlint/rules/resources/Configuration.py\n--- a/src/cfnlint/rules/resources/Configuration.py\n+++ b/src/cfnlint/rules/resources/Configuration.py\n@@ -14,6 +14,7 @@\n   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n+import six\n from cfnlint import CloudFormationLintRule\n from cfnlint import RuleMatch\n import cfnlint.helpers\n@@ -82,6 +83,15 @@\n                             ['Resources', resource_name, property_key],\n                             message.format(property_key, resource_name)))\n \n+                # validate condition is a string\n+                condition = resource_values.get('Condition', '')\n+                if not isinstance(condition, six.string_types):\n+                    message = 'Condition for resource {0} should be a string'\n+                    matches.append(RuleMatch(\n+                        ['Resources', resource_name, 'Condition'],\n+                        message.format(resource_name)\n+                    ))\n+\n                 resource_type = resource_values.get('Type', '')\n                 if not resource_type:\n                     message = 'Type not defined for resource {0}'\n", "issue": "Condition: <list> on Resource triggers \"Unknown exception while processing rule\"\n*cfn-lint version: (`cfn-lint --version`)*\r\ncfn-lint 0.21.4\r\n\r\n*Description of issue.*\r\nA resource with a Condition property defined as a list triggers:\r\n```\r\nE0002 Unknown exception while processing rule E8002: unhashable type: 'list_node'\r\n/tmp/cfn-lint-condition-list-error.yaml:1:1\r\n```\r\nI believe that the use of lists / multiple values for a Condition property of a Resource is probably not legal (although I was unable to find clear confirmation of that in the documentation during a quick scan), but it should probably trigger a lint error rather than an exception.\r\n\r\nIt would also be helpful, if possible, to include the template line-number where the exception was triggered, rather than line:char 1:1 to make tracking the cause of such problems easier.\r\n\r\nI have also seen the same exception, but for rule W1001, I though it was the same cause, but my reproduce test didn't re-trigger the W1001 case.\r\n\r\n*Reproduce example*\r\n```\r\nAWSTemplateFormatVersion: 2010-09-09\r\nDescription: \"cfn-lint condition list error\"\r\n\r\nConditions:\r\n    Cond1: !Equals [ !Ref 'AWS::Region', 'us-east-1' ]\r\n    Cond2: !Equals [ !Ref 'AWS::Region', 'eu-west-1' ]\r\n\r\nResources:\r\n\r\n    EIP1:\r\n        Type: AWS::EC2::EIP\r\n        Condition:\r\n          - Cond1\r\n          - Cond2\r\n        Properties:\r\n            Domain: 'vpc'\r\n\r\n    EIP2:\r\n        Type: AWS::EC2::EIP\r\n        Condition: Cond1\r\n        Properties:\r\n            Domain: 'vpc'\r\n\r\n    EIP3:\r\n        Type: AWS::EC2::EIP\r\n        Condition: Cond2\r\n        Properties:\r\n            Domain: 'vpc'\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\n  Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this\n  software and associated documentation files (the \"Software\"), to deal in the Software\n  without restriction, including without limitation the rights to use, copy, modify,\n  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n  permit persons to whom the Software is furnished to do so.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\nimport six\nfrom cfnlint import CloudFormationLintRule\nfrom cfnlint import RuleMatch\n\n\nclass Exists(CloudFormationLintRule):\n    \"\"\"Check if used Conditions are defined \"\"\"\n    id = 'E8002'\n    shortdesc = 'Check if the referenced Conditions are defined'\n    description = 'Making sure the used conditions are actually defined in the Conditions section'\n    source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html'\n    tags = ['conditions']\n\n    def match(self, cfn):\n        \"\"\"Check CloudFormation Conditions\"\"\"\n\n        matches = []\n        ref_conditions = {}\n\n        # Get all defined conditions\n        conditions = cfn.template.get('Conditions', {})\n\n        # Get all \"If's\" that reference a Condition\n        iftrees = cfn.search_deep_keys('Fn::If')\n        for iftree in iftrees:\n            if isinstance(iftree[-1], list):\n                ref_conditions[iftree[-1][0]] = iftree\n            else:\n                ref_conditions[iftree[-1]] = iftree\n\n        # Get resource's Conditions\n        for resource_name, resource_values in cfn.get_resources().items():\n            if 'Condition' in resource_values:\n                path = ['Resources', resource_name, 'Condition']\n                ref_conditions[resource_values['Condition']] = path\n\n        # Get conditions used by another condition\n        condtrees = cfn.search_deep_keys('Condition')\n\n        for condtree in condtrees:\n            if condtree[0] == 'Conditions':\n                if isinstance(condtree[-1], (str, six.text_type, six.string_types)):\n                    path = ['Conditions', condtree[-1]]\n                    ref_conditions[condtree[-1]] = path\n\n        # Get Output Conditions\n        for _, output_values in cfn.template.get('Outputs', {}).items():\n            if 'Condition' in output_values:\n                path = ['Outputs', output_values['Condition']]\n                ref_conditions[output_values['Condition']] = path\n\n        # Check if all the conditions are defined\n        for ref_condition, ref_path in ref_conditions.items():\n            if ref_condition not in conditions:\n                message = 'Condition {0} is not defined.'\n                matches.append(RuleMatch(\n                    ref_path,\n                    message.format(ref_condition)\n                ))\n\n        return matches\n", "path": "src/cfnlint/rules/conditions/Exists.py"}, {"content": "\"\"\"\n  Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this\n  software and associated documentation files (the \"Software\"), to deal in the Software\n  without restriction, including without limitation the rights to use, copy, modify,\n  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n  permit persons to whom the Software is furnished to do so.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\nfrom cfnlint import CloudFormationLintRule\nfrom cfnlint import RuleMatch\nimport cfnlint.helpers\n\n\nclass Configuration(CloudFormationLintRule):\n    \"\"\"Check Base Resource Configuration\"\"\"\n    id = 'E3001'\n    shortdesc = 'Basic CloudFormation Resource Check'\n    description = 'Making sure the basic CloudFormation resources ' + \\\n                  'are properly configured'\n    source_url = 'https://github.com/aws-cloudformation/cfn-python-lint'\n    tags = ['resources']\n\n    def match(self, cfn):\n        \"\"\"Check CloudFormation Resources\"\"\"\n\n        matches = []\n\n        valid_attributes = [\n            'CreationPolicy',\n            'DeletionPolicy',\n            'DependsOn',\n            'Metadata',\n            'UpdatePolicy',\n            'UpdateReplacePolicy',\n            'Properties',\n            'Type',\n            'Condition'\n        ]\n\n        valid_custom_attributes = [\n            'Version',\n            'Properties',\n            'DependsOn',\n            'Metadata',\n            'Condition',\n            'Type',\n        ]\n\n        resources = cfn.template.get('Resources', {})\n        if not isinstance(resources, dict):\n            message = 'Resource not properly configured'\n            matches.append(RuleMatch(['Resources'], message))\n        else:\n            for resource_name, resource_values in cfn.template.get('Resources', {}).items():\n                self.logger.debug('Validating resource %s base configuration', resource_name)\n                if not isinstance(resource_values, dict):\n                    message = 'Resource not properly configured at {0}'\n                    matches.append(RuleMatch(\n                        ['Resources', resource_name],\n                        message.format(resource_name)\n                    ))\n                    continue\n                resource_type = resource_values.get('Type', '')\n                check_attributes = []\n                if resource_type.startswith('Custom::') or resource_type == 'AWS::CloudFormation::CustomResource':\n                    check_attributes = valid_custom_attributes\n                else:\n                    check_attributes = valid_attributes\n\n                for property_key, _ in resource_values.items():\n                    if property_key not in check_attributes:\n                        message = 'Invalid resource attribute {0} for resource {1}'\n                        matches.append(RuleMatch(\n                            ['Resources', resource_name, property_key],\n                            message.format(property_key, resource_name)))\n\n                resource_type = resource_values.get('Type', '')\n                if not resource_type:\n                    message = 'Type not defined for resource {0}'\n                    matches.append(RuleMatch(\n                        ['Resources', resource_name],\n                        message.format(resource_name)\n                    ))\n                else:\n                    self.logger.debug('Check resource types by region...')\n                    for region, specs in cfnlint.helpers.RESOURCE_SPECS.items():\n                        if region in cfn.regions:\n                            if resource_type not in specs['ResourceTypes']:\n                                if not resource_type.startswith(('Custom::', 'AWS::Serverless::')):\n                                    message = 'Invalid or unsupported Type {0} for resource {1} in {2}'\n                                    matches.append(RuleMatch(\n                                        ['Resources', resource_name, 'Type'],\n                                        message.format(resource_type, resource_name, region)\n                                    ))\n\n                if 'Properties' not in resource_values:\n                    resource_spec = cfnlint.helpers.RESOURCE_SPECS[cfn.regions[0]]\n                    if resource_type in resource_spec['ResourceTypes']:\n                        properties_spec = resource_spec['ResourceTypes'][resource_type]['Properties']\n                        # pylint: disable=len-as-condition\n                        if len(properties_spec) > 0:\n                            required = 0\n                            for _, property_spec in properties_spec.items():\n                                if property_spec.get('Required', False):\n                                    required += 1\n                            if required > 0:\n                                if resource_type == 'AWS::CloudFormation::WaitCondition' and 'CreationPolicy' in resource_values.keys():\n                                    self.logger.debug('Exception to required properties section as CreationPolicy is defined.')\n                                else:\n                                    message = 'Properties not defined for resource {0}'\n                                    matches.append(RuleMatch(\n                                        ['Resources', resource_name],\n                                        message.format(resource_name)\n                                    ))\n\n        return matches\n", "path": "src/cfnlint/rules/resources/Configuration.py"}], "after_files": [{"content": "\"\"\"\n  Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this\n  software and associated documentation files (the \"Software\"), to deal in the Software\n  without restriction, including without limitation the rights to use, copy, modify,\n  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n  permit persons to whom the Software is furnished to do so.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\nimport six\nfrom cfnlint import CloudFormationLintRule\nfrom cfnlint import RuleMatch\n\n\nclass Exists(CloudFormationLintRule):\n    \"\"\"Check if used Conditions are defined \"\"\"\n    id = 'E8002'\n    shortdesc = 'Check if the referenced Conditions are defined'\n    description = 'Making sure the used conditions are actually defined in the Conditions section'\n    source_url = 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html'\n    tags = ['conditions']\n\n    def match(self, cfn):\n        \"\"\"Check CloudFormation Conditions\"\"\"\n\n        matches = []\n        ref_conditions = {}\n\n        # Get all defined conditions\n        conditions = cfn.template.get('Conditions', {})\n\n        # Get all \"If's\" that reference a Condition\n        iftrees = cfn.search_deep_keys('Fn::If')\n        for iftree in iftrees:\n            if isinstance(iftree[-1], list):\n                ref_conditions[iftree[-1][0]] = iftree\n            else:\n                ref_conditions[iftree[-1]] = iftree\n\n        # Get resource's Conditions\n        for resource_name, resource_values in cfn.get_resources().items():\n            condition = resource_values.get('Condition')\n            if isinstance(condition, six.string_types):  # make sure its a string\n                path = ['Resources', resource_name, 'Condition']\n                ref_conditions[condition] = path\n\n        # Get conditions used by another condition\n        condtrees = cfn.search_deep_keys('Condition')\n\n        for condtree in condtrees:\n            if condtree[0] == 'Conditions':\n                if isinstance(condtree[-1], (str, six.text_type, six.string_types)):\n                    path = ['Conditions', condtree[-1]]\n                    ref_conditions[condtree[-1]] = path\n\n        # Get Output Conditions\n        for _, output_values in cfn.template.get('Outputs', {}).items():\n            if 'Condition' in output_values:\n                path = ['Outputs', output_values['Condition']]\n                ref_conditions[output_values['Condition']] = path\n\n        # Check if all the conditions are defined\n        for ref_condition, ref_path in ref_conditions.items():\n            if ref_condition not in conditions:\n                message = 'Condition {0} is not defined.'\n                matches.append(RuleMatch(\n                    ref_path,\n                    message.format(ref_condition)\n                ))\n\n        return matches\n", "path": "src/cfnlint/rules/conditions/Exists.py"}, {"content": "\"\"\"\n  Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this\n  software and associated documentation files (the \"Software\"), to deal in the Software\n  without restriction, including without limitation the rights to use, copy, modify,\n  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n  permit persons to whom the Software is furnished to do so.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\nimport six\nfrom cfnlint import CloudFormationLintRule\nfrom cfnlint import RuleMatch\nimport cfnlint.helpers\n\n\nclass Configuration(CloudFormationLintRule):\n    \"\"\"Check Base Resource Configuration\"\"\"\n    id = 'E3001'\n    shortdesc = 'Basic CloudFormation Resource Check'\n    description = 'Making sure the basic CloudFormation resources ' + \\\n                  'are properly configured'\n    source_url = 'https://github.com/aws-cloudformation/cfn-python-lint'\n    tags = ['resources']\n\n    def match(self, cfn):\n        \"\"\"Check CloudFormation Resources\"\"\"\n\n        matches = []\n\n        valid_attributes = [\n            'CreationPolicy',\n            'DeletionPolicy',\n            'DependsOn',\n            'Metadata',\n            'UpdatePolicy',\n            'UpdateReplacePolicy',\n            'Properties',\n            'Type',\n            'Condition'\n        ]\n\n        valid_custom_attributes = [\n            'Version',\n            'Properties',\n            'DependsOn',\n            'Metadata',\n            'Condition',\n            'Type',\n        ]\n\n        resources = cfn.template.get('Resources', {})\n        if not isinstance(resources, dict):\n            message = 'Resource not properly configured'\n            matches.append(RuleMatch(['Resources'], message))\n        else:\n            for resource_name, resource_values in cfn.template.get('Resources', {}).items():\n                self.logger.debug('Validating resource %s base configuration', resource_name)\n                if not isinstance(resource_values, dict):\n                    message = 'Resource not properly configured at {0}'\n                    matches.append(RuleMatch(\n                        ['Resources', resource_name],\n                        message.format(resource_name)\n                    ))\n                    continue\n                resource_type = resource_values.get('Type', '')\n                check_attributes = []\n                if resource_type.startswith('Custom::') or resource_type == 'AWS::CloudFormation::CustomResource':\n                    check_attributes = valid_custom_attributes\n                else:\n                    check_attributes = valid_attributes\n\n                for property_key, _ in resource_values.items():\n                    if property_key not in check_attributes:\n                        message = 'Invalid resource attribute {0} for resource {1}'\n                        matches.append(RuleMatch(\n                            ['Resources', resource_name, property_key],\n                            message.format(property_key, resource_name)))\n\n                # validate condition is a string\n                condition = resource_values.get('Condition', '')\n                if not isinstance(condition, six.string_types):\n                    message = 'Condition for resource {0} should be a string'\n                    matches.append(RuleMatch(\n                        ['Resources', resource_name, 'Condition'],\n                        message.format(resource_name)\n                    ))\n\n                resource_type = resource_values.get('Type', '')\n                if not resource_type:\n                    message = 'Type not defined for resource {0}'\n                    matches.append(RuleMatch(\n                        ['Resources', resource_name],\n                        message.format(resource_name)\n                    ))\n                else:\n                    self.logger.debug('Check resource types by region...')\n                    for region, specs in cfnlint.helpers.RESOURCE_SPECS.items():\n                        if region in cfn.regions:\n                            if resource_type not in specs['ResourceTypes']:\n                                if not resource_type.startswith(('Custom::', 'AWS::Serverless::')):\n                                    message = 'Invalid or unsupported Type {0} for resource {1} in {2}'\n                                    matches.append(RuleMatch(\n                                        ['Resources', resource_name, 'Type'],\n                                        message.format(resource_type, resource_name, region)\n                                    ))\n\n                if 'Properties' not in resource_values:\n                    resource_spec = cfnlint.helpers.RESOURCE_SPECS[cfn.regions[0]]\n                    if resource_type in resource_spec['ResourceTypes']:\n                        properties_spec = resource_spec['ResourceTypes'][resource_type]['Properties']\n                        # pylint: disable=len-as-condition\n                        if len(properties_spec) > 0:\n                            required = 0\n                            for _, property_spec in properties_spec.items():\n                                if property_spec.get('Required', False):\n                                    required += 1\n                            if required > 0:\n                                if resource_type == 'AWS::CloudFormation::WaitCondition' and 'CreationPolicy' in resource_values.keys():\n                                    self.logger.debug('Exception to required properties section as CreationPolicy is defined.')\n                                else:\n                                    message = 'Properties not defined for resource {0}'\n                                    matches.append(RuleMatch(\n                                        ['Resources', resource_name],\n                                        message.format(resource_name)\n                                    ))\n\n        return matches\n", "path": "src/cfnlint/rules/resources/Configuration.py"}]}