We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
aws - glue connection has NoneType error when no VPC
### Describe the bug

When there is no VPC on the Glue connection resource, we get a `TypeError: 'NoneType' object is not iterable` error

### What did you expect to happen?

Succeed in this case.

### Cloud Provider

Amazon Web Services (AWS)

### Cloud Custodian version and dependency information

```shell
Custodian:   0.9.32
Python:      3.9.6 (default, Aug 11 2023, 19:44:49) 
             [Clang 15.0.0 (clang-1500.0.40.1)]
```


### Policy

_No response_

### Relevant log/traceback output

```shell
ERROR    custodian.output:output.py:336 Error while executing policy
Traceback (most recent call last):
  File "/Users/timmygrable/Projects/cloud-custodian/c7n/policy.py", line 330, in run
    resources = self.policy.resource_manager.resources()
  File "/Users/timmygrable/Projects/cloud-custodian/c7n/query.py", line 549, in resources
    resources = self.filter_resources(resources)
  File "/Users/timmygrable/Projects/cloud-custodian/c7n/manager.py", line 112, in filter_resources
    resources = f.process(resources, event)
  File "/Users/timmygrable/Projects/cloud-custodian/c7n/filters/vpc.py", line 98, in process
    related = self.get_related(resources)
  File "/Users/timmygrable/Projects/cloud-custodian/c7n/filters/related.py", line 49, in get_related
    return {r[model.id]: r for r in related
TypeError: 'NoneType' object is not iterable
```


