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
170 def _recursive_handle_properties(self
, resource
):
171 '''Recursively handle the properties of the depends_on_nodes nodes.'''
172 # Use of hashtable (dict) here should be faster?
173 if resource
in self
.processed_resources
:
175 self
.processed_resources
.append(resource
)
176 for depend_on
in resource
.depends_on_nodes
:
177 self
._recursive
_handle
_properties
(depend_on
)
179 if resource
.type == "OS::Nova::ServerGroup":
180 resource
.handle_properties(self
.mano_resources
)
182 resource
.handle_properties()
184 def _get_policy_type(self
, policy
):
185 if isinstance(policy
, dict):
186 for key
, details
in policy
.items():
187 if 'type' in details
:
188 return details
['type']
190 def _translate_nodetemplates(self
):
192 self
.log
.debug(_('Translating the node templates.'))
193 # Copy the TOSCA graph: nodetemplate
194 all_node_templates
= []
195 node_to_artifact_map
= {}
196 vnf_type_to_vnf_node
= {}
197 vnf_type_to_vdus_map
= {}
198 vnf_type_substitution_mapping
= {}
199 vnf_type_to_capability_substitution_mapping
= {}
200 tpl
= self
.tosca
.tpl
['topology_template']['node_templates']
201 associated_vnfd_flag
= False
203 for node
in self
.nodetemplates
:
204 all_node_templates
.append(node
)
205 if node
.parent_type
.type == 'tosca.nodes.nfv.riftio.VNF1':
206 vnf_type_to_vnf_node
[node
.type] = node
.name
208 if 'artifacts' in tpl
[node_key
]:
209 node_to_artifact_map
[node_key
] = tpl
[node_key
]['artifacts']
210 for template
in self
.tosca
.nested_tosca_templates_with_topology
:
211 tpl_node
= template
.tpl
['node_templates']
212 vnf_type
= template
.substitution_mappings
.node_type
214 vnf_type_to_vdus_map
[vnf_type
] = []
215 vnf_type_substitution_mapping
[vnf_type
] = []
216 vnf_type_to_capability_substitution_mapping
[vnf_type
] = []
217 vnf_type_to_capability_substitution_mapping
[vnf_type
] = []
220 for node
in template
.nodetemplates
:
221 all_node_templates
.append(node
)
222 for node_key
in tpl_node
:
223 if 'artifacts' in tpl_node
[node_key
]:
224 node_to_artifact_map
[node_key
] = tpl_node
[node_key
]['artifacts']
225 for node
in template
.nodetemplates
:
226 if 'VDU' in node
.type:
227 vnf_type_to_vdus_map
[vnf_type
].append(node
.name
)
228 for policy
in template
.policies
:
229 policies
.append(policy
.name
)
230 for req
in template
.substitution_mappings
.requirements
:
231 vnf_type_substitution_mapping
[template
.substitution_mappings
.node_type
].append(req
)
232 if template
.substitution_mappings
.capabilities
:
233 for capability
in template
.substitution_mappings
.capabilities
:
234 sub_list
= template
.substitution_mappings
.capabilities
[capability
]
235 if len(sub_list
) > 0:
236 vnf_type_to_capability_substitution_mapping
[vnf_type
].append({capability
: sub_list
[0]})
238 for node
in all_node_templates
:
239 base_type
= ManoResource
.get_base_type(node
.type_definition
)
240 self
.log
.debug(_("Translate node %(name)s of type %(type)s with "
244 'base': base_type
.type})
245 mano_node
= TranslateNodeTemplates
. \
246 TOSCA_TO_MANO_TYPE
[base_type
.type](
249 metadata
=self
.metadata
)
250 # Currently tosca-parser does not add the artifacts
252 if mano_node
.type == 'vnfd':
253 associated_vnfd_flag
= True
254 if mano_node
.name
in node_to_artifact_map
:
255 mano_node
.artifacts
= node_to_artifact_map
[mano_node
.name
]
256 self
.mano_resources
.append(mano_node
)
257 self
.mano_lookup
[node
] = mano_node
259 if not associated_vnfd_flag
:
260 dummy_file
= "{0}{1}".format(os
.getenv('RIFT_INSTALL'), "/usr/rift/mano/common/dummy_vnf_node.yaml")
261 tosca_vnf
= ToscaTemplate(dummy_file
, {}, True)
262 vnf_type
= self
.tosca
.topology_template
.substitution_mappings
.node_type
263 vnf_type_to_vdus_map
[vnf_type
] = []
265 for node
in tosca_vnf
.nodetemplates
:
266 all_node_templates
.append(node
)
267 base_type
= ManoResource
.get_base_type(node
.type_definition
)
268 vnf_type_to_vnf_node
[vnf_type
] = node
.name
269 mano_node
= TranslateNodeTemplates
. \
270 TOSCA_TO_MANO_TYPE
[base_type
.type](
273 metadata
=self
.metadata
)
274 mano_node
.vnf_type
= vnf_type
275 self
.mano_resources
.append(mano_node
)
276 print("Adding a new node")
278 for node
in self
.tosca
.nodetemplates
:
279 if 'VDU' in node
.type:
280 vnf_type_to_vdus_map
[vnf_type
].append(node
.name
)
282 # The parser currently do not generate the objects for groups
283 for group
in self
.tosca
.topology_template
.groups
:
284 group_type
= group
.type
286 group_node
= TranslateNodeTemplates
. \
287 TOSCA_TO_MANO_TYPE
[group_type
](
290 metadata
=self
.metadata
)
291 self
.mano_groups
.append(group_node
)
293 # The parser currently do not generate the objects for policies
295 for policy
in self
.tosca
.topology_template
.policies
:
296 policy_type
= policy
.type
298 policy_node
= TranslateNodeTemplates
. \
299 TOSCA_TO_MANO_TYPE
[policy_type
](
302 metadata
=self
.metadata
)
303 self
.mano_policies
.append(policy_node
)
304 for template
in self
.tosca
.nested_tosca_templates_with_topology
:
305 vnf_type
= template
.substitution_mappings
.node_type
306 if vnf_type
in vnf_type_to_vnf_node
:
307 vnf_node
= vnf_type_to_vnf_node
[vnf_type
]
309 for policy
in template
.policies
:
310 policy_type
= policy
.type
312 policy_node
= TranslateNodeTemplates
. \
313 TOSCA_TO_MANO_TYPE
[policy_type
](
316 metadata
=self
.metadata
,
318 self
.mano_policies
.append(policy_node
)
320 for node
in self
.mano_resources
:
321 self
.log
.debug(_("Handle properties for {0} of type {1}").
322 format(node
.name
, node
.type_
))
323 node
.handle_properties()
325 self
.log
.debug(_("Handle capabilites for {0} of type {1}").
326 format(node
.name
, node
.type_
))
327 node
.handle_capabilities()
329 self
.log
.debug(_("Handle aritfacts for {0} of type {1}").
330 format(node
.name
, node
.type_
))
331 node
.handle_artifacts()
333 self
.log
.debug(_("Handle interfaces for {0} of type {1}").
334 format(node
.name
, node
.type_
))
335 node
.handle_interfaces()
337 self
.log
.debug(_("Update image checksum for {0} of type {1}").
338 format(node
.name
, node
.type_
))
339 node
.update_image_checksum(self
.tosca
.path
)
341 for node
in self
.mano_resources
:
342 # Handle vnf and vdu dependencies first
343 if node
.type == "vnfd":
345 self
.log
.debug(_("Handle requirements for {0} of "
347 format(node
.name
, node
.type_
))
348 node
.handle_requirements(self
.mano_resources
, self
.mano_policies
, vnf_type_to_vdus_map
)
350 except Exception as e
:
351 self
.log
.error(_("Exception for {0} in requirements {1}").
352 format(node
.name
, node
.type_
))
353 self
.log
.exception(e
)
355 for node
in self
.mano_resources
:
356 # Now handle other dependencies
357 if node
.type != "vnfd":
359 self
.log
.debug(_("Handle requirements for {0} of type {1}").
360 format(node
.name
, node
.type_
))
361 node
.handle_requirements(self
.mano_resources
)
362 except Exception as e
:
363 self
.log
.error(_("Exception for {0} in requirements {1}").
364 format(node
.name
, node
.type_
))
365 self
.log
.exception(e
)
367 for node
in self
.mano_resources
:
368 if node
.type == "vld":
369 node
.handle_vld_properties(self
.mano_resources
, vnf_type_substitution_mapping
)
370 elif node
.type == 'forwarding_path':
371 node
.handle_forwarding_path_dependencies(self
.mano_resources
, vnf_type_to_capability_substitution_mapping
)
373 return self
.mano_resources
375 def translate_groups(self
):
376 for group
in self
.mano_groups
:
377 group
.handle_properties(self
.mano_resources
, self
.mano_groups
)
378 return self
.mano_groups
380 def translate_policies(self
):
381 for policy
in self
.mano_policies
:
382 policy
.handle_properties(self
.mano_resources
, self
.mano_groups
)
383 return self
.mano_policies
385 def find_mano_resource(self
, name
):
386 for resource
in self
.mano_resources
:
387 if resource
.name
== name
:
390 def _find_tosca_node(self
, tosca_name
):
391 for node
in self
.nodetemplates
:
392 if node
.name
== tosca_name
:
395 def _find_mano_resource_for_tosca(self
, tosca_name
,
396 current_mano_resource
=None):
397 if tosca_name
== 'SELF':
398 return current_mano_resource
399 if tosca_name
== 'HOST' and current_mano_resource
is not None:
400 for req
in current_mano_resource
.nodetemplate
.requirements
:
402 return self
._find
_mano
_resource
_for
_tosca
(req
['host'])
404 for node
in self
.nodetemplates
:
405 if node
.name
== tosca_name
:
406 return self
.mano_lookup
[node
]