cloud-radar 0.14.0a7__py3-none-any.whl → 0.14.0a9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cloud_radar/cf/unit/_template.py +12 -34
- cloud_radar/cf/unit/functions.py +1 -103
- cloud_radar/cf/unit/test__template.py +10 -12
- {cloud_radar-0.14.0a7.dist-info → cloud_radar-0.14.0a9.dist-info}/METADATA +2 -2
- {cloud_radar-0.14.0a7.dist-info → cloud_radar-0.14.0a9.dist-info}/RECORD +7 -7
- {cloud_radar-0.14.0a7.dist-info → cloud_radar-0.14.0a9.dist-info}/LICENSE.txt +0 -0
- {cloud_radar-0.14.0a7.dist-info → cloud_radar-0.14.0a9.dist-info}/WHEEL +0 -0
cloud_radar/cf/unit/_template.py
CHANGED
@@ -81,6 +81,7 @@ class Template:
|
|
81
81
|
self.transforms: Optional[Union[str, List[str]]] = self.template.get(
|
82
82
|
"Transform", None
|
83
83
|
)
|
84
|
+
self.allowed_functions: functions.Dispatch = self.load_allowed_functions()
|
84
85
|
|
85
86
|
# All loaded, validate against any template level hooks
|
86
87
|
# that have been configured
|
@@ -207,7 +208,7 @@ class Template:
|
|
207
208
|
# If we get this far then we do not support this type of configuration file
|
208
209
|
raise ValueError("Parameter file is not in a supported format")
|
209
210
|
|
210
|
-
def load_allowed_functions(self)
|
211
|
+
def load_allowed_functions(self):
|
211
212
|
"""Loads the allowed functions for this template.
|
212
213
|
|
213
214
|
Raises:
|
@@ -231,8 +232,9 @@ class Template:
|
|
231
232
|
return {**functions.ALL_FUNCTIONS, **transform_functions}
|
232
233
|
|
233
234
|
if isinstance(self.transforms, list):
|
234
|
-
|
235
|
+
|
235
236
|
transform_functions = {}
|
237
|
+
|
236
238
|
for transform in self.transforms:
|
237
239
|
if transform not in functions.TRANSFORMS:
|
238
240
|
raise ValueError(f"Transform {transform} not supported")
|
@@ -249,13 +251,8 @@ class Template:
|
|
249
251
|
def render_all_sections(self, template: Dict[str, Any]) -> Dict[str, Any]:
|
250
252
|
"""Solves all conditionals, references and pseudo variables for all sections"""
|
251
253
|
|
252
|
-
allowed_functions = self.load_allowed_functions()
|
253
|
-
|
254
254
|
if "Conditions" in template:
|
255
|
-
template["Conditions"] = self.resolve_values(
|
256
|
-
template["Conditions"],
|
257
|
-
allowed_functions,
|
258
|
-
)
|
255
|
+
template["Conditions"] = self.resolve_values(template["Conditions"])
|
259
256
|
|
260
257
|
template_sections = ["Resources", "Outputs"]
|
261
258
|
|
@@ -278,10 +275,7 @@ class Template:
|
|
278
275
|
if not condition_value:
|
279
276
|
continue
|
280
277
|
|
281
|
-
template[section][r_name] = self.resolve_values(
|
282
|
-
r_value,
|
283
|
-
allowed_functions,
|
284
|
-
)
|
278
|
+
template[section][r_name] = self.resolve_values(r_value)
|
285
279
|
|
286
280
|
return template
|
287
281
|
|
@@ -346,7 +340,6 @@ class Template:
|
|
346
340
|
def resolve_values( # noqa: max-complexity: 13
|
347
341
|
self,
|
348
342
|
data: Any,
|
349
|
-
allowed_func: functions.Dispatch,
|
350
343
|
) -> Any:
|
351
344
|
"""Recurses through a Cloudformation template. Solving all
|
352
345
|
references and variables along the way.
|
@@ -366,10 +359,7 @@ class Template:
|
|
366
359
|
# This takes care of keys that not intrinsic functions,
|
367
360
|
# except for the condition func
|
368
361
|
if "Fn::" not in key and key != "Condition":
|
369
|
-
data[key] = self.resolve_values(
|
370
|
-
value,
|
371
|
-
allowed_func,
|
372
|
-
)
|
362
|
+
data[key] = self.resolve_values(value)
|
373
363
|
continue
|
374
364
|
|
375
365
|
# Takes care of the tricky 'Condition' key
|
@@ -387,21 +377,15 @@ class Template:
|
|
387
377
|
return functions.condition(self, value)
|
388
378
|
|
389
379
|
# Normal key like in an IAM role
|
390
|
-
data[key] = self.resolve_values(
|
391
|
-
value,
|
392
|
-
allowed_func,
|
393
|
-
)
|
380
|
+
data[key] = self.resolve_values(value)
|
394
381
|
continue
|
395
382
|
|
396
|
-
if key not in
|
383
|
+
if key not in self.allowed_functions:
|
397
384
|
raise ValueError(f"{key} with value ({value}) not allowed here")
|
398
385
|
|
399
|
-
value = self.resolve_values(
|
400
|
-
value,
|
401
|
-
functions.ALLOWED_FUNCTIONS[key],
|
402
|
-
)
|
386
|
+
value = self.resolve_values(value)
|
403
387
|
|
404
|
-
funct_result =
|
388
|
+
funct_result = self.allowed_functions[key](self, value)
|
405
389
|
|
406
390
|
if isinstance(funct_result, str):
|
407
391
|
# If the result is a string then process any
|
@@ -412,13 +396,7 @@ class Template:
|
|
412
396
|
|
413
397
|
return data
|
414
398
|
elif isinstance(data, list):
|
415
|
-
return [
|
416
|
-
self.resolve_values(
|
417
|
-
item,
|
418
|
-
allowed_func,
|
419
|
-
)
|
420
|
-
for item in data
|
421
|
-
]
|
399
|
+
return [self.resolve_values(item) for item in data]
|
422
400
|
elif isinstance(data, str):
|
423
401
|
return self.resolve_dynamic_references(data)
|
424
402
|
else:
|
cloud_radar/cf/unit/functions.py
CHANGED
@@ -283,9 +283,7 @@ def condition(template: "Template", name: Any) -> bool:
|
|
283
283
|
condition_value = template.template["Conditions"][name]
|
284
284
|
|
285
285
|
if not isinstance(condition_value, bool):
|
286
|
-
condition_value: bool = template.resolve_values( # type: ignore
|
287
|
-
condition_value, allowed_func=ALLOWED_NESTED_CONDITIONS
|
288
|
-
)
|
286
|
+
condition_value: bool = template.resolve_values(condition_value) # type: ignore
|
289
287
|
|
290
288
|
return condition_value
|
291
289
|
|
@@ -942,106 +940,6 @@ ALL_FUNCTIONS: Dispatch = {
|
|
942
940
|
**INTRINSICS,
|
943
941
|
}
|
944
942
|
|
945
|
-
ALLOWED_NESTED_CONDITIONS: Dispatch = {
|
946
|
-
"Fn::FindInMap": find_in_map,
|
947
|
-
"Ref": ref,
|
948
|
-
**CONDITIONS,
|
949
|
-
}
|
950
|
-
|
951
|
-
# Cloudformation only allows certain functions to be called from inside
|
952
|
-
# other functions. The keys are the function name and the values are the
|
953
|
-
# functions that are allowed to be nested inside it.
|
954
|
-
ALLOWED_FUNCTIONS: Dict[str, Dispatch] = {
|
955
|
-
"Fn::And": ALLOWED_NESTED_CONDITIONS,
|
956
|
-
"Fn::Equals": {**ALLOWED_NESTED_CONDITIONS, "Fn::Join": join, "Fn::Select": select},
|
957
|
-
"Fn::If": {
|
958
|
-
"Fn::Base64": base64,
|
959
|
-
"Fn::FindInMap": find_in_map,
|
960
|
-
"Fn::GetAtt": get_att,
|
961
|
-
"Fn::GetAZs": get_azs,
|
962
|
-
"Fn::If": if_,
|
963
|
-
"Fn::Join": join,
|
964
|
-
"Fn::Select": select,
|
965
|
-
"Fn::Sub": sub,
|
966
|
-
"Ref": ref,
|
967
|
-
"Fn::ImportValue": import_value,
|
968
|
-
},
|
969
|
-
"Fn::Not": ALLOWED_NESTED_CONDITIONS,
|
970
|
-
"Fn::Or": ALLOWED_NESTED_CONDITIONS,
|
971
|
-
"Condition": {}, # Only allows strings
|
972
|
-
"Fn::Base64": ALL_FUNCTIONS,
|
973
|
-
"Fn::Cidr": {
|
974
|
-
"Fn::Select": select,
|
975
|
-
"Ref": ref,
|
976
|
-
},
|
977
|
-
"Fn::FindInMap": {
|
978
|
-
"Fn::FindInMap": find_in_map,
|
979
|
-
"Ref": ref,
|
980
|
-
},
|
981
|
-
"Fn::GetAtt": {}, # This one is complicated =/
|
982
|
-
"Fn::GetAZs": {
|
983
|
-
"Ref": ref,
|
984
|
-
},
|
985
|
-
"Fn::ImportValue": {
|
986
|
-
"Fn::Base64": base64,
|
987
|
-
"Fn::FindInMap": find_in_map,
|
988
|
-
"Fn::If": if_,
|
989
|
-
"Fn::Join": join,
|
990
|
-
"Fn::Select": select,
|
991
|
-
"Fn::Split": split,
|
992
|
-
"Fn::Sub": sub,
|
993
|
-
"Ref": ref,
|
994
|
-
}, # Import value can't depend on resources (not implemented)
|
995
|
-
"Fn::Join": {
|
996
|
-
"Fn::Base64": base64,
|
997
|
-
"Fn::FindInMap": find_in_map,
|
998
|
-
"Fn::GetAtt": get_att,
|
999
|
-
"Fn::GetAZs": get_azs,
|
1000
|
-
"Fn::If": if_,
|
1001
|
-
"Fn::ImportValue": import_value,
|
1002
|
-
"Fn::Join": join,
|
1003
|
-
"Fn::Split": split,
|
1004
|
-
"Fn::Select": select,
|
1005
|
-
"Fn::Sub": sub,
|
1006
|
-
"Ref": ref,
|
1007
|
-
},
|
1008
|
-
"Fn::Select": {
|
1009
|
-
"Fn::FindInMap": find_in_map,
|
1010
|
-
"Fn::GetAtt": get_att,
|
1011
|
-
"Fn::GetAZs": get_azs,
|
1012
|
-
"Fn::If": if_,
|
1013
|
-
"Fn::Split": split,
|
1014
|
-
"Ref": ref,
|
1015
|
-
},
|
1016
|
-
"Fn::Split": {
|
1017
|
-
"Fn::Base64": base64,
|
1018
|
-
"Fn::FindInMap": find_in_map,
|
1019
|
-
"Fn::GetAtt": get_att,
|
1020
|
-
"Fn::GetAZs": get_azs,
|
1021
|
-
"Fn::If": if_,
|
1022
|
-
"Fn::ImportValue": import_value,
|
1023
|
-
"Fn::Join": join,
|
1024
|
-
"Fn::Split": split,
|
1025
|
-
"Fn::Select": select,
|
1026
|
-
"Fn::Sub": sub,
|
1027
|
-
"Ref": ref,
|
1028
|
-
},
|
1029
|
-
"Fn::Sub": {
|
1030
|
-
"Fn::Base64": base64,
|
1031
|
-
"Fn::FindInMap": find_in_map,
|
1032
|
-
"Fn::GetAtt": get_att,
|
1033
|
-
"Fn::GetAZs": get_azs,
|
1034
|
-
"Fn::If": if_,
|
1035
|
-
"Fn::ImportValue": import_value,
|
1036
|
-
"Fn::Join": join,
|
1037
|
-
"Fn::Select": select,
|
1038
|
-
"Ref": ref,
|
1039
|
-
"Fn::Sub": sub,
|
1040
|
-
},
|
1041
|
-
"Fn::Transform": {}, # Transform isn't fully implemented
|
1042
|
-
"Ref": {}, # String only.
|
1043
|
-
}
|
1044
|
-
|
1045
943
|
# Extra functions that are allowed if the template is using a transform.
|
1046
944
|
TRANSFORMS: Dict[str, Dispatch] = {
|
1047
945
|
"AWS::CodeDeployBlueGreen": {},
|
@@ -7,40 +7,38 @@ from cloud_radar.cf.unit._template import Template
|
|
7
7
|
|
8
8
|
def test_load_allowed_functions_no_transforms():
|
9
9
|
template = Template({})
|
10
|
-
|
11
|
-
assert
|
10
|
+
template.load_allowed_functions()
|
11
|
+
assert template.allowed_functions == functions.ALL_FUNCTIONS
|
12
12
|
|
13
13
|
|
14
14
|
def test_load_allowed_functions_single_transform():
|
15
15
|
template = Template({"Transform": "AWS::Serverless-2016-10-31"})
|
16
|
-
|
16
|
+
template.load_allowed_functions()
|
17
17
|
expected = {
|
18
18
|
**functions.ALL_FUNCTIONS,
|
19
19
|
**functions.TRANSFORMS["AWS::Serverless-2016-10-31"],
|
20
20
|
}
|
21
|
-
assert
|
21
|
+
assert template.allowed_functions == expected
|
22
22
|
|
23
23
|
|
24
24
|
def test_load_allowed_functions_multiple_transforms():
|
25
25
|
template = Template({"Transform": ["AWS::Serverless-2016-10-31", "AWS::Include"]})
|
26
|
-
|
26
|
+
template.load_allowed_functions()
|
27
27
|
expected = {
|
28
28
|
**functions.ALL_FUNCTIONS,
|
29
29
|
**functions.TRANSFORMS["AWS::Serverless-2016-10-31"],
|
30
30
|
**functions.TRANSFORMS["AWS::Include"],
|
31
31
|
}
|
32
|
-
assert
|
32
|
+
assert template.allowed_functions == expected
|
33
33
|
|
34
34
|
|
35
35
|
def test_load_allowed_functions_invalid_transform():
|
36
|
-
|
36
|
+
|
37
37
|
with pytest.raises(ValueError):
|
38
|
-
|
38
|
+
Template({"Transform": "InvalidTransform"})
|
39
39
|
|
40
40
|
|
41
41
|
def test_load_allowed_functions_invalid_transforms():
|
42
|
-
|
43
|
-
{"Transform": ["AWS::Serverless-2016-10-31", "InvalidTransform"]}
|
44
|
-
)
|
42
|
+
|
45
43
|
with pytest.raises(ValueError):
|
46
|
-
|
44
|
+
Template({"Transform": ["AWS::Serverless-2016-10-31", "InvalidTransform"]})
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: cloud-radar
|
3
|
-
Version: 0.14.
|
3
|
+
Version: 0.14.0a9
|
4
4
|
Summary: Run functional tests on cloudformation stacks.
|
5
5
|
License: Apache-2.0
|
6
6
|
Keywords: aws,cloudformation,cloud-radar,testing,taskcat,cloud,radar
|
@@ -388,7 +388,7 @@ Levi - [@shady_cuz](https://twitter.com/shady_cuz)
|
|
388
388
|
* [Taskcat](https://aws-quickstart.github.io/taskcat/)
|
389
389
|
* [Hypermodern Python](https://cjolowicz.github.io/posts/hypermodern-python-01-setup/)
|
390
390
|
* [Best-README-Template](https://github.com/othneildrew/Best-README-Template)
|
391
|
-
* @dhutchison - He was the first contributor to this project and finished the last couple of features to make this project complete. Thank you!
|
391
|
+
* [David Hutchison (@dhutchison)](https://github.com/dhutchison) - He was the first contributor to this project and finished the last couple of features to make this project complete. Thank you!
|
392
392
|
|
393
393
|
<!-- MARKDOWN LINKS & IMAGES -->
|
394
394
|
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
@@ -9,10 +9,10 @@ cloud_radar/cf/unit/_output.py,sha256=rhQQ4aJu06bxAoG7GOXkuOPzAmLCrTA2Ytb8rNXA4V
|
|
9
9
|
cloud_radar/cf/unit/_parameter.py,sha256=AdPIqc2ggSW1VR0USF30zjphX3z1HHbGKQt8n-Kzhfo,3199
|
10
10
|
cloud_radar/cf/unit/_resource.py,sha256=dWaR-5s6ea5mIu6Dhf1hY31Wd4WLHbHsbyxnu2Tz6QI,8512
|
11
11
|
cloud_radar/cf/unit/_stack.py,sha256=_S0L9O7Lw-QAJDKubClp2b6UYtYfyzg272_7WQkUdo8,5785
|
12
|
-
cloud_radar/cf/unit/_template.py,sha256=
|
13
|
-
cloud_radar/cf/unit/functions.py,sha256=
|
14
|
-
cloud_radar/cf/unit/test__template.py,sha256=
|
15
|
-
cloud_radar-0.14.
|
16
|
-
cloud_radar-0.14.
|
17
|
-
cloud_radar-0.14.
|
18
|
-
cloud_radar-0.14.
|
12
|
+
cloud_radar/cf/unit/_template.py,sha256=RSZjqD0FgBYMgyZb_KUkIOaO_mTODLJH9czvhZ_ii3U,32196
|
13
|
+
cloud_radar/cf/unit/functions.py,sha256=NSJh14wJK4dmTibmGqB0aK_kAP1RFW9RjdkZZsD11tc,26332
|
14
|
+
cloud_radar/cf/unit/test__template.py,sha256=nHc9WziIeGDo0d-rsn3HV4X7BsoKmwwHUxcp3qzuZo8,1414
|
15
|
+
cloud_radar-0.14.0a9.dist-info/LICENSE.txt,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
16
|
+
cloud_radar-0.14.0a9.dist-info/METADATA,sha256=C9i9uowVgleXdUvo0i9lrmbwlSZ9SudJPIEYBCChQGA,16784
|
17
|
+
cloud_radar-0.14.0a9.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
18
|
+
cloud_radar-0.14.0a9.dist-info/RECORD,,
|
File without changes
|
File without changes
|