Skip to content

Commit 93fd15e

Browse files
authored
Make an exception for DocDB Cluster Port return type (#3759)
* Make an exception for DocDB Cluster Port return type
1 parent 03c8c46 commit 93fd15e

File tree

8 files changed

+67
-58
lines changed

8 files changed

+67
-58
lines changed

src/cfnlint/rules/functions/GetAtt.py

+11
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ def _resolve_getatt(
123123
pointer = getatts.match(region, [resource_name, attribute_name])
124124

125125
getatt_schema = schema.resolver.resolve_cfn_pointer(pointer)
126+
# there is one exception we need to handle. The resource type
127+
# has a mix of types the input is integer and the output
128+
# is string. Since this is the only occurence
129+
# we are putting in an exception to it.
130+
if (
131+
validator.context.resources[resource_name].type
132+
== "AWS::DocDB::DBCluster"
133+
and attribute_name == "Port"
134+
):
135+
getatt_schema = {"type": "string"}
136+
126137
if not getatt_schema.get("type") or not s.get("type"):
127138
continue
128139

src/cfnlint/rules/outputs/Value.py

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def validate(self, validator: Validator, _: Any, instance: Any, schema: Any):
4444
conditions=validator.context.conditions.evolve(
4545
conditions,
4646
),
47+
strict_types=False,
4748
)
4849
)
4950

src/cfnlint/schema/_getatts.py

-4
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,6 @@
126126
"AWS::DocDB::DBCluster": [
127127
"Port",
128128
],
129-
"AWS::EC2::Instance": [
130-
"AvailabilityZone",
131-
],
132-
"AWS::EC2::SecurityGroup": ["VpcId"],
133129
"AWS::Greengrass::ConnectorDefinition": [
134130
"Name",
135131
],

test/fixtures/results/integration/getatt-types.json

