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
6 # http://www.apache.org/licenses/LICENSE-2.0
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
14 # Copyright 2016 RIFT.io Inc
19 from collections
import OrderedDict
23 from rift
.mano
.tosca_translator
.common
.utils
import _
25 from toscaparser
.common
.exception
import ValidationError
26 from toscaparser
.elements
.interfaces
import InterfacesDef
27 from toscaparser
.functions
import GetInput
30 SECTIONS
= (TYPE
, PROPERTIES
, MEDADATA
, DEPENDS_ON
, UPDATE_POLICY
,
32 ('type', 'properties', 'metadata',
33 'depends_on', 'update_policy', 'deletion_policy')
36 class ManoResource(object):
37 '''Base class for TOSCA node type translation to RIFT.io MANO type.'''
49 deletion_policy
=None):
51 self
.nodetemplate
= nodetemplate
55 self
.name
= nodetemplate
.name
59 self
.properties
= properties
or {}
60 self
.metadata
= metadata
61 self
._artifacts
= artifacts
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
74 self
.depends_on
= depends_on
75 self
.depends_on_nodes
= depends_on
78 self
.depends_on_nodes
= []
79 self
.update_policy
= update_policy
80 self
.deletion_policy
= deletion_policy
81 self
.group_dependencies
= {}
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') %
90 # Added the below property menthods to support methods that
91 # works on both toscaparser.NodeType and translator.ManoResource
97 def type(self
, value
):
106 self
._id
= str(uuid
.uuid1())
110 def description(self
):
111 return _("Translated from TOSCA")
115 if self
._vendor
is None:
116 if self
.metadata
and 'vendor' in self
.metadata
:
117 self
._vendor
= self
.metadata
['vendor']
119 self
._vendor
= "RIFT.io"
124 if self
._version
is None:
125 if self
.metadata
and 'version' in self
.metadata
:
126 self
._version
= str(self
.metadata
['version'])
128 self
._version
= '1.0'
133 return self
._artifacts
136 def artifacts(self
, value
):
137 self
._artifacts
= value
140 return "%s(%s)"%(self
.name
, self
.type)
142 def map_tosca_name_to_mano(self
, name
):
143 new_name
= name
.replace("_", "-")
146 def map_keys_to_mano(self
, d
):
147 if isinstance(d
, dict):
149 d
[self
.map_tosca_name_to_mano(key
)] = \
150 self
.map_keys_to_mano(d
.pop(key
))
152 elif isinstance(d
, list):
155 arr
.append(self
.map_keys_to_mano(memb
))
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
)
168 # Check if the required properties are present
169 if not set(required
).issubset(properties
.keys()):
171 if key
not in properties
:
172 err_msg
= _("Property {0} is not defined "
174 format(key
, self
.name
, self
.type_
)
175 self
.log
.error(err_msg
)
176 raise ValidationError(message
=err_msg
)
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}), "
184 format(key
, self
.name
, self
.type_
))
186 def handle_properties(self
):
189 def handle_artifacts(self
):
192 def handle_capabilities(self
):
195 def handle_requirements(self
, nodes
):
198 def handle_interfaces(self
):
201 def update_image_checksum(self
, in_file
):
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").
209 def get_supporting_files(self
, files
, desc_id
=None):
212 def top_of_chain(self
):
213 dependent
= self
.group_dependencies
.get(self
)
214 if dependent
is None:
217 return dependent
.top_of_chain()
219 def get_dict_output(self
):
220 resource_sections
= OrderedDict()
221 resource_sections
[TYPE
] = self
.type
223 resource_sections
[PROPERTIES
] = self
.properties
225 resource_sections
[MEDADATA
] = self
.metadata
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
235 return {self
.name
: resource_sections
}
237 def get_tosca_props(self
):
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
}
243 tosca_props
[prop
.name
] = prop
.value
246 def get_tosca_caps(self
):
248 for cap
in self
.nodetemplate
.get_capabilities_objects():
249 properties
= cap
.get_properties()
251 tosca_caps
[cap
.name
] = {}
252 for name
in properties
:
253 tosca_caps
[cap
.name
][name
] = properties
[name
].value
256 def get_tosca_reqs(self
):
258 for requirement
in self
.nodetemplate
.requirements
:
259 for endpoint
, details
in six
.iteritems(requirement
):
263 if isinstance(details
, dict):
264 target
= details
.get('node')
265 relation
= details
.get('relationship')
268 if (target
and relation
and
269 not isinstance(relation
, six
.string_types
)):
270 interfaces
= relation
.get('interfaces')
271 req
[endpoint
] = {'target': target
}
273 req
[endpoint
] = {'relation': relation
}
275 req
[endpoint
] = {'interfaces': interfaces
}
276 tosca_reqs
.append(req
)
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 \
285 if args
[1] in self
.properties
:
286 return self
.properties
[args
[1]]
288 self
.log
.error(_("{0}, property {} not defined").
289 format(self
.name
, args
[1]))
291 self
.log
.error(_("Get property for {0} of type {1} not supported").
292 format(self
.name
, args
))
294 def get_node_with_name(self
, name
, nodes
):
295 """Get the node instance with specified name"""
297 if node
.name
== name
:
300 def get_nodes_related(self
, target
, type_
, nodes
):
301 """Get list of nodes related to target node"""
304 if (node
.name
== target
.name
or
307 for rel
in node
.nodetemplate
.related_nodes
:
308 if rel
.name
== target
.name
:
309 dep_nodes
.append(node
)
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
))
320 def _get_all_operations(node
):
322 for operation
in node
.interfaces
:
323 operations
[operation
.name
] = operation
325 node_type
= node
.type_definition
326 if (isinstance(node_type
, str) or
327 node_type
.type == "tosca.policies.Placement"):
331 type_operations
= ManoResource
._get
_interface
_operations
_from
_type
(
332 node_type
, node
, 'Standard')
333 type_operations
.update(operations
)
334 operations
= type_operations
336 if node_type
.parent_type
is not None:
337 node_type
= node_type
.parent_type
342 def _get_interface_operations_from_type(node_type
, node
, lifecycle_name
):
344 if (isinstance(node_type
, str) or
345 node_type
.type == "tosca.policies.Placement"):
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
,
359 def get_parent_type(node_type
):
360 if node_type
.parent_type
is not None:
361 return node_type
.parent_type
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'):
372 return ManoResource
.get_base_type(parent_type
)