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
.yang_translator
.common
.exception
import YangClassAttributeError
21 from rift
.mano
.yang_translator
.common
.exception
import YangClassImportError
22 from rift
.mano
.yang_translator
.common
.exception
import YangModImportError
23 from rift
.mano
.yang_translator
.common
.utils
import _
24 from rift
.mano
.yang_translator
.conf
.config
import ConfigProvider \
26 from rift
.mano
.yang_translator
.rwmano
.syntax
.tosca_resource \
30 class TranslateDescriptors(object):
31 '''Translate YANG NodeTemplates to RIFT.io MANO Resources.'''
33 YANG_DESC
= (NSD
, VNFD
) = ('nsd', 'vnfd')
35 ###########################
36 # Module utility Functions
37 # for dynamic class loading
38 ###########################
40 YANG_TO_TOSCA_TYPE
= None
42 def _load_classes(log
, locations
, classes
):
43 '''Dynamically load all the classes from the given locations.'''
45 for cls_path
in locations
:
46 # Use the absolute path of the class path
47 abs_path
= os
.path
.dirname(os
.path
.abspath(__file__
))
48 abs_path
= abs_path
.replace('rift/mano/yang_translator/rwmano',
50 log
.debug(_("Loading classes from %s") % abs_path
)
52 # Grab all the yang type module files in the given path
53 mod_files
= [f
for f
in os
.listdir(abs_path
) if (
55 not f
.startswith('__init__') and
56 f
.startswith('yang_'))]
58 # For each module, pick out the target translation class
60 f_name
, ext
= f
.rsplit('.', 1)
61 mod_name
= cls_path
+ '/' + f_name
62 mod_name
= mod_name
.replace('/', '.')
64 mod
= importlib
.import_module(mod_name
)
65 target_name
= getattr(mod
, 'TARGET_CLASS_NAME')
66 clazz
= getattr(mod
, target_name
)
69 raise YangModImportError(mod_name
=mod_name
)
70 except AttributeError:
72 raise YangClassImportError(name
=target_name
,
75 # TARGET_CLASS_NAME is not defined in module.
76 # Re-raise the exception
79 def _generate_type_map(log
):
80 '''Generate YANG translation types map.
82 Load user defined classes from location path specified in conf file.
83 Base classes are located within the yang directory.
86 # Base types directory
87 BASE_PATH
= 'rift/mano/yang_translator/rwmano/yang'
89 # Custom types directory defined in conf file
90 custom_path
= translatorConfig
.get_value('DEFAULT',
91 'custom_types_location')
93 # First need to load the parent module, for example 'contrib.mano',
94 # for all of the dynamically loaded classes.
96 TranslateDescriptors
._load
_classes
(log
,
97 (BASE_PATH
, custom_path
),
100 types_map
= {clazz
.yangtype
: clazz
for clazz
in classes
}
101 log
.debug(_("Type maps loaded: {}").format(types_map
.keys()))
102 except AttributeError as e
:
103 raise YangClassAttributeError(message
=e
.message
)
107 def __init__(self
, log
, yangs
, tosca_template
, vnfd_files
=None):
110 self
.tosca_template
= tosca_template
111 self
.vnfd_files
= vnfd_files
112 # list of all TOSCA resources generated
113 self
.tosca_resources
= []
115 log
.debug(_('Mapping between YANG nodetemplate and TOSCA resource.'))
118 if TranslateDescriptors
.YANG_TO_TOSCA_TYPE
is None:
119 TranslateDescriptors
.YANG_TO_TOSCA_TYPE
= \
120 TranslateDescriptors
._generate
_type
_map
(self
.log
)
121 return self
._translate
_yang
()
123 def translate_metadata(self
):
124 """Translate and store the metadata in instance"""
128 'version': 'version',
131 # Initialize to default values
132 metadata
['name'] = 'yang_to_tosca'
133 metadata
['vendor'] = 'RIFT.io'
134 metadata
['version'] = '1.0'
135 if 'nsd' in self
.yangs
:
136 yang_meta
= self
.yang
['nsd'][0]
137 elif 'vnfd' in self
.yangs
:
138 yang_meta
= self
.yang
['vnfd'][0]
139 for key
in FIELDS_MAP
:
140 if key
in yang_meta
.keys():
141 metadata
[key
] = str(yang_meta
[FIELDS_MAP
[key
]])
142 self
.log
.debug(_("Metadata {0}").format(metadata
))
143 self
.metadata
= metadata
145 def _translate_yang(self
):
146 self
.log
.debug(_('Translating the descriptors.'))
147 if self
.NSD
in self
.yangs
:
148 for nsd
in self
.yangs
[self
.NSD
]:
149 self
.log
.debug(_("Translate descriptor of type nsd: {}").
151 node_name
= nsd
.pop(ToscaResource
.NAME
).replace(' ','_')
152 node_name
= node_name
if node_name
.endswith('nsd') else ''.join([node_name
, '_nsd'])
153 tosca_node
= TranslateDescriptors
. \
154 YANG_TO_TOSCA_TYPE
[self
.NSD
](
160 self
.tosca_resources
.append(tosca_node
)
163 if self
.VNFD
in self
.yangs
:
164 for vnfd
in self
.yangs
[self
.VNFD
]:
165 if vnfd
['name'] not in vnfd_name_list
:
166 self
.log
.debug(_("Translate descriptor of type vnfd: {}").
168 vnfd_name_list
.append(vnfd
['name'])
169 tosca_node
= TranslateDescriptors
. \
170 YANG_TO_TOSCA_TYPE
[self
.VNFD
](
172 vnfd
.pop(ToscaResource
.NAME
),
175 self
.tosca_resources
.append(tosca_node
)
177 # First translate VNFDs
178 for node
in self
.tosca_resources
:
179 if node
.type == self
.VNFD
:
180 self
.log
.debug(_("Handle yang for {0} of type {1}").
181 format(node
.name
, node
.type_
))
185 for node
in self
.tosca_resources
:
186 if node
.type == self
.NSD
:
187 self
.log
.debug(_("Handle yang for {0} of type {1}").
188 format(node
.name
, node
.type_
))
189 node
.handle_yang(self
.tosca_resources
)
191 return self
.tosca_resources
193 def find_tosca_resource(self
, name
):
194 for resource
in self
.tosca_resources
:
195 if resource
.name
== name
:
198 def _find_yang_node(self
, yang_name
):
199 for node
in self
.nodetemplates
:
200 if node
.name
== yang_name
: