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
28 class TranslateNodeTemplates(object):
29 '''Translate TOSCA NodeTemplates to RIFT.io MANO Resources.'''
35 TOSCA_TO_MANO_REQUIRES
= {'container': 'server',
37 'dependency': 'depends_on',
38 'connects': 'depends_on'}
40 TOSCA_TO_MANO_PROPERTIES
= {'properties': 'input'}
42 TOSCA_TO_MANO_TYPE
= None
44 ###########################
45 # Module utility Functions
46 # for dynamic class loading
47 ###########################
49 def _load_classes(log
, locations
, classes
):
50 '''Dynamically load all the classes from the given locations.'''
52 for cls_path
in locations
:
53 # Use the absolute path of the class path
54 abs_path
= os
.path
.dirname(os
.path
.abspath(__file__
))
55 abs_path
= abs_path
.replace('rift/mano/tosca_translator/rwmano', cls_path
)
56 log
.debug(_("Loading classes from %s") % abs_path
)
58 # Grab all the tosca type module files in the given path
59 mod_files
= [f
for f
in os
.listdir(abs_path
) if (
61 not f
.startswith('__init__') and
62 f
.startswith('tosca_'))]
64 # For each module, pick out the target translation class
66 # NOTE: For some reason the existing code does not use
67 # the map to instantiate
68 # ToscaBlockStorageAttachment. Don't add it to the map
69 # here until the dependent code is fixed to use the
71 if f
== 'tosca_block_storage_attachment.py':
74 # mod_name = cls_path + '/' + f.rstrip('.py')
75 # Above have an issue if the mod name ends with p or y
76 f_name
, ext
= f
.rsplit('.', 1)
77 mod_name
= cls_path
+ '/' + f_name
78 mod_name
= mod_name
.replace('/', '.')
80 mod
= importlib
.import_module(mod_name
)
81 target_name
= getattr(mod
, 'TARGET_CLASS_NAME')
82 clazz
= getattr(mod
, target_name
)
85 raise ToscaModImportError(mod_name
=mod_name
)
86 except AttributeError:
88 raise ToscaClassImportError(name
=target_name
,
91 # TARGET_CLASS_NAME is not defined in module.
92 # Re-raise the exception
95 def _generate_type_map(log
):
96 '''Generate TOSCA translation types map.
98 Load user defined classes from location path specified in conf file.
99 Base classes are located within the tosca directory.
102 # Base types directory
103 BASE_PATH
= 'rift/mano/tosca_translator/rwmano/tosca'
105 # Custom types directory defined in conf file
106 custom_path
= translatorConfig
.get_value('DEFAULT',
107 'custom_types_location')
109 # First need to load the parent module, for example 'contrib.mano',
110 # for all of the dynamically loaded classes.
112 TranslateNodeTemplates
._load
_classes
(log
,
113 (BASE_PATH
, custom_path
),
116 types_map
= {clazz
.toscatype
: clazz
for clazz
in classes
}
117 log
.debug(_("Type maps loaded: {}").format(types_map
.keys()))
118 except AttributeError as e
:
119 raise ToscaClassAttributeError(message
=e
.message
)
123 def __init__(self
, log
, tosca
, mano_template
):
126 self
.nodetemplates
= self
.tosca
.nodetemplates
127 self
.mano_template
= mano_template
128 # list of all MANO resources generated
129 self
.mano_resources
= []
130 self
.mano_policies
= []
131 self
.mano_groups
= []
132 # mapping between TOSCA nodetemplate and MANO resource
133 log
.debug(_('Mapping between TOSCA nodetemplate and MANO resource.'))
134 self
.mano_lookup
= {}
135 self
.policies
= self
.tosca
.topology_template
.policies
136 self
.groups
= self
.tosca
.topology_template
.groups
140 if TranslateNodeTemplates
.TOSCA_TO_MANO_TYPE
is None:
141 TranslateNodeTemplates
.TOSCA_TO_MANO_TYPE
= \
142 TranslateNodeTemplates
._generate
_type
_map
(self
.log
)
144 self
.translate_metadata()
145 return self
._translate
_nodetemplates
()
147 def translate_metadata(self
):
148 """Translate and store the metadata in instance"""
152 'version': 'version',
155 # Initialize to default values
156 metadata
['name'] = 'tosca_to_mano'
157 metadata
['vendor'] = 'RIFT.io'
158 metadata
['version'] = '1.0'
159 if 'metadata' in self
.tosca
.tpl
:
160 tosca_meta
= self
.tosca
.tpl
['metadata']
161 for key
in FIELDS_MAP
:
162 if key
in tosca_meta
.keys():
163 metadata
[FIELDS_MAP
[key
]] = str(tosca_meta
[key
])
164 if 'logo' in tosca_meta
:
165 metadata
['logo'] = os
.path
.basename(tosca_meta
['logo'])
166 self
.log
.debug(_("Metadata {0}").format(metadata
))
167 self
.metadata
= metadata
169 def _recursive_handle_properties(self
, resource
):
170 '''Recursively handle the properties of the depends_on_nodes nodes.'''
171 # Use of hashtable (dict) here should be faster?
172 if resource
in self
.processed_resources
:
174 self
.processed_resources
.append(resource
)
175 for depend_on
in resource
.depends_on_nodes
:
176 self
._recursive
_handle
_properties
(depend_on
)
178 if resource
.type == "OS::Nova::ServerGroup":
179 resource
.handle_properties(self
.mano_resources
)
181 resource
.handle_properties()
183 def _get_policy_type(self
, policy
):
184 if isinstance(policy
, dict):
185 for key
, details
in policy
.items():
186 if 'type' in details
:
187 return details
['type']
189 def _translate_nodetemplates(self
):
191 self
.log
.debug(_('Translating the node templates.'))
192 # Copy the TOSCA graph: nodetemplate
193 all_node_templates
= []
194 node_to_artifact_map
= {}
195 vnf_type_to_vnf_node
= {}
196 vnf_type_to_vdus_map
= {}
197 vnf_type_substitution_mapping
= {}
198 vnf_type_to_capability_substitution_mapping
= {}
199 tpl
= self
.tosca
.tpl
['topology_template']['node_templates']
201 for node
in self
.nodetemplates
:
202 all_node_templates
.append(node
)
203 if node
.parent_type
.type == 'tosca.nodes.nfv.riftio.VNF1':
204 vnf_type_to_vnf_node
[node
.type] = node
.name
206 if 'artifacts' in tpl
[node_key
]:
207 node_to_artifact_map
[node_key
] = tpl
[node_key
]['artifacts']
208 for template
in self
.tosca
.nested_tosca_templates_with_topology
:
209 tpl_node
= template
.tpl
['node_templates']
210 vnf_type
= template
.substitution_mappings
.node_type
212 vnf_type_to_vdus_map
[vnf_type
] = []
213 vnf_type_substitution_mapping
[vnf_type
] = []
214 vnf_type_to_capability_substitution_mapping
[vnf_type
] = []
215 vnf_type_to_capability_substitution_mapping
[vnf_type
] = []
217 for node
in template
.nodetemplates
:
218 all_node_templates
.append(node
)
219 for node_key
in tpl_node
:
220 if 'artifacts' in tpl_node
[node_key
]:
221 node_to_artifact_map
[node_key
] = tpl_node
[node_key
]['artifacts']
222 for node
in template
.nodetemplates
:
223 if 'VDU' in node
.type:
224 vnf_type_to_vdus_map
[vnf_type
].append(node
.name
)
225 for policy
in template
.policies
:
226 policies
.append(policy
.name
)
227 for req
in template
.substitution_mappings
.requirements
:
228 vnf_type_substitution_mapping
[template
.substitution_mappings
.node_type
].append(req
)
229 for capability
in template
.substitution_mappings
.capabilities
:
230 sub_list
= template
.substitution_mappings
.capabilities
[capability
]
231 if len(sub_list
) > 0:
232 vnf_type_to_capability_substitution_mapping
[vnf_type
].append({capability
: sub_list
[0]})
234 for node
in all_node_templates
:
235 base_type
= ManoResource
.get_base_type(node
.type_definition
)
236 self
.log
.debug(_("Translate node %(name)s of type %(type)s with "
240 'base': base_type
.type})
241 mano_node
= TranslateNodeTemplates
. \
242 TOSCA_TO_MANO_TYPE
[base_type
.type](
245 metadata
=self
.metadata
)
246 # Currently tosca-parser does not add the artifacts
248 if mano_node
.name
in node_to_artifact_map
:
249 mano_node
.artifacts
= node_to_artifact_map
[mano_node
.name
]
250 self
.mano_resources
.append(mano_node
)
251 self
.mano_lookup
[node
] = mano_node
253 # The parser currently do not generate the objects for groups
254 for group
in self
.tosca
.topology_template
.groups
:
255 group_type
= group
.type
257 group_node
= TranslateNodeTemplates
. \
258 TOSCA_TO_MANO_TYPE
[group_type
](
261 metadata
=self
.metadata
)
262 self
.mano_groups
.append(group_node
)
264 # The parser currently do not generate the objects for policies
266 for policy
in self
.tosca
.topology_template
.policies
:
267 policy_type
= policy
.type
269 policy_node
= TranslateNodeTemplates
. \
270 TOSCA_TO_MANO_TYPE
[policy_type
](
273 metadata
=self
.metadata
)
274 self
.mano_policies
.append(policy_node
)
275 for template
in self
.tosca
.nested_tosca_templates_with_topology
:
276 vnf_type
= template
.substitution_mappings
.node_type
277 if vnf_type
in vnf_type_to_vnf_node
:
278 vnf_node
= vnf_type_to_vnf_node
[vnf_type
]
280 for policy
in template
.policies
:
281 policy_type
= policy
.type
283 policy_node
= TranslateNodeTemplates
. \
284 TOSCA_TO_MANO_TYPE
[policy_type
](
287 metadata
=self
.metadata
,
289 self
.mano_policies
.append(policy_node
)
291 for node
in self
.mano_resources
:
292 self
.log
.debug(_("Handle properties for {0} of type {1}").
293 format(node
.name
, node
.type_
))
294 node
.handle_properties()
296 self
.log
.debug(_("Handle capabilites for {0} of type {1}").
297 format(node
.name
, node
.type_
))
298 node
.handle_capabilities()
300 self
.log
.debug(_("Handle aritfacts for {0} of type {1}").
301 format(node
.name
, node
.type_
))
302 node
.handle_artifacts()
304 self
.log
.debug(_("Handle interfaces for {0} of type {1}").
305 format(node
.name
, node
.type_
))
306 node
.handle_interfaces()
308 self
.log
.debug(_("Update image checksum for {0} of type {1}").
309 format(node
.name
, node
.type_
))
310 node
.update_image_checksum(self
.tosca
.path
)
312 for node
in self
.mano_resources
:
313 # Handle vnf and vdu dependencies first
314 if node
.type == "vnfd":
316 self
.log
.debug(_("Handle requirements for {0} of "
318 format(node
.name
, node
.type_
))
319 node
.handle_requirements(self
.mano_resources
, self
.mano_policies
, vnf_type_to_vdus_map
)
321 except Exception as e
:
322 self
.log
.error(_("Exception for {0} in requirements {1}").
323 format(node
.name
, node
.type_
))
324 self
.log
.exception(e
)
326 for node
in self
.mano_resources
:
327 # Now handle other dependencies
328 if node
.type != "vnfd":
330 self
.log
.debug(_("Handle requirements for {0} of type {1}").
331 format(node
.name
, node
.type_
))
332 node
.handle_requirements(self
.mano_resources
)
333 except Exception as e
:
334 self
.log
.error(_("Exception for {0} in requirements {1}").
335 format(node
.name
, node
.type_
))
336 self
.log
.exception(e
)
338 for node
in self
.mano_resources
:
339 if node
.type == "vld":
340 node
.handle_vld_properties(self
.mano_resources
, vnf_type_substitution_mapping
)
341 elif node
.type == 'forwarding_path':
342 node
.handle_forwarding_path_dependencies(self
.mano_resources
, vnf_type_to_capability_substitution_mapping
)
344 return self
.mano_resources
346 def translate_groups(self
):
347 for group
in self
.mano_groups
:
348 group
.handle_properties(self
.mano_resources
, self
.mano_groups
)
349 return self
.mano_groups
351 def translate_policies(self
):
352 for policy
in self
.mano_policies
:
353 policy
.handle_properties(self
.mano_resources
, self
.mano_groups
)
354 return self
.mano_policies
356 def find_mano_resource(self
, name
):
357 for resource
in self
.mano_resources
:
358 if resource
.name
== name
:
361 def _find_tosca_node(self
, tosca_name
):
362 for node
in self
.nodetemplates
:
363 if node
.name
== tosca_name
:
366 def _find_mano_resource_for_tosca(self
, tosca_name
,
367 current_mano_resource
=None):
368 if tosca_name
== 'SELF':
369 return current_mano_resource
370 if tosca_name
== 'HOST' and current_mano_resource
is not None:
371 for req
in current_mano_resource
.nodetemplate
.requirements
:
373 return self
._find
_mano
_resource
_for
_tosca
(req
['host'])
375 for node
in self
.nodetemplates
:
376 if node
.name
== tosca_name
:
377 return self
.mano_lookup
[node
]