+21-21
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
},
3232
{
3333
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
34-
"Id": "76c89a87-5cd1-4dcd-1050-b5dc891de1fe",
34+
"Id": "f9f8618f-c9a0-d78f-84f6-a2fb809cc514",
3535
"Level": "Error",
3636
"Location": {
3737
"End": {
3838
"ColumnNumber": 69,
39-
"LineNumber": 29
39+
"LineNumber": 35
4040
},
4141
"Path": [
4242
"Outputs",
@@ -49,7 +49,7 @@
4949
],
5050
"Start": {
5151
"ColumnNumber": 57,
52-
"LineNumber": 29
52+
"LineNumber": 35
5353
}
5454
},
5555
"Message": "{'Fn::GetAtt': ['CapacityReservation', 'InstanceCount']} is not of type 'string'",
@@ -63,12 +63,12 @@
6363
},
6464
{
6565
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
66-
"Id": "efe80ed4-7370-e389-6d0f-9e5234a86db9",
66+
"Id": "518fa518-bd82-b365-8ec2-c48ae8581f3e",
6767
"Level": "Error",
6868
"Location": {
6969
"End": {
7070
"ColumnNumber": 10,
71-
"LineNumber": 31
71+
"LineNumber": 37
7272
},
7373
"Path": [
7474
"Outputs",
@@ -78,7 +78,7 @@
7878
],
7979
"Start": {
8080
"ColumnNumber": 5,
81-
"LineNumber": 31
81+
"LineNumber": 37
8282
}
8383
},
8484
"Message": "{'Fn::GetAtt': ['CapacityReservation', 'InstanceCount']} is not of type 'string'",
@@ -92,12 +92,12 @@
9292
},
9393
{
9494
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
95-
"Id": "75ebbb04-db20-4d32-4546-8fe0b984ef73",
95+
"Id": "3ff33f0b-1651-bc3b-710e-e603779c3c5f",
9696
"Level": "Error",
9797
"Location": {
9898
"End": {
9999
"ColumnNumber": 10,
100-
"LineNumber": 33
100+
"LineNumber": 39
101101
},
102102
"Path": [
103103
"Outputs",
@@ -107,7 +107,7 @@
107107
],
108108
"Start": {
109109
"ColumnNumber": 5,
110-
"LineNumber": 33
110+
"LineNumber": 39
111111
}
112112
},
113113
"Message": "'CapacityReservation.InstanceCount' is not of type 'string'",
@@ -121,12 +121,12 @@
121121
},
122122
{
123123
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
124-
"Id": "5dd605a3-2dee-84bd-905b-ddc1a10cc24f",
124+
"Id": "c9b79105-67dc-dbe7-3757-b4a9d47c5366",
125125
"Level": "Informational",
126126
"Location": {
127127
"End": {
128128
"ColumnNumber": 22,
129-
"LineNumber": 35
129+
"LineNumber": 41
130130
},
131131
"Path": [
132132
"Outputs",
@@ -137,7 +137,7 @@
137137
],
138138
"Start": {
139139
"ColumnNumber": 20,
140-
"LineNumber": 35
140+
"LineNumber": 41
141141
}
142142
},
143143
"Message": "Prefer using Fn::Sub over Fn::Join with an empty delimiter",
@@ -151,12 +151,12 @@
151151
},
152152
{
153153
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
154-
"Id": "518fa518-bd82-b365-8ec2-c48ae8581f3e",
154+
"Id": "e9db8f22-319e-6556-6eef-9dfb16e9aa1b",
155155
"Level": "Error",
156156
"Location": {
157157
"End": {
158158
"ColumnNumber": 10,
159-
"LineNumber": 37
159+
"LineNumber": 43
160160
},
161161
"Path": [
162162
"Outputs",
@@ -169,7 +169,7 @@
169169
],
170170
"Start": {
171171
"ColumnNumber": 5,
172-
"LineNumber": 37
172+
"LineNumber": 43
173173
}
174174
},
175175
"Message": "{'Fn::GetAtt': ['CapacityReservation', 'InstanceCount']} is not of type 'string'",
@@ -183,12 +183,12 @@
183183
},
184184
{
185185
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
186-
"Id": "59af0561-c0a4-cef0-bca5-bcd57975d7b3",
186+
"Id": "a777b7aa-5a61-f44b-0e11-7f8fad0117c0",
187187
"Level": "Informational",
188188
"Location": {
189189
"End": {
190190
"ColumnNumber": 22,
191-
"LineNumber": 37
191+
"LineNumber": 43
192192
},
193193
"Path": [
194194
"Outputs",
@@ -199,7 +199,7 @@
199199
],
200200
"Start": {
201201
"ColumnNumber": 20,
202-
"LineNumber": 37
202+
"LineNumber": 43
203203
}
204204
},
205205
"Message": "Prefer using Fn::Sub over Fn::Join with an empty delimiter",
@@ -213,12 +213,12 @@
213213
},
214214
{
215215
"Filename": "test/fixtures/templates/integration/getatt-types.yaml",
216-
"Id": "3b709659-f299-68e5-3bac-f9835c487de3",
216+
"Id": "f968510f-4410-ab60-e14d-76661faf7d3e",
217217
"Level": "Error",
218218
"Location": {
219219
"End": {
220220
"ColumnNumber": 10,
221-
"LineNumber": 41
221+
"LineNumber": 47
222222
},
223223
"Path": [
224224
"Outputs",
@@ -228,7 +228,7 @@
228228
],
229229
"Start": {
230230
"ColumnNumber": 5,
231-
"LineNumber": 41
231+
"LineNumber": 47
232232
}
233233
},
234234
"Message": "{'Fn::GetAtt': ['CapacityReservation', 'EphemeralStorage']} is not of type 'string'",

test/fixtures/templates/integration/getatt-types.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ Resources:
1616
Properties:
1717
Type: String
1818
Value: !GetAtt CapacityReservation.InstanceCount # #/Value: expected type: String, found: Integer
19+
DocDBCluster:
20+
DeletionPolicy: Delete
21+
UpdateReplacePolicy: Delete
22+
Type: AWS::DocDB::DBCluster
23+
Properties:
24+
BackupRetentionPeriod: 1
1925
Outputs:
2026
Value:
2127
Value: 1 # OK
@@ -41,3 +47,5 @@ Outputs:
4147
Value: !GetAtt CapacityReservation.EphemeralStorage # Template format error: Every Value member must be a string.
4248
Length:
4349
Value: {Fn::Length: [1, 2, 3]} # OK
50+
DocDBClusterPort:
51+
Value: !GetAtt DocDBCluster.Port # OK

test/unit/rules/conftest.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,16 @@ def functions():
6262

6363

6464
@pytest.fixture
65-
def context(cfn, path, functions):
65+
def strict_types(strict_types=True):
66+
return strict_types
67+
68+
69+
@pytest.fixture
70+
def context(cfn, path, functions, strict_types):
6671
return create_context_for_template(cfn).evolve(
6772
path=path,
6873
functions=functions,
74+
strict_types=strict_types,
6975
)
7076

7177

test/unit/rules/functions/test_getatt.py

+16-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def rule():
2222
"Resources": {
2323
"MyBucket": {"Type": "AWS::S3::Bucket"},
2424
"MyCodePipeline": {"Type": "AWS::CodePipeline::Pipeline"},
25+
"DocDBCluster": {"Type": "AWS::DocDB::DBCluster"},
2526
},
2627
"Parameters": {
2728
"MyResourceParameter": {"Type": "String", "Default": "MyBucket"},
@@ -92,7 +93,10 @@ def validate(self, validator, s, instance, schema):
9293
{},
9394
[
9495
ValidationError(
95-
"'Foo' is not one of ['MyBucket', 'MyCodePipeline']",
96+
(
97+
"'Foo' is not one of ['MyBucket', "
98+
"'MyCodePipeline', 'DocDBCluster']"
99+
),
96100
path=deque(["Fn::GetAtt", 0]),
97101
schema_path=deque(["enum"]),
98102
validator="fn_getatt",
@@ -152,6 +156,14 @@ def validate(self, validator, s, instance, schema):
152156
{},
153157
[],
154158
),
159+
(
160+
"Valid GetAtt with exception type",
161+
{"Fn::GetAtt": "DocDBCluster.Port"},
162+
{"type": ["string"]},
163+
_template,
164+
{},
165+
[],
166+
),
155167
# (
156168
# "Invalid GetAtt with integer to string",
157169
# {"Fn::GetAtt": "MyCodePipeline.Version"},
@@ -224,7 +236,8 @@ def validate(self, validator, s, instance, schema):
224236
[
225237
ValidationError(
226238
(
227-
"'Arn' is not one of ['MyBucket', 'MyCodePipeline'] when "
239+
"'Arn' is not one of ['MyBucket', "
240+
"'MyCodePipeline', 'DocDBCluster'] when "
228241
"{'Ref': 'MyAttributeParameter'} is resolved"
229242
),
230243
path=deque(["Fn::GetAtt", 0]),
@@ -248,9 +261,7 @@ def validate(self, validator, s, instance, schema):
248261
],
249262
indirect=["template"],
250263
)
251-
def test_validate(
252-
name, instance, schema, template, child_rules, expected, validator, rule
253-
):
264+
def test_validate(name, instance, schema, child_rules, expected, validator, rule):
254265
rule.child_rules = child_rules
255266
errs = list(rule.fn_getatt(validator, schema, instance, {}))
256267

test/unit/rules/outputs/test_value.py

+3-27
Original file line numberDiff line numberDiff line change
@@ -101,41 +101,17 @@ def validator(cfn, context):
101101
{
102102
"Value": 1.0,
103103
},
104-
[
105-
ValidationError(
106-
"1.0 is not of type 'string'",
107-
validator="type",
108-
schema_path=deque(["type"]),
109-
path=deque(["Value"]),
110-
rule=Value(),
111-
)
112-
],
104+
[],
113105
),
114106
(
115107
{
116108
"Value": 1,
117109
},
118-
[
119-
ValidationError(
120-
"1 is not of type 'string'",
121-
validator="type",
122-
schema_path=deque(["type"]),
123-
path=deque(["Value"]),
124-
rule=Value(),
125-
)
126-
],
110+
[],
127111
),
128112
(
129113
{"Value": True},
130-
[
131-
ValidationError(
132-
"True is not of type 'string'",
133-
validator="type",
134-
schema_path=deque(["type"]),
135-
path=deque(["Value"]),
136-
rule=Value(),
137-
)
138-
],
114+
[],
139115
),
140116
(
141117
{"Value": [{}]},

0 commit comments

Comments
 (0)