Revert "Full Juju Charm support"
[osm/SO.git] / common / python / rift / mano / tosca_translator / rwmano / syntax / mano_resource.py
1 #
2 # Licensed under the Apache License, Version 2.0 (the "License"); you may
3 # not use this file except in compliance with the License. You may obtain
4 # a copy of the License at
5 #
6 # http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 # License for the specific language governing permissions and limitations
12 # under the License.
13 #
14 # Copyright 2016 RIFT.io Inc
15
16
17 import uuid
18
19 from collections import OrderedDict
20
21 import six
22
23 from rift.mano.tosca_translator.common.utils import _
24
25 from toscaparser.common.exception import ValidationError
26 from toscaparser.elements.interfaces import InterfacesDef
27 from toscaparser.functions import GetInput
28
29
30 SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY,
31 DELETION_POLICY) = \
32 ('type', 'properties', 'metadata',
33 'depends_on', 'update_policy', 'deletion_policy')
34
35
36 class ManoResource(object):
37 '''Base class for TOSCA node type translation to RIFT.io MANO type.'''
38
39 def __init__(self,
40 log,
41 nodetemplate,
42 name=None,
43 type_=None,
44 properties=None,
45 metadata=None,
46 artifacts=None,
47 depends_on=None,
48 update_policy=None,
49 deletion_policy=None):
50 self.log = log
51 self.nodetemplate = nodetemplate
52 if name:
53 self.name = name
54 else:
55 self.name = nodetemplate.name
56 self.type_ = type_
57 self._id = None
58 self._version = None
59 self.properties = properties or {}
60 self.metadata = metadata
61 self._artifacts = artifacts
62
63 # The difference between depends_on and depends_on_nodes is
64 # that depends_on defines dependency in the context of the
65 # HOT template and it is used during the template output.
66 # Depends_on_nodes defines the direct dependency between the
67 # tosca nodes and is not used during the output of the
68 # HOT template but for internal processing only. When a tosca
69 # node depends on another node it will be always added to
70 # depends_on_nodes but not always to depends_on. For example
71 # if the source of dependency is a server, the dependency will
72 # be added as properties.get_resource and not depends_on
73 if depends_on:
74 self.depends_on = depends_on
75 self.depends_on_nodes = depends_on
76 else:
77 self.depends_on = []
78 self.depends_on_nodes = []
79 self.update_policy = update_policy
80 self.deletion_policy = deletion_policy
81 self.group_dependencies = {}
82 self.operations = {}
83 # if hide_resource is set to true, then this resource will not be
84 # generated in the output yaml.
85 self.hide_resource = False
86 log.debug(_('Translating TOSCA node %(name)s of type %(type)s') %
87 {'name': self.name,
88 'type': self.type_})
89
90 # Added the below property menthods to support methods that
91 # works on both toscaparser.NodeType and translator.ManoResource
92 @property
93 def type(self):
94 return self.type_
95
96 @type.setter
97 def type(self, value):
98 self.type_ = value
99
100 def get_type(self):
101 return self.type_
102
103 @property
104 def id(self):
105 if self._id is None:
106 self._id = str(uuid.uuid1())
107 return self._id
108
109 @property
110 def description(self):
111 return _("Translated from TOSCA")
112
113 @property
114 def vendor(self):
115 if self._vendor is None:
116 if self.metadata and 'vendor' in self.metadata:
117 self._vendor = self.metadata['vendor']
118 else:
119 self._vendor = "RIFT.io"
120 return self._vendor
121
122 @property
123 def version(self):
124 if self._version is None:
125 if self.metadata and 'version' in self.metadata:
126 self._version = str(self.metadata['version'])
127 else:
128 self._version = '1.0'
129 return self._version
130
131 @property
132 def artifacts(self):
133 return self._artifacts
134
135 @artifacts.setter
136 def artifacts(self, value):
137 self._artifacts = value
138
139 def __str__(self):
140 return "%s(%s)"%(self.name, self.type)
141
142 def map_tosca_name_to_mano(self, name):
143 new_name = name.replace("_", "-")
144 return new_name
145
146 def map_keys_to_mano(self, d):
147 if isinstance(d, dict):
148 for key in d.keys():
149 d[self.map_tosca_name_to_mano(key)] = \
150 self.map_keys_to_mano(d.pop(key))
151 return d
152 elif isinstance(d, list):
153 arr = []
154 for memb in d:
155 arr.append(self.map_keys_to_mano(memb))
156 return arr
157 else:
158 return d
159
160 def validate_properties(self, properties, required=None, optional=None):
161 if not isinstance(properties, dict):
162 err_msg = _("Properties for {0}({1}) is not right type"). \
163 format(self.name, self.type_)
164 self.log.error(err_msg)
165 raise ValidationError(message=err_msg)
166
167 if required:
168 # Check if the required properties are present
169 if not set(required).issubset(properties.keys()):
170 for key in required:
171 if key not in properties:
172 err_msg = _("Property {0} is not defined "
173 "for {1}({2})"). \
174 format(key, self.name, self.type_)
175 self.log.error(err_msg)
176 raise ValidationError(message=err_msg)
177
178 # Check for unknown properties
179 for key in properties.keys():
180 if (key not in required or
181 key not in optional):
182 self.log.warn(_("Property {0} not supported for {1}({2}), "
183 "will be ignored.").
184 format(key, self.name, self.type_))
185
186 def handle_properties(self):
187 pass
188
189 def handle_artifacts(self):
190 pass
191
192 def handle_capabilities(self):
193 pass
194
195 def handle_requirements(self, nodes):
196 pass
197
198 def handle_interfaces(self):
199 pass
200
201 def update_image_checksum(self, in_file):
202 pass
203
204 def generate_yang_model(self, nsd, vnfds, use_gi=False):
205 """Generate yang model for the node"""
206 self.log.debug(_("{0}: Not doing anything for YANG model generation").
207 format(self))
208
209 def get_supporting_files(self, files, desc_id=None):
210 pass
211
212 def top_of_chain(self):
213 dependent = self.group_dependencies.get(self)
214 if dependent is None:
215 return self
216 else:
217 return dependent.top_of_chain()
218
219 def get_dict_output(self):
220 resource_sections = OrderedDict()
221 resource_sections[TYPE] = self.type
222 if self.properties:
223 resource_sections[PROPERTIES] = self.properties
224 if self.metadata:
225 resource_sections[MEDADATA] = self.metadata
226 if self.depends_on:
227 resource_sections[DEPENDS_ON] = []
228 for depend in self.depends_on:
229 resource_sections[DEPENDS_ON].append(depend.name)
230 if self.update_policy:
231 resource_sections[UPDATE_POLICY] = self.update_policy
232 if self.deletion_policy:
233 resource_sections[DELETION_POLICY] = self.deletion_policy
234
235 return {self.name: resource_sections}
236
237 def get_tosca_props(self):
238 tosca_props = {}
239 for prop in self.nodetemplate.get_properties_objects():
240 if isinstance(prop.value, GetInput):
241 tosca_props[prop.name] = {'get_param': prop.value.input_name}
242 else:
243 tosca_props[prop.name] = prop.value
244 return tosca_props
245
246 def get_tosca_caps(self):
247 tosca_caps = {}
248 for cap in self.nodetemplate.get_capabilities_objects():
249 properties = cap.get_properties()
250 if len(properties):
251 tosca_caps[cap.name] = {}
252 for name in properties:
253 tosca_caps[cap.name][name] = properties[name].value
254 return tosca_caps
255
256 def get_tosca_reqs(self):
257 tosca_reqs = []
258 for requirement in self.nodetemplate.requirements:
259 for endpoint, details in six.iteritems(requirement):
260 req = {}
261 relation = None
262 interfaces = None
263 if isinstance(details, dict):
264 target = details.get('node')
265 relation = details.get('relationship')
266 else:
267 target = details
268 if (target and relation and
269 not isinstance(relation, six.string_types)):
270 interfaces = relation.get('interfaces')
271 req[endpoint] = {'target': target}
272 if relation:
273 req[endpoint] = {'relation': relation}
274 if interfaces:
275 req[endpoint] = {'interfaces': interfaces}
276 tosca_reqs.append(req)
277 return tosca_reqs
278
279 def get_property(self, args):
280 # TODO(Philip): Should figure out how to get this resolved
281 # by tosca-parser using GetProperty
282 if isinstance(args, list):
283 if len(args) == 2 and \
284 args[0] == 'SELF':
285 if args[1] in self.properties:
286 return self.properties[args[1]]
287 else:
288 self.log.error(_("{0}, property {} not defined").
289 format(self.name, args[1]))
290 return
291 self.log.error(_("Get property for {0} of type {1} not supported").
292 format(self.name, args))
293
294 def get_node_with_name(self, name, nodes):
295 """Get the node instance with specified name"""
296 for node in nodes:
297 if node.name == name:
298 return node
299
300 def get_nodes_related(self, target, type_, nodes):
301 """Get list of nodes related to target node"""
302 dep_nodes = []
303 for node in nodes:
304 if (node.name == target.name or
305 type_ != node.type):
306 continue
307 for rel in node.nodetemplate.related_nodes:
308 if rel.name == target.name:
309 dep_nodes.append(node)
310 break
311 return dep_nodes
312
313 def get_mano_attribute(self, attribute, args):
314 # this is a place holder and should be implemented by the subclass
315 # if translation is needed for the particular attribute
316 raise Exception(_("No translation in TOSCA type {0} for attribute "
317 "{1}").format(self.nodetemplate.type, attribute))
318
319 @staticmethod
320 def _get_all_operations(node):
321 operations = {}
322 for operation in node.interfaces:
323 operations[operation.name] = operation
324
325 node_type = node.type_definition
326 if (isinstance(node_type, str) or
327 node_type.type == "tosca.policies.Placement"):
328 return operations
329
330 while True:
331 type_operations = ManoResource._get_interface_operations_from_type(
332 node_type, node, 'Standard')
333 type_operations.update(operations)
334 operations = type_operations
335
336 if node_type.parent_type is not None:
337 node_type = node_type.parent_type
338 else:
339 return operations
340
341 @staticmethod
342 def _get_interface_operations_from_type(node_type, node, lifecycle_name):
343 operations = {}
344 if (isinstance(node_type, str) or
345 node_type.type == "tosca.policies.Placement"):
346 return operations
347 if node_type.interfaces and lifecycle_name in node_type.interfaces:
348 for name, elems in node_type.interfaces[lifecycle_name].items():
349 # ignore empty operations (only type)
350 # ignore global interface inputs,
351 # concrete inputs are on the operations themselves
352 if name != 'type' and name != 'inputs':
353 operations[name] = InterfacesDef(node_type,
354 lifecycle_name,
355 node, name, elems)
356 return operations
357
358 @staticmethod
359 def get_parent_type(node_type):
360 if node_type.parent_type is not None:
361 return node_type.parent_type
362 else:
363 return None
364
365 @staticmethod
366 def get_base_type(node_type):
367 parent_type = ManoResource.get_parent_type(node_type)
368 if parent_type is not None:
369 if parent_type.type.endswith('.Root'):
370 return node_type
371 else:
372 return ManoResource.get_base_type(parent_type)
373 else:
374 return node_type