update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / common / python / rift / mano / yang_translator / rwmano / syntax / tosca_template.py
1 # Copyright 2016 RIFT.io Inc
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 from collections import OrderedDict
16
17 import textwrap
18
19 from rift.mano.yang_translator.common.utils import _
20 from rift.mano.yang_translator.rwmano.syntax.tosca_resource \
21 import ToscaResource
22
23 import yaml
24
25
26 class ToscaTemplate(object):
27 '''Container for full RIFT.io TOSCA template.'''
28
29 KEYS = (TOSCA, FILES) = ('tosca', 'files')
30
31 def __init__(self, log):
32 self.log = log
33 self.resources = []
34
35 def output_to_tosca(self):
36 self.log.debug(_('Converting translated output to tosca template.'))
37
38 templates = {}
39 vnfd_templates = {}
40
41 for resource in self.resources:
42 if resource.type == 'vnfd':
43 tmpl = resource.generate_tosca()
44 tmpl = resource.generate_tosca_template(tmpl)
45 self.log.debug(_("TOSCA template generated for {0}:\n{1}").
46 format(resource.name, tmpl))
47 vnfd_templates[resource.name] = tmpl
48
49 for resource in self.resources:
50 # Each NSD should generate separate templates
51 if resource.type == 'nsd':
52 tmpl = resource.generate_tosca_type()
53 tmpl = resource.generate_tosca_template(tmpl)
54 self.log.debug(_("TOSCA template generated for {0}:\n{1}").
55 format(resource.name, tmpl))
56 templates[resource.name] = {self.TOSCA: self.output_to_yaml(tmpl)}
57 files = resource.get_supporting_files()
58 if len(files):
59 templates[resource.name][self.FILES] = files
60
61 for resource in self.resources:
62 if resource.type == 'vnfd':
63 tmpl = vnfd_templates[resource.name]
64 templates[resource.name] = {self.TOSCA: self.output_to_yaml(tmpl)}
65 files = resource.get_supporting_files()
66 if len(files):
67 templates[resource.name][self.FILES] = files
68
69 return templates
70
71 def represent_ordereddict(self, dumper, data):
72 nodes = []
73 for key, value in data.items():
74 node_key = dumper.represent_data(key)
75 node_value = dumper.represent_data(value)
76 nodes.append((node_key, node_value))
77 return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', nodes)
78
79 def ordered_node(self, node):
80 order = [ToscaResource.TYPE, ToscaResource.DERIVED_FROM,
81 ToscaResource.DESC, ToscaResource.MEMBERS,
82 ToscaResource.PROPERTIES, ToscaResource.CAPABILITIES,
83 ToscaResource.REQUIREMENTS,ToscaResource.ARTIFACTS,
84 ToscaResource.INTERFACES]
85 new_node = OrderedDict()
86 self.log.debug("Node to oder: {}".format(node))
87 for ent in order:
88 if ent in node:
89 new_node.update({ent: node.pop(ent)})
90
91 # Check if we missed any entry
92 if len(node):
93 self.log.warn(_("Did not sort these entries: {0}").
94 format(node))
95 new_node.update(node)
96
97 return new_node
98
99 def ordered_nodes(self, nodes):
100 new_nodes = OrderedDict()
101 if isinstance(nodes, dict):
102 for name, node in nodes.items():
103 new_nodes.update({name: self.ordered_node(node)})
104 return new_nodes
105 else:
106 return nodes
107
108 def ordered_nodes_sub_mapping(self, nodes):
109 new_nodes = OrderedDict()
110 if isinstance(nodes, dict):
111 for name, node in nodes.items():
112 new_nodes.update({name: node})
113 return new_nodes
114 else:
115 return nodes
116
117 def output_to_yaml(self, tosca):
118 self.log.debug(_('Converting translated output to yaml format.'))
119 dict_output = OrderedDict()
120 dict_output.update({'tosca_definitions_version':
121 tosca['tosca_definitions_version']})
122 # Description
123 desc_str = ""
124 if ToscaResource.DESC in tosca:
125 # Wrap the text to a new line if the line exceeds 80 characters.
126 wrapped_txt = "\n ". \
127 join(textwrap.wrap(tosca[ToscaResource.DESC], 80))
128 desc_str = ToscaResource.DESC + ": >\n " + \
129 wrapped_txt + "\n\n"
130 dict_output.update({ToscaResource.DESC: tosca[ToscaResource.DESC]})
131
132 if ToscaResource.METADATA in tosca:
133 dict_output.update({ToscaResource.METADATA:
134 tosca[ToscaResource.METADATA]})
135 if ToscaResource.IMPORT in tosca:
136 dict_output.update({ToscaResource.IMPORT:
137 tosca[ToscaResource.IMPORT]})
138
139 # Add all types
140 types_list = [ToscaResource.DATA_TYPES, ToscaResource.CAPABILITY_TYPES,
141 ToscaResource.NODE_TYPES, ToscaResource.ARTIFACT_TYPES,
142 ToscaResource.GROUP_TYPES, ToscaResource.POLICY_TYPES]
143 for typ in types_list:
144 if typ in tosca:
145 dict_output.update({typ: self.ordered_nodes(tosca[typ])})
146
147 # Add topology template
148 topo_list = [ToscaResource.INPUTS, ToscaResource.NODE_TMPL,
149 ToscaResource.GROUPS, ToscaResource.POLICIES,
150 ToscaResource.OUTPUTS]
151 if ToscaResource.TOPOLOGY_TMPL in tosca:
152 tmpl = OrderedDict()
153 for typ in tosca[ToscaResource.TOPOLOGY_TMPL]:
154 if typ != ToscaResource.SUBSTITUTION_MAPPING:
155 tmpl.update({typ:
156 self.ordered_nodes(
157 tosca[ToscaResource.TOPOLOGY_TMPL][typ])})
158 else:
159 tmpl.update({typ:
160 self.ordered_nodes_sub_mapping(
161 tosca[ToscaResource.TOPOLOGY_TMPL][typ])})
162 dict_output.update({ToscaResource.TOPOLOGY_TMPL: tmpl})
163
164 yaml.add_representer(OrderedDict, self.represent_ordereddict)
165 yaml_string = yaml.dump(dict_output, default_flow_style=False)
166 # get rid of the '' from yaml.dump around numbers
167 yaml_string = yaml_string.replace('\'', '')
168 self.log.debug(_("YAML output:\n{0}").format(yaml_string))
169 return yaml_string