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
20 from rift
.mano
.tosca_translator
.common
.utils
import _
21 from rift
.mano
.tosca_translator
.common
.exception
import ToscaClassAttributeError
22 from rift
.mano
.tosca_translator
.common
.exception
import ToscaClassImportError
23 from rift
.mano
.tosca_translator
.common
.exception
import ToscaModImportError
24 from rift
.mano
.tosca_translator
.conf
.config
import ConfigProvider
as translatorConfig
25 from rift
.mano
.tosca_translator
.rwmano
.syntax
.mano_resource
import ManoResource
26 from toscaparser
.tosca_template
import ToscaTemplate
29 class TranslateNodeTemplates(object):
30 '''Translate TOSCA NodeTemplates to RIFT.io MANO Resources.'''
36 TOSCA_TO_MANO_REQUIRES
= {'container': 'server',
38 'dependency': 'depends_on',
39 'connects': 'depends_on'}
41 TOSCA_TO_MANO_PROPERTIES
= {'properties': 'input'}
43 TOSCA_TO_MANO_TYPE
= None
45 ###########################
46 # Module utility Functions
47 # for dynamic class loading
48 ###########################
50 def _load_classes(log
, locations
, classes
):
51 '''Dynamically load all the classes from the given locations.'''
53 for cls_path
in locations
:
54 # Use the absolute path of the class path
55 abs_path
= os
.path
.dirname(os
.path
.abspath(__file__
))
56 abs_path
= abs_path
.replace('rift/mano/tosca_translator/rwmano', cls_path
)
57 log
.debug(_("Loading classes from %s") % abs_path
)
59 # Grab all the tosca type module files in the given path
60 mod_files
= [f
for f
in os
.listdir(abs_path
) if (
62 not f
.startswith('__init__') and
63 f
.startswith('tosca_'))]
65 # For each module, pick out the target translation class
67 # NOTE: For some reason the existing code does not use
68 # the map to instantiate
69 # ToscaBlockStorageAttachment. Don't add it to the map
70 # here until the dependent code is fixed to use the
72 if f
== 'tosca_block_storage_attachment.py':
75 # mod_name = cls_path + '/' + f.rstrip('.py')
76 # Above have an issue if the mod name ends with p or y
77 f_name
, ext
= f
.rsplit('.', 1)
78 mod_name
= cls_path
+ '/' + f_name
79 mod_name
= mod_name
.replace('/', '.')
81 mod
= importlib
.import_module(mod_name
)
82 target_name
= getattr(mod
, 'TARGET_CLASS_NAME')
83 clazz
= getattr(mod
, target_name
)
86 raise ToscaModImportError(mod_name
=mod_name
)
87 except AttributeError:
89 raise ToscaClassImportError(name
=target_name
,
92 # TARGET_CLASS_NAME is not defined in module.
93 # Re-raise the exception
96 def _generate_type_map(log
):
97 '''Generate TOSCA translation types map.
99 Load user defined classes from location path specified in conf file.
100 Base classes are located within the tosca directory.
103 # Base types directory
104 BASE_PATH
= 'rift/mano/tosca_translator/rwmano/tosca'
106 # Custom types directory defined in conf file
107 custom_path
= translatorConfig
.get_value('DEFAULT',
108 'custom_types_location')
110 # First need to load the parent module, for example 'contrib.mano',
111 # for all of the dynamically loaded classes.
113 TranslateNodeTemplates
._load
_classes
(log
,
114 (BASE_PATH
, custom_path
),
117 types_map
= {clazz
.toscatype
: clazz
for clazz
in classes
}
118 log
.debug(_("Type maps loaded: {}").format(types_map
.keys()))
119 except AttributeError as e
:
120 raise ToscaClassAttributeError(message
=e
.message
)
124 def __init__(self
, log
, tosca
, mano_template
):
127 self
.nodetemplates
= self
.tosca
.nodetemplates
128 self
.mano_template
= mano_template
129 # list of all MANO resources generated
130 self
.mano_resources
= []
131 self
.mano_policies
= []
132 self
.mano_groups
= []
133 # mapping between TOSCA nodetemplate and MANO resource
134 log
.debug(_('Mapping between TOSCA nodetemplate and MANO resource.'))
135 self
.mano_lookup
= {}
136 self
.policies
= self
.tosca
.topology_template
.policies
137 self
.groups
= self
.tosca
.topology_template
.groups
141 if TranslateNodeTemplates
.TOSCA_TO_MANO_TYPE
is None:
142 TranslateNodeTemplates
.TOSCA_TO_MANO_TYPE
= \
143 TranslateNodeTemplates
._generate
_type
_map
(self
.log
)
145 self
.translate_metadata()
146 return self
._translate
_nodetemplates
()
148 def translate_metadata(self
):
149 """Translate and store the metadata in instance"""
153 'version': 'version',
156 # Initialize to default values
157 metadata
['name'] = 'tosca_to_mano'
158 metadata
['vendor'] = 'RIFT.io'
159 metadata
['version'] = '1.0'
160 if 'metadata' in self
.tosca
.tpl
:
161 tosca_meta
= self
.tosca
.tpl
['metadata']
162 for key
in FIELDS_MAP
:
163 if key
in tosca_meta
.keys():
164 metadata
[FIELDS_MAP
[key
]] = str(tosca_meta
[key
])
165 if 'logo' in tosca_meta
:
166 metadata
['logo'] = os
.path
.basename(tosca_meta
['logo'])
167 self
.log
.debug(_("Metadata {0}").format(metadata
))
168 self
.metadata
= metadata
171 def _recursive_handle_properties(self
, resource
):
172 '''Recursively handle the properties of the depends_on_nodes nodes.'''
173 # Use of hashtable (dict) here should be faster?
174 if resource
in self
.processed_resources
:
176 self
.processed_resources
.append(resource
)
177 for depend_on
in resource
.depends_on_nodes
:
178 self
._recursive
_handle
_properties
(depend_on
)
180 if resource
.type == "OS::Nova::ServerGroup":
181 resource
.handle_properties(self
.mano_resources
)
183 resource
.handle_properties()
185 def _get_policy_type(self
, policy
):
186 if isinstance(policy
, dict):
187 for key
, details
in policy
.items():
188 if 'type' in details
:
189 return details
['type']
191 def _translate_nodetemplates(self
):
193 self
.log
.debug(_('Translating the node templates.'))
194 # Copy the TOSCA graph: nodetemplate
195 all_node_templates
= []
196 node_to_artifact_map
= {}
197 vnf_type_to_vnf_node
= {}
198 vnf_type_to_vdus_map
= {}
199 vnf_type_substitution_mapping
= {}
200 vnf_type_to_capability_substitution_mapping
= {}
201 tpl
= self
.tosca
.tpl
['topology_template']['node_templates']
202 associated_vnfd_flag
= False
204 for node
in self
.nodetemplates
:
205 all_node_templates
.append(node
)
206 if node
.parent_type
.type == 'tosca.nodes.nfv.riftio.VNF1':
207 vnf_type_to_vnf_node
[node
.type] = node
.name
209 if 'artifacts' in tpl
[node_key
]:
210 node_to_artifact_map
[node_key
] = tpl
[node_key
]['artifacts']
211 for template
in self
.tosca
.nested_tosca_templates_with_topology
:
212 tpl_node
= template
.tpl
['node_templates']
213 vnf_type
= template
.substitution_mappings
.node_type
215 vnf_type_to_vdus_map
[vnf_type
] = []
216 vnf_type_substitution_mapping
[vnf_type
] = []
217 vnf_type_to_capability_substitution_mapping
[vnf_type
] = []
218 vnf_type_to_capability_substitution_mapping
[vnf_type
] = []
221 for node
in template
.nodetemplates
:
222 all_node_templates
.append(node
)
223 for node_key
in tpl_node
:
224 if 'artifacts' in tpl_node
[node_key
]:
225 node_to_artifact_map
[node_key
] = tpl_node
[node_key
]['artifacts']
226 for node
in template
.nodetemplates
:
227 if 'VDU' in node
.type:
228 vnf_type_to_vdus_map
[vnf_type
].append(node
.name
)
229 for policy
in template
.policies
:
230 policies
.append(policy
.name
)
231 if template
.substitution_mappings
.requirements
:
232 for req
in template
.substitution_mappings
.requirements
:
233 vnf_type_substitution_mapping
[template
.substitution_mappings
.node_type
].append(req
)
234 if template
.substitution_mappings
.capabilities
:
235 for capability
in template
.substitution_mappings
.capabilities
:
236 sub_list
= template
.substitution_mappings
.capabilities
[capability
]
237 if len(sub_list
) > 0:
238 vnf_type_to_capability_substitution_mapping
[vnf_type
].append({capability
: sub_list
[0]})
240 for node
in all_node_templates
:
241 base_type
= ManoResource
.get_base_type(node
.type_definition
)
242 self
.log
.debug(_("Translate node %(name)s of type %(type)s with "
246 'base': base_type
.type})
247 mano_node
= TranslateNodeTemplates
. \
248 TOSCA_TO_MANO_TYPE
[base_type
.type](
251 metadata
=self
.metadata
)
252 # Currently tosca-parser does not add the artifacts
254 if mano_node
.type == 'vnfd':
255 associated_vnfd_flag
= True
256 if mano_node
.name
in node_to_artifact_map
:
257 mano_node
.artifacts
= node_to_artifact_map
[mano_node
.name
]
258 self
.mano_resources
.append(mano_node
)
259 self
.mano_lookup
[node
] = mano_node
261 if not associated_vnfd_flag
:
262 dummy_file
= "{0}{1}".format(os
.getenv('RIFT_INSTALL'), "/usr/rift/mano/common/dummy_vnf_node.yaml")
263 tosca_vnf
= ToscaTemplate(dummy_file
, {}, True)
264 vnf_type
= self
.tosca
.topology_template
.substitution_mappings
.node_type
265 vnf_type_to_vdus_map
[vnf_type
] = []
267 for node
in tosca_vnf
.nodetemplates
:
268 all_node_templates
.append(node
)
269 base_type
= ManoResource
.get_base_type(node
.type_definition
)
270 vnf_type_to_vnf_node
[vnf_type
] = node
.name
271 mano_node
= TranslateNodeTemplates
. \
272 TOSCA_TO_MANO_TYPE
[base_type
.type](
275 metadata
=self
.metadata
)
276 mano_node
.vnf_type
= vnf_type
277 self
.mano_resources
.append(mano_node
)
279 for node
in self
.tosca
.nodetemplates
:
280 if 'VDU' in node
.type:
281 vnf_type_to_vdus_map
[vnf_type
].append(node
.name
)
283 # The parser currently do not generate the objects for groups
284 for group
in self
.tosca
.topology_template
.groups
:
285 group_type
= group
.type
287 group_node
= TranslateNodeTemplates
. \
288 TOSCA_TO_MANO_TYPE
[group_type
](
291 metadata
=self
.metadata
)
292 self
.mano_groups
.append(group_node
)
294 # The parser currently do not generate the objects for policies
296 for policy
in self
.tosca
.topology_template
.policies
:
297 policy_type
= policy
.type
299 policy_node
= TranslateNodeTemplates
. \
300 TOSCA_TO_MANO_TYPE
[policy_type
](
303 metadata
=self
.metadata
)
304 self
.mano_policies
.append(policy_node
)
305 for template
in self
.tosca
.nested_tosca_templates_with_topology
:
306 vnf_type
= template
.substitution_mappings
.node_type
307 if vnf_type
in vnf_type_to_vnf_node
:
308 vnf_node
= vnf_type_to_vnf_node
[vnf_type
]
310 for policy
in template
.policies
:
311 policy_type
= policy
.type
313 policy_node
= TranslateNodeTemplates
. \
314 TOSCA_TO_MANO_TYPE
[policy_type
](
317 metadata
=self
.metadata
,
319 self
.mano_policies
.append(policy_node
)
322 for node
in self
.mano_resources
:
323 self
.log
.debug(_("Handle properties for {0} of type {1}").
324 format(node
.name
, node
.type_
))
325 node
.handle_properties()
327 self
.log
.debug(_("Handle capabilites for {0} of type {1}").
328 format(node
.name
, node
.type_
))
329 node
.handle_capabilities()
331 self
.log
.debug(_("Handle aritfacts for {0} of type {1}").
332 format(node
.name
, node
.type_
))
333 node
.handle_artifacts()
335 self
.log
.debug(_("Handle interfaces for {0} of type {1}").
336 format(node
.name
, node
.type_
))
337 node
.handle_interfaces()
339 self
.log
.debug(_("Update image checksum for {0} of type {1}").
340 format(node
.name
, node
.type_
))
341 node
.update_image_checksum(self
.tosca
.path
)
343 for node
in list(self
.mano_resources
):
344 if node
.type == "vnfd":
345 vnfd_resources
.append(node
)
346 self
.mano_resources
.remove(node
)
348 vnfd_resources
.sort(key
=lambda x
: x
.member_vnf_id
, reverse
=True)
349 vnf_type_duplicate_map
= {}
350 for node
in reversed(vnfd_resources
):
351 if node
.vnf_type
in vnf_type_duplicate_map
:
352 for policy
in self
.mano_policies
:
353 if hasattr(policy
, '_vnf_name') and policy
._vnf
_name
== node
.name
:
354 policy
._vnf
_name
= vnf_type_duplicate_map
[node
.vnf_type
]
356 vnf_type_duplicate_map
[node
.vnf_type
] = node
.name
358 self
.mano_resources
.extend(vnfd_resources
)
359 for node
in self
.mano_resources
:
360 # Handle vnf and vdu dependencies first
361 if node
.type == "vnfd":
363 self
.log
.debug(_("Handle requirements for {0} of "
365 format(node
.name
, node
.type_
))
366 node
.handle_requirements(self
.mano_resources
, self
.mano_policies
, vnf_type_to_vdus_map
)
368 except Exception as e
:
369 self
.log
.error(_("Exception for {0} in requirements {1}").
370 format(node
.name
, node
.type_
))
371 self
.log
.exception(e
)
373 for node
in self
.mano_resources
:
374 # Now handle other dependencies
375 if node
.type != "vnfd":
377 self
.log
.debug(_("Handle requirements for {0} of type {1}").
378 format(node
.name
, node
.type_
))
379 node
.handle_requirements(self
.mano_resources
)
380 except Exception as e
:
381 self
.log
.error(_("Exception for {0} in requirements {1}").
382 format(node
.name
, node
.type_
))
383 self
.log
.exception(e
)
385 for node
in self
.mano_resources
:
386 if node
.type == "vld":
387 node
.handle_vld_properties(self
.mano_resources
, vnf_type_substitution_mapping
)
388 elif node
.type == 'forwarding_path':
389 node
.handle_forwarding_path_dependencies(self
.mano_resources
, vnf_type_to_capability_substitution_mapping
)
391 return self
.mano_resources
393 def translate_groups(self
):
394 for group
in self
.mano_groups
:
395 group
.handle_properties(self
.mano_resources
, self
.mano_groups
)
396 return self
.mano_groups
398 def translate_policies(self
):
399 for policy
in self
.mano_policies
:
400 policy
.handle_properties(self
.mano_resources
, self
.mano_groups
)
401 return self
.mano_policies
403 def find_mano_resource(self
, name
):
404 for resource
in self
.mano_resources
:
405 if resource
.name
== name
:
408 def _find_tosca_node(self
, tosca_name
):
409 for node
in self
.nodetemplates
:
410 if node
.name
== tosca_name
:
413 def _find_mano_resource_for_tosca(self
, tosca_name
,
414 current_mano_resource
=None):
415 if tosca_name
== 'SELF':
416 return current_mano_resource
417 if tosca_name
== 'HOST' and current_mano_resource
is not None:
418 for req
in current_mano_resource
.nodetemplate
.requirements
:
420 return self
._find
_mano
_resource
_for
_tosca
(req
['host'])
422 for node
in self
.nodetemplates
:
423 if node
.name
== tosca_name
:
424 return self
.mano_lookup
[node
]