### Extra information or context

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `c7n/filters/related.py`
Content:
```
1 # Copyright The Cloud Custodian Authors.
2 # SPDX-License-Identifier: Apache-2.0
3 import importlib
4 from functools import lru_cache
5 
6 from .core import ValueFilter, OPERATORS
7 from c7n.query import ChildResourceQuery
8 from c7n.utils import jmespath_search
9 
10 
11 class RelatedResourceFilter(ValueFilter):
12 
13     schema_alias = False
14 
15     RelatedResource = None
16     RelatedIdsExpression = None
17     AnnotationKey = None
18     FetchThreshold = 10
19 
20     def get_permissions(self):
21         return self.get_resource_manager().get_permissions()
22 
23     def validate(self):
24         name = self.__class__.__name__
25         if self.RelatedIdsExpression is None:
26             raise ValueError(
27                 "%s Filter requires resource expression" % name)
28         # if self.AnnotationKey is None:
29         #    raise ValueError(
30         #        "%s Filter requires annotation key" % name)
31 
32         if self.RelatedResource is None:
33             raise ValueError(
34                 "%s Filter requires resource manager spec" % name)
35         return super(RelatedResourceFilter, self).validate()
36 
37     def get_related_ids(self, resources):
38         return set(jmespath_search(
39             "[].%s" % self.RelatedIdsExpression, resources))
40 
41     def get_related(self, resources):
42         resource_manager = self.get_resource_manager()
43         related_ids = self.get_related_ids(resources)
44         model = resource_manager.get_model()
45         if len(related_ids) < self.FetchThreshold:
46             related = resource_manager.get_resources(list(related_ids))
47         else:
48             related = resource_manager.resources()
49         return {r[model.id]: r for r in related
50                 if r[model.id] in related_ids}
51 
52     @lru_cache(maxsize=None)
53     def get_resource_manager(self):
54         mod_path, class_name = self.RelatedResource.rsplit('.', 1)
55         module = importlib.import_module(mod_path)
56         manager_class = getattr(module, class_name)
57         return manager_class(self.manager.ctx, {})
58 
59     def process_resource(self, resource, related):
60         related_ids = self.get_related_ids([resource])
61         model = self.manager.get_model()
62         op = self.data.get('operator', 'or')
63         found = []
64 
65         if self.data.get('match-resource') is True:
66             self.data['value'] = self.get_resource_value(
67                 self.data['key'], resource)
68 
69         if self.data.get('value_type') == 'resource_count':
70             count_matches = OPERATORS[self.data.get('op')](len(related_ids), self.data.get('value'))
71             if count_matches:
72                 self._add_annotations(related_ids, resource)
73             return count_matches
74 
75         for rid in related_ids:
76             robj = related.get(rid, None)
77             if robj is None:
78                 # in the event that the filter is looking specifically for absent values, we can
79                 # safely assume that the non-existant related resource will have an absent value at
80                 # any given key
81                 if self.data['value'] == 'absent':
82                     found.append(rid)
83                 else:
84                     self.log.warning(
85                         "Resource %s:%s references non existant %s: %s",
86                         self.manager.type,
87                         resource[model.id],
88                         self.RelatedResource.rsplit('.', 1)[-1],
89                         rid)
90                 continue
91             if self.match(robj):
92                 found.append(rid)
93 
94         if found:
95             self._add_annotations(found, resource)
96 
97         if op == 'or' and found:
98             return True
99         elif op == 'and' and len(found) == len(related_ids):
100             return True
101         return False
102 
103     def _add_annotations(self, related_ids, resource):
104         if self.AnnotationKey is not None:
105             akey = 'c7n:%s' % self.AnnotationKey
106             resource[akey] = list(set(related_ids).union(resource.get(akey, [])))
107 
108     def process(self, resources, event=None):
109         related = self.get_related(resources)
110         return [r for r in resources if self.process_resource(r, related)]
111 
112 
113 class RelatedResourceByIdFilter(RelatedResourceFilter):
114     """
115     Value filter for related resources in which the main resource only contains the related
116     resource id.
117     """
118 
119     RelatedResourceByIdExpression = None
120 
121     def get_related(self, resources):
122         resource_manager = self.get_resource_manager()
123         related_ids = self.get_related_ids(resources)
124 
125         related = {}
126         for r in resource_manager.resources():
127             matched_vpc = self.get_related_by_ids(r) & related_ids
128             if matched_vpc:
129                 for vpc in matched_vpc:
130                     related_resources = related.get(vpc, [])
131                     related_resources.append(r)
132                     related[vpc] = related_resources
133         return related
134 
135     def get_related_by_ids(self, resources):
136         RelatedResourceKey = self.RelatedResourceByIdExpression or self.RelatedIdsExpression
137         ids = jmespath_search("%s" % RelatedResourceKey, resources)
138         if isinstance(ids, str):
139             ids = [ids]
140         return set(ids)
141 
142     def process_resource(self, resource, related):
143         related_ids = self.get_related_ids([resource])
144         op = self.data.get('operator', 'or')
145         found = []
146 
147         if self.data.get('match-resource') is True:
148             self.data['value'] = self.get_resource_value(
149                 self.data['key'], resource)
150 
151         if self.data.get('value_type') == 'resource_count':
152             count_matches = OPERATORS[self.data.get('op')](len(related_ids), self.data.get('value'))
153             if count_matches:
154                 self._add_annotations(related_ids, resource)
155             return count_matches
156 
157         for rid in related_ids:
158             robjs = related.get(rid, [None])
159             for robj in robjs:
160                 if robj is None:
161                     continue
162                 if self.match(robj):
163                     found.append(rid)
164 
165         if found:
166             self._add_annotations(found, resource)
167 
168         if op == 'or' and found:
169             return True
170         elif op == 'and' and len(found) == len(related_ids):
171             return True
172         return False
173 
174 
175 class ChildResourceFilter(RelatedResourceFilter):
176     ChildResource = None
177     RelatedIdsExpression = None
178     ChildResourceParentKey = "c7n:parent-id"
179 
180     def get_related(self, resources):
181         self.child_resources = {}
182 
183         parent_ids = self.get_related_ids(resources)
184 
185         child_resource_manager = self.get_resource_manager()
186         child_query = ChildResourceQuery(
187             child_resource_manager.session_factory,
188             child_resource_manager,
189         )
190         children = child_query.filter(child_resource_manager, parent_ids=list(parent_ids))
191         for r in children:
192             self.child_resources.setdefault(r[self.ChildResourceParentKey], []).append(r)
193 
194         return self.child_resources
195 
196     def _add_annotations(self, related_ids, resource):
197         if self.AnnotationKey is not None:
198             model = self.manager.get_model()
199             akey = 'c7n:%s' % self.AnnotationKey
200             resource[akey] = self.child_resources.get(resource[model.id], [])
201
```
--- 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/c7n/filters/related.py b/c7n/filters/related.py
--- a/c7n/filters/related.py
+++ b/c7n/filters/related.py
@@ -46,6 +46,10 @@
             related = resource_manager.get_resources(list(related_ids))
         else:
             related = resource_manager.resources()
