Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/customizations/cloudformation/yamlhelper.py
1567 views
1
# Copyright 2012-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
from botocore.compat import json
14
from botocore.compat import OrderedDict
15
16
import yaml
17
from yaml.resolver import ScalarNode, SequenceNode
18
19
20
def intrinsics_multi_constructor(loader, tag_prefix, node):
21
"""
22
YAML constructor to parse CloudFormation intrinsics.
23
This will return a dictionary with key being the intrinsic name
24
"""
25
26
# Get the actual tag name excluding the first exclamation
27
tag = node.tag[1:]
28
29
# Some intrinsic functions doesn't support prefix "Fn::"
30
prefix = "Fn::"
31
if tag in ["Ref", "Condition"]:
32
prefix = ""
33
34
cfntag = prefix + tag
35
36
if tag == "GetAtt" and isinstance(node.value, str):
37
# ShortHand notation for !GetAtt accepts Resource.Attribute format
38
# while the standard notation is to use an array
39
# [Resource, Attribute]. Convert shorthand to standard format
40
value = node.value.split(".", 1)
41
42
elif isinstance(node, ScalarNode):
43
# Value of this node is scalar
44
value = loader.construct_scalar(node)
45
46
elif isinstance(node, SequenceNode):
47
# Value of this node is an array (Ex: [1,2])
48
value = loader.construct_sequence(node)
49
50
else:
51
# Value of this node is an mapping (ex: {foo: bar})
52
value = loader.construct_mapping(node)
53
54
return {cfntag: value}
55
56
57
def _dict_representer(dumper, data):
58
return dumper.represent_dict(data.items())
59
60
61
def yaml_dump(dict_to_dump):
62
"""
63
Dumps the dictionary as a YAML document
64
:param dict_to_dump:
65
:return:
66
"""
67
FlattenAliasDumper.add_representer(OrderedDict, _dict_representer)
68
return yaml.dump(
69
dict_to_dump,
70
default_flow_style=False,
71
Dumper=FlattenAliasDumper,
72
)
73
74
75
def _dict_constructor(loader, node):
76
# Necessary in order to make yaml merge tags work
77
loader.flatten_mapping(node)
78
return OrderedDict(loader.construct_pairs(node))
79
80
81
class SafeLoaderWrapper(yaml.SafeLoader):
82
"""Isolated safe loader to allow for customizations without global changes.
83
"""
84
85
pass
86
87
def yaml_parse(yamlstr):
88
"""Parse a yaml string"""
89
try:
90
# PyYAML doesn't support json as well as it should, so if the input
91
# is actually just json it is better to parse it with the standard
92
# json parser.
93
return json.loads(yamlstr, object_pairs_hook=OrderedDict)
94
except ValueError:
95
loader = SafeLoaderWrapper
96
loader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
97
_dict_constructor)
98
loader.add_multi_constructor("!", intrinsics_multi_constructor)
99
return yaml.load(yamlstr, loader)
100
101
102
class FlattenAliasDumper(yaml.SafeDumper):
103
def ignore_aliases(self, data):
104
return True
105
106