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 self
.log
.debug(_("Metadata {0}").format(metadata
))
165 self
.metadata
= metadata
167 def _recursive_handle_properties(self
, resource
):
168 '''Recursively handle the properties of the depends_on_nodes nodes.'''
169 # Use of hashtable (dict) here should be faster?
170 if resource
in self
.processed_resources
:
172 self
.processed_resources
.append(resource
)
173 for depend_on
in resource
.depends_on_nodes
:
174 self
._recursive
_handle
_properties
(depend_on
)
176 if resource
.type == "OS::Nova::ServerGroup":
177 resource
.handle_properties(self
.mano_resources
)
179 resource
.handle_properties()
181 def _get_policy_type(self
, policy
):
182 if isinstance(policy
, dict):
183 for key
, details
in policy
.items():
184 if 'type' in details
:
185 return details
['type']
187 def _translate_nodetemplates(self
):
189 self
.log
.debug(_('Translating the node templates.'))
190 # Copy the TOSCA graph: nodetemplate
191 tpl
= self
.tosca
.tpl
['topology_template']['node_templates']
192 for node
in self
.nodetemplates
:
193 base_type
= ManoResource
.get_base_type(node
.type_definition
)
194 self
.log
.debug(_("Translate node %(name)s of type %(type)s with "
198 'base': base_type
.type})
199 mano_node
= TranslateNodeTemplates
. \
200 TOSCA_TO_MANO_TYPE
[base_type
.type](
203 metadata
=self
.metadata
)
204 # Currently tosca-parser does not add the artifacts
206 if mano_node
.name
in tpl
:
207 tpl_node
= tpl
[mano_node
.name
]
208 self
.log
.debug("Check artifacts for {}".format(tpl_node
))
209 if 'artifacts' in tpl_node
:
210 mano_node
.artifacts
= tpl_node
['artifacts']
211 self
.mano_resources
.append(mano_node
)
212 self
.mano_lookup
[node
] = mano_node
214 # The parser currently do not generate the objects for groups
215 if 'groups' in self
.tosca
.tpl
['topology_template']:
216 tpl
= self
.tosca
.tpl
['topology_template']['groups']
217 self
.log
.debug("Groups: {}".format(tpl
))
218 for group
, details
in tpl
.items():
219 self
.log
.debug(_("Translate group {}: {}").
220 format(group
, details
))
221 group_type
= details
['type']
223 group_node
= TranslateNodeTemplates
. \
224 TOSCA_TO_MANO_TYPE
[group_type
](
228 metadata
=self
.metadata
)
229 self
.mano_groups
.append(group_node
)
231 # The parser currently do not generate the objects for policies
232 if 'policies' in self
.tosca
.tpl
['topology_template']:
233 tpl
= self
.tosca
.tpl
['topology_template']['policies']
234 # for policy in self.policies:
236 self
.log
.debug(_("Translate policy {}").
238 policy_type
= self
._get
_policy
_type
(policy
)
240 policy_node
= TranslateNodeTemplates
. \
241 TOSCA_TO_MANO_TYPE
[policy_type
](
244 metadata
=self
.metadata
)
245 self
.mano_policies
.append(policy_node
)
247 for node
in self
.mano_resources
:
248 self
.log
.debug(_("Handle properties for {0} of type {1}").
249 format(node
.name
, node
.type_
))
250 node
.handle_properties()
252 self
.log
.debug(_("Handle capabilites for {0} of type {1}").
253 format(node
.name
, node
.type_
))
254 node
.handle_capabilities()
256 self
.log
.debug(_("Handle aritfacts for {0} of type {1}").
257 format(node
.name
, node
.type_
))
258 node
.handle_artifacts()
260 self
.log
.debug(_("Handle interfaces for {0} of type {1}").
261 format(node
.name
, node
.type_
))
262 node
.handle_interfaces()
264 self
.log
.debug(_("Update image checksum for {0} of type {1}").
265 format(node
.name
, node
.type_
))
266 node
.update_image_checksum(self
.tosca
.path
)
268 for node
in self
.mano_resources
:
269 # Handle vnf and vdu dependencies first
270 if node
.type == "vnfd":
272 self
.log
.debug(_("Handle requirements for {0} of "
274 format(node
.name
, node
.type_
))
275 node
.handle_requirements(self
.mano_resources
)
276 except Exception as e
:
277 self
.log
.error(_("Exception for {0} in requirements {1}").
278 format(node
.name
, node
.type_
))
279 self
.log
.exception(e
)
281 for node
in self
.mano_resources
:
282 # Now handle other dependencies
283 if node
.type != "vnfd":
285 self
.log
.debug(_("Handle requirements for {0} of type {1}").
286 format(node
.name
, node
.type_
))
287 node
.handle_requirements(self
.mano_resources
)
288 except Exception as e
:
289 self
.log
.error(_("Exception for {0} in requirements {1}").
290 format(node
.name
, node
.type_
))
291 self
.log
.exception(e
)
293 return self
.mano_resources
295 def translate_groups(self
):
296 for group
in self
.mano_groups
:
297 group
.handle_properties(self
.mano_resources
)
298 return self
.mano_groups
300 def translate_policies(self
):
301 for policy
in self
.mano_policies
:
302 policy
.handle_properties(self
.mano_resources
, self
.mano_groups
)
303 return self
.mano_policies
305 def find_mano_resource(self
, name
):
306 for resource
in self
.mano_resources
:
307 if resource
.name
== name
:
310 def _find_tosca_node(self
, tosca_name
):
311 for node
in self
.nodetemplates
:
312 if node
.name
== tosca_name
:
315 def _find_mano_resource_for_tosca(self
, tosca_name
,
316 current_mano_resource
=None):
317 if tosca_name
== 'SELF':
318 return current_mano_resource
319 if tosca_name
== 'HOST' and current_mano_resource
is not None:
320 for req
in current_mano_resource
.nodetemplate
.requirements
:
322 return self
._find
_mano
_resource
_for
_tosca
(req
['host'])
324 for node
in self
.nodetemplates
:
325 if node
.name
== tosca_name
:
326 return self
.mano_lookup
[node
]