+
+        if related is None:
+            return {}
+
         return {r[model.id]: r for r in related
                 if r[model.id] in related_ids}

{"golden_diff": "diff --git a/c7n/filters/related.py b/c7n/filters/related.py\n--- a/c7n/filters/related.py\n+++ b/c7n/filters/related.py\n@@ -46,6 +46,10 @@\n             related = resource_manager.get_resources(list(related_ids))\n         else:\n             related = resource_manager.resources()\n+\n+        if related is None:\n+            return {}\n+\n         return {r[model.id]: r for r in related\n                 if r[model.id] in related_ids}\n", "issue": "aws - glue connection has NoneType error when no VPC\n### Describe the bug\n\nWhen there is no VPC on the Glue connection resource, we get a `TypeError: 'NoneType' object is not iterable` error\n\n### What did you expect to happen?\n\nSucceed in this case.\n\n### Cloud Provider\n\nAmazon Web Services (AWS)\n\n### Cloud Custodian version and dependency information\n\n```shell\nCustodian:   0.9.32\r\nPython:      3.9.6 (default, Aug 11 2023, 19:44:49) \r\n             [Clang 15.0.0 (clang-1500.0.40.1)]\n```\n\n\n### Policy\n\n_No response_\n\n### Relevant log/traceback output\n\n```shell\nERROR    custodian.output:output.py:336 Error while executing policy\r\nTraceback (most recent call last):\r\n  File \"/Users/timmygrable/Projects/cloud-custodian/c7n/policy.py\", line 330, in run\r\n    resources = self.policy.resource_manager.resources()\r\n  File \"/Users/timmygrable/Projects/cloud-custodian/c7n/query.py\", line 549, in resources\r\n    resources = self.filter_resources(resources)\r\n  File \"/Users/timmygrable/Projects/cloud-custodian/c7n/manager.py\", line 112, in filter_resources\r\n    resources = f.process(resources, event)\r\n  File \"/Users/timmygrable/Projects/cloud-custodian/c7n/filters/vpc.py\", line 98, in process\r\n    related = self.get_related(resources)\r\n  File \"/Users/timmygrable/Projects/cloud-custodian/c7n/filters/related.py\", line 49, in get_related\r\n    return {r[model.id]: r for r in related\r\nTypeError: 'NoneType' object is not iterable\n```\n\n\n### Extra information or context\n\n_No response_\n", "before_files": [{"content": "# Copyright The Cloud Custodian Authors.\n# SPDX-License-Identifier: Apache-2.0\nimport importlib\nfrom functools import lru_cache\n\nfrom .core import ValueFilter, OPERATORS\nfrom c7n.query import ChildResourceQuery\nfrom c7n.utils import jmespath_search\n\n\nclass RelatedResourceFilter(ValueFilter):\n\n    schema_alias = False\n\n    RelatedResource = None\n    RelatedIdsExpression = None\n    AnnotationKey = None\n    FetchThreshold = 10\n\n    def get_permissions(self):\n        return self.get_resource_manager().get_permissions()\n\n    def validate(self):\n        name = self.__class__.__name__\n        if self.RelatedIdsExpression is None:\n            raise ValueError(\n                \"%s Filter requires resource expression\" % name)\n        # if self.AnnotationKey is None:\n        #    raise ValueError(\n        #        \"%s Filter requires annotation key\" % name)\n\n        if self.RelatedResource is None:\n            raise ValueError(\n                \"%s Filter requires resource manager spec\" % name)\n        return super(RelatedResourceFilter, self).validate()\n\n    def get_related_ids(self, resources):\n        return set(jmespath_search(\n            \"[].%s\" % self.RelatedIdsExpression, resources))\n\n    def get_related(self, resources):\n        resource_manager = self.get_resource_manager()\n        related_ids = self.get_related_ids(resources)\n        model = resource_manager.get_model()\n        if len(related_ids) < self.FetchThreshold:\n            related = resource_manager.get_resources(list(related_ids))\n        else:\n            related = resource_manager.resources()\n        return {r[model.id]: r for r in related\n                if r[model.id] in related_ids}\n\n    @lru_cache(maxsize=None)\n    def get_resource_manager(self):\n        mod_path, class_name = self.RelatedResource.rsplit('.', 1)\n        module = importlib.import_module(mod_path)\n        manager_class = getattr(module, class_name)\n        return manager_class(self.manager.ctx, {})\n\n    def process_resource(self, resource, related):\n        related_ids = self.get_related_ids([resource])\n        model = self.manager.get_model()\n        op = self.data.get('operator', 'or')\n        found = []\n\n        if self.data.get('match-resource') is True:\n            self.data['value'] = self.get_resource_value(\n                self.data['key'], resource)\n\n        if self.data.get('value_type') == 'resource_count':\n            count_matches = OPERATORS[self.data.get('op')](len(related_ids), self.data.get('value'))\n            if count_matches:\n                self._add_annotations(related_ids, resource)\n            return count_matches\n\n        for rid in related_ids:\n            robj = related.get(rid, None)\n            if robj is None:\n                # in the event that the filter is looking specifically for absent values, we can\n                # safely assume that the non-existant related resource will have an absent value at\n                # any given key\n                if self.data['value'] == 'absent':\n                    found.append(rid)\n                else:\n                    self.log.warning(\n                        \"Resource %s:%s references non existant %s: %s\",\n                        self.manager.type,\n                        resource[model.id],\n                        self.RelatedResource.rsplit('.', 1)[-1],\n                        rid)\n                continue\n            if self.match(robj):\n                found.append(rid)\n\n        if found:\n            self._add_annotations(found, resource)\n\n        if op == 'or' and found:\n            return True\n        elif op == 'and' and len(found) == len(related_ids):\n            return True\n        return False\n\n    def _add_annotations(self, related_ids, resource):\n        if self.AnnotationKey is not None:\n            akey = 'c7n:%s' % self.AnnotationKey\n            resource[akey] = list(set(related_ids).union(resource.get(akey, [])))\n\n    def process(self, resources, event=None):\n        related = self.get_related(resources)\n        return [r for r in resources if self.process_resource(r, related)]\n\n\nclass RelatedResourceByIdFilter(RelatedResourceFilter):\n    \"\"\"\n    Value filter for related resources in which the main resource only contains the related\n    resource id.\n    \"\"\"\n\n    RelatedResourceByIdExpression = None\n\n    def get_related(self, resources):\n        resource_manager = self.get_resource_manager()\n        related_ids = self.get_related_ids(resources)\n\n        related = {}\n        for r in resource_manager.resources():\n            matched_vpc = self.get_related_by_ids(r) & related_ids\n            if matched_vpc:\n                for vpc in matched_vpc:\n                    related_resources = related.get(vpc, [])\n                    related_resources.append(r)\n                    related[vpc] = related_resources\n        return related\n\n    def get_related_by_ids(self, resources):\n        RelatedResourceKey = self.RelatedResourceByIdExpression or self.RelatedIdsExpression\n        ids = jmespath_search(\"%s\" % RelatedResourceKey, resources)\n        if isinstance(ids, str):\n            ids = [ids]\n        return set(ids)\n\n    def process_resource(self, resource, related):\n        related_ids = self.get_related_ids([resource])\n        op = self.data.get('operator', 'or')\n        found = []\n\n        if self.data.get('match-resource') is True:\n            self.data['value'] = self.get_resource_value(\n                self.data['key'], resource)\n\n        if self.data.get('value_type') == 'resource_count':\n            count_matches = OPERATORS[self.data.get('op')](len(related_ids), self.data.get('value'))\n            if count_matches:\n                self._add_annotations(related_ids, resource)\n            return count_matches\n\n        for rid in related_ids:\n            robjs = related.get(rid, [None])\n            for robj in robjs:\n                if robj is None:\n                    continue\n                if self.match(robj):\n                    found.append(rid)\n\n        if found:\n            self._add_annotations(found, resource)\n\n        if op == 'or' and found:\n            return True\n        elif op == 'and' and len(found) == len(related_ids):\n            return True\n        return False\n\n\nclass ChildResourceFilter(RelatedResourceFilter):\n    ChildResource = None\n    RelatedIdsExpression = None\n    ChildResourceParentKey = \"c7n:parent-id\"\n\n    def get_related(self, resources):\n        self.child_resources = {}\n\n        parent_ids = self.get_related_ids(resources)\n\n        child_resource_manager = self.get_resource_manager()\n        child_query = ChildResourceQuery(\n            child_resource_manager.session_factory,\n            child_resource_manager,\n        )\n        children = child_query.filter(child_resource_manager, parent_ids=list(parent_ids))\n        for r in children:\n            self.child_resources.setdefault(r[self.ChildResourceParentKey], []).append(r)\n\n        return self.child_resources\n\n    def _add_annotations(self, related_ids, resource):\n        if self.AnnotationKey is not None:\n            model = self.manager.get_model()\n            akey = 'c7n:%s' % self.AnnotationKey\n            resource[akey] = self.child_resources.get(resource[model.id], [])\n", "path": "c7n/filters/related.py"}], "after_files": [{"content": "# Copyright The Cloud Custodian Authors.\n# SPDX-License-Identifier: Apache-2.0\nimport importlib\nfrom functools import lru_cache\n\nfrom .core import ValueFilter, OPERATORS\nfrom c7n.query import ChildResourceQuery\nfrom c7n.utils import jmespath_search\n\n\nclass RelatedResourceFilter(ValueFilter):\n\n    schema_alias = False\n\n    RelatedResource = None\n    RelatedIdsExpression = None\n    AnnotationKey = None\n    FetchThreshold = 10\n\n    def get_permissions(self):\n        return self.get_resource_manager().get_permissions()\n\n    def validate(self):\n        name = self.__class__.__name__\n        if self.RelatedIdsExpression is None:\n            raise ValueError(\n                \"%s Filter requires resource expression\" % name)\n        # if self.AnnotationKey is None:\n        #    raise ValueError(\n        #        \"%s Filter requires annotation key\" % name)\n\n        if self.RelatedResource is None:\n            raise ValueError(\n                \"%s Filter requires resource manager spec\" % name)\n        return super(RelatedResourceFilter, self).validate()\n\n    def get_related_ids(self, resources):\n        return set(jmespath_search(\n            \"[].%s\" % self.RelatedIdsExpression, resources))\n\n    def get_related(self, resources):\n        resource_manager = self.get_resource_manager()\n        related_ids = self.get_related_ids(resources)\n        model = resource_manager.get_model()\n        if len(related_ids) < self.FetchThreshold:\n            related = resource_manager.get_resources(list(related_ids))\n        else:\n            related = resource_manager.resources()\n\n        if related is None:\n            return {}\n\n        return {r[model.id]: r for r in related\n                if r[model.id] in related_ids}\n\n    @lru_cache(maxsize=None)\n    def get_resource_manager(self):\n        mod_path, class_name = self.RelatedResource.rsplit('.', 1)\n        module = importlib.import_module(mod_path)\n        manager_class = getattr(module, class_name)\n        return manager_class(self.manager.ctx, {})\n\n    def process_resource(self, resource, related):\n        related_ids = self.get_related_ids([resource])\n        model = self.manager.get_model()\n        op = self.data.get('operator', 'or')\n        found = []\n\n        if self.data.get('match-resource') is True:\n            self.data['value'] = self.get_resource_value(\n                self.data['key'], resource)\n\n        if self.data.get('value_type') == 'resource_count':\n            count_matches = OPERATORS[self.data.get('op')](len(related_ids), self.data.get('value'))\n            if count_matches:\n                self._add_annotations(related_ids, resource)\n            return count_matches\n\n        for rid in related_ids:\n            robj = related.get(rid, None)\n            if robj is None:\n                # in the event that the filter is looking specifically for absent values, we can\n                # safely assume that the non-existant related resource will have an absent value at\n                # any given key\n                if self.data['value'] == 'absent':\n                    found.append(rid)\n                else:\n                    self.log.warning(\n                        \"Resource %s:%s references non existant %s: %s\",\n                        self.manager.type,\n                        resource[model.id],\n                        self.RelatedResource.rsplit('.', 1)[-1],\n                        rid)\n                continue\n            if self.match(robj):\n                found.append(rid)\n\n        if found:\n            self._add_annotations(found, resource)\n\n        if op == 'or' and found:\n            return True\n        elif op == 'and' and len(found) == len(related_ids):\n            return True\n        return False\n\n    def _add_annotations(self, related_ids, resource):\n        if self.AnnotationKey is not None:\n            akey = 'c7n:%s' % self.AnnotationKey\n            resource[akey] = list(set(related_ids).union(resource.get(akey, [])))\n\n    def process(self, resources, event=None):\n        related = self.get_related(resources)\n        return [r for r in resources if self.process_resource(r, related)]\n\n\nclass RelatedResourceByIdFilter(RelatedResourceFilter):\n    \"\"\"\n    Value filter for related resources in which the main resource only contains the related\n    resource id.\n    \"\"\"\n\n    RelatedResourceByIdExpression = None\n\n    def get_related(self, resources):\n        resource_manager = self.get_resource_manager()\n        related_ids = self.get_related_ids(resources)\n\n        related = {}\n        for r in resource_manager.resources():\n            matched_vpc = self.get_related_by_ids(r) & related_ids\n            if matched_vpc:\n                for vpc in matched_vpc:\n                    related_resources = related.get(vpc, [])\n                    related_resources.append(r)\n                    related[vpc] = related_resources\n        return related\n\n    def get_related_by_ids(self, resources):\n        RelatedResourceKey = self.RelatedResourceByIdExpression or self.RelatedIdsExpression\n        ids = jmespath_search(\"%s\" % RelatedResourceKey, resources)\n        if isinstance(ids, str):\n            ids = [ids]\n        return set(ids)\n\n    def process_resource(self, resource, related):\n        related_ids = self.get_related_ids([resource])\n        op = self.data.get('operator', 'or')\n        found = []\n\n        if self.data.get('match-resource') is True:\n            self.data['value'] = self.get_resource_value(\n                self.data['key'], resource)\n\n        if self.data.get('value_type') == 'resource_count':\n            count_matches = OPERATORS[self.data.get('op')](len(related_ids), self.data.get('value'))\n            if count_matches:\n                self._add_annotations(related_ids, resource)\n            return count_matches\n\n        for rid in related_ids:\n            robjs = related.get(rid, [None])\n            for robj in robjs:\n                if robj is None:\n                    continue\n                if self.match(robj):\n                    found.append(rid)\n\n        if found:\n            self._add_annotations(found, resource)\n\n        if op == 'or' and found:\n            return True\n        elif op == 'and' and len(found) == len(related_ids):\n            return True\n        return False\n\n\nclass ChildResourceFilter(RelatedResourceFilter):\n    ChildResource = None\n    RelatedIdsExpression = None\n    ChildResourceParentKey = \"c7n:parent-id\"\n\n    def get_related(self, resources):\n        self.child_resources = {}\n\n        parent_ids = self.get_related_ids(resources)\n\n        child_resource_manager = self.get_resource_manager()\n        child_query = ChildResourceQuery(\n            child_resource_manager.session_factory,\n            child_resource_manager,\n        )\n        children = child_query.filter(child_resource_manager, parent_ids=list(parent_ids))\n        for r in children:\n            self.child_resources.setdefault(r[self.ChildResourceParentKey], []).append(r)\n\n        return self.child_resources\n\n    def _add_annotations(self, related_ids, resource):\n        if self.AnnotationKey is not None:\n            model = self.manager.get_model()\n            akey = 'c7n:%s' % self.AnnotationKey\n            resource[akey] = self.child_resources.get(resource[model.id], [])\n", "path": "c7n/filters/related.py"}]}