Skip to content

Commit ac8d51d

Browse files
authored
Update getatt resolution for better regional support (#3597)
1 parent 69fbdff commit ac8d51d

File tree

5 files changed

+50
-46
lines changed

5 files changed

+50
-46
lines changed

src/cfnlint/context/context.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ def __post_init__(self, resource) -> None:
375375
raise ValueError("Condition must be a string")
376376
self.condition = c
377377

378-
@property
379378
def get_atts(self, region: str = "us-east-1") -> AttributeDict:
380379
return PROVIDER_SCHEMA_MANAGER.get_type_getatts(self.type, region)
381380

src/cfnlint/rules/functions/GetAtt.py

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -82,43 +82,46 @@ def _resolve_getatt(
8282
yield err
8383
break
8484
else:
85-
for attribute_name, _, _ in validator.resolve_value(value[1]):
86-
if all(
87-
not (bool(re.fullmatch(each, attribute_name)))
88-
for each in validator.context.resources[resource_name].get_atts
89-
):
90-
err = ValidationError(
91-
(
92-
f"{attribute_name!r} is not one of "
93-
f"{validator.context.resources[resource_name].get_atts!r}"
94-
),
95-
validator=self.fn.py,
96-
path=deque([self.fn.name, 1]),
97-
)
98-
if attribute_name != value[1]:
99-
err.message = (
100-
err.message + f" when {value[1]!r} is resolved"
85+
t = validator.context.resources[resource_name].type
86+
for (
87+
regions,
88+
schema,
89+
) in PROVIDER_SCHEMA_MANAGER.get_resource_schemas_by_regions(
90+
t, validator.context.regions
91+
):
92+
region = regions[0]
93+
for attribute_name, _, _ in validator.resolve_value(value[1]):
94+
if all(
95+
not (bool(re.fullmatch(each, attribute_name)))
96+
for each in validator.context.resources[
97+
resource_name
98+
].get_atts(region)
99+
):
100+
err = ValidationError(
101+
(
102+
f"{attribute_name!r} is not one of "
103+
f"{validator.context.resources[resource_name].get_atts(region)!r}"
104+
f" in {regions!r}"
105+
),
106+
validator=self.fn.py,
107+
path=deque([self.fn.name, 1]),
101108
)
102-
yield err
103-
continue
104-
105-
evolved = validator.evolve(schema=s) # type: ignore
106-
evolved.validators = { # type: ignore
107-
"type": validator.validators.get("type"), # type: ignore
108-
}
109-
110-
getatts = validator.cfn.get_valid_getatts()
111-
t = validator.context.resources[resource_name].type
112-
pointer = getatts.match(
113-
validator.context.regions[0], [resource_name, attribute_name]
114-
)
115-
116-
for (
117-
_,
118-
schema,
119-
) in PROVIDER_SCHEMA_MANAGER.get_resource_schemas_by_regions(
120-
t, validator.context.regions
121-
):
109+
if attribute_name != value[1]:
110+
err.message = (
111+
err.message + f" when {value[1]!r} is resolved"
112+
)
113+
yield err
114+
continue
115+
116+
evolved = validator.evolve(schema=s) # type: ignore
117+
evolved.validators = { # type: ignore
118+
"type": validator.validators.get("type"), # type: ignore
119+
}
120+
121+
getatts = validator.cfn.get_valid_getatts()
122+
t = validator.context.resources[resource_name].type
123+
pointer = getatts.match(region, [resource_name, attribute_name])
124+
122125
getatt_schema = schema.resolver.resolve_cfn_pointer(pointer)
123126
if not getatt_schema.get("type") or not s.get("type"):
124127
continue

src/cfnlint/rules/functions/GetAttFormat.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,19 @@ def validate(
4242

4343
resource, attr = instance[0:2]
4444

45-
getatt_ptr = validator.context.resources[resource].get_atts[attr]
4645
t = validator.context.resources[resource].type
47-
48-
if t in self._resource_type_exceptions:
49-
return
50-
5146
for (
52-
_,
47+
regions,
5348
resource_schema,
5449
) in PROVIDER_SCHEMA_MANAGER.get_resource_schemas_by_regions(
5550
t, validator.context.regions
5651
):
52+
region = regions[0]
53+
getatt_ptr = validator.context.resources[resource].get_atts(region)[attr]
54+
55+
if t in self._resource_type_exceptions:
56+
return
57+
5758
getatt_schema = resource_schema.resolver.resolve_cfn_pointer(getatt_ptr)
5859
getatt_fmt = getatt_schema.get("format")
5960
if getatt_fmt != fmt:

test/unit/rules/functions/test_getatt.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ def validate(self, validator, s, instance, schema):
8686
ValidationError(
8787
(
8888
"'foo' is not one of ['Arn', 'DomainName', "
89-
"'DualStackDomainName', 'RegionalDomainName', 'WebsiteURL']"
89+
"'DualStackDomainName', 'RegionalDomainName', 'WebsiteURL'] "
90+
"in ['us-east-1']"
9091
),
9192
path=deque(["Fn::GetAtt", 1]),
9293
schema_path=deque([]),
@@ -219,7 +220,7 @@ def validate(self, validator, s, instance, schema):
219220
(
220221
"'MyBucket' is not one of ['Arn', 'DomainName', "
221222
"'DualStackDomainName', 'RegionalDomainName', "
222-
"'WebsiteURL'] when "
223+
"'WebsiteURL'] in ['us-east-1'] when "
223224
"{'Ref': 'MyResourceParameter'} is resolved"
224225
),
225226
path=deque(["Fn::GetAtt", 1]),

test/unit/rules/functions/test_sub.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def context(cfn):
249249
"'DomainName', "
250250
"'DualStackDomainName', "
251251
"'RegionalDomainName', "
252-
"'WebsiteURL']"
252+
"'WebsiteURL'] in ['us-east-1']"
253253
),
254254
path=deque(["Fn::Sub"]),
255255
schema_path=deque([]),

0 commit comments

Comments
 (0)