update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / common / python / rift / mano / tosca_translator / rwmano / tosca / tosca_nfv_vnf.py
1 #
2 # Copyright 2016 RIFT.io Inc
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17
18 from rift.mano.tosca_translator.common.utils import _
19 from rift.mano.tosca_translator.common.utils import convert_keys_to_python
20 from rift.mano.tosca_translator.rwmano.syntax.mano_resource import ManoResource
21 from toscaparser.functions import GetInput
22
23 from toscaparser.common.exception import ValidationError
24
25 try:
26 import gi
27 gi.require_version('RwVnfdYang', '1.0')
28
29 from gi.repository import RwVnfdYang as RwVnfdYang
30 except ImportError:
31 pass
32 except ValueError:
33 pass
34
35
36 # Name used to dynamically load appropriate map class.
37 TARGET_CLASS_NAME = 'ToscaNfvVnf'
38
39
40 class ToscaNfvVnf(ManoResource):
41 '''Translate TOSCA node type tosca.nodes.nfv.vnf.'''
42
43 toscatype = 'tosca.nodes.nfv.VNF'
44
45 REQUIRED_PROPS = ['name', 'short-name', 'id', 'short-name', 'description',
46 'mgmt-interface']
47 OPTIONAL_PROPS = ['version', 'vendor', 'http-endpoint', 'monitoring-param',
48 'connection-point']
49 IGNORE_PROPS = ['port', 'monitoring_param']
50 TOSCA_CAPS = ['mgmt_interface', 'http_endpoint', 'monitoring_param_0',
51 'monitoring_param_1', 'connection_point']
52
53 def __init__(self, log, nodetemplate, metadata=None):
54 super(ToscaNfvVnf, self).__init__(log,
55 nodetemplate,
56 type_="vnfd",
57 metadata=metadata)
58 self._const_vnfd = {}
59 self._vnf_config = {}
60 self._vdus = []
61 self._policies = []
62 self._cps = []
63 self.vnf_type = nodetemplate.type
64 self.member_vnf_id = None
65 self._reqs = {}
66 self.logo = None
67
68 def map_tosca_name_to_mano(self, name):
69 new_name = super().map_tosca_name_to_mano(name)
70 if new_name.startswith('monitoring-param'):
71 new_name = 'monitoring-param'
72 if new_name == 'polling-interval':
73 new_name = 'polling_interval_secs'
74 return new_name
75
76 def handle_properties(self):
77 tosca_props = self.get_tosca_props()
78 self.log.debug(_("VNF {0} with tosca properties: {1}").
79 format(self.name, tosca_props))
80
81 def get_vnf_config(config):
82 vnf_config = {}
83 for key, value in config.items():
84 new_key = self.map_tosca_name_to_mano(key)
85 if isinstance(value, dict):
86 sub_config = {}
87 for subkey, subvalue in value.items():
88 sub_config[self.map_tosca_name_to_mano(subkey)] = \
89 subvalue
90 vnf_config[new_key] = sub_config
91 else:
92 vnf_config[new_key] = value
93
94 if vnf_config['config-type'] != 'script':
95 err_msg = _("{}, Only script config supported "
96 "for now: {}"). \
97 format(self, vnf_config['config-type'])
98 self.log.error(err_msg)
99 raise ValidationError(message=err_msg)
100
101 # Replace config-details with actual name (config-type)
102 if ('config-type' in vnf_config and
103 'config-details' in vnf_config):
104 vnf_config[vnf_config['config-type']] = \
105 vnf_config.pop('config-details')
106 vnf_config.pop('config-type')
107
108 # Update config-delay and confgig-priortiy to correct struct
109 vnf_config['config-attributes'] = {}
110 if 'config-delay' in vnf_config:
111 vnf_config['config-attributes']['config-delay'] = \
112 vnf_config.pop('config-delay')
113 else:
114 vnf_config['config-attributes']['config-delay'] = 0
115 if 'config-priority' in vnf_config:
116 vnf_config['config-attributes']['config-priority'] = \
117 vnf_config.pop('config-priority')
118 return vnf_config
119
120 vnf_props = {}
121 for key, value in tosca_props.items():
122 if key == 'id':
123 self._const_vnfd['member-vnf-index'] = int(value)
124 self._const_vnfd['vnfd-id-ref'] = self.id
125 self.member_vnf_id = int(value)
126 elif key == 'vnf_configuration':
127 self._vnf_config = get_vnf_config(value)
128 else:
129 vnf_props[key] = value
130
131 if 'name' not in vnf_props:
132 vnf_props['name'] = self.name
133
134 if 'short-name' not in vnf_props:
135 vnf_props['short-name'] = self.name
136
137 if 'id' not in vnf_props:
138 vnf_props['id'] = self.id
139
140 if 'vendor' not in vnf_props:
141 vnf_props['vendor'] = self.vendor
142
143 if 'description' not in vnf_props:
144 vnf_props['description'] = self.description
145
146 if 'start_by_default' in vnf_props:
147 self._const_vnfd['start-by-default'] = \
148 vnf_props.pop('start_by_default')
149 if 'logo' in self.metadata:
150 vnf_props['logo'] = self.metadata['logo']
151 self.logo = self.metadata['logo']
152
153
154 self.log.debug(_("VNF {0} with constituent vnf: {1}").
155 format(self.name, self._const_vnfd))
156 self.log.debug(_("VNF {0} with properties: {1}").
157 format(self.name, vnf_props))
158 self.properties = vnf_props
159
160 def handle_capabilities(self):
161 tosca_caps = self.get_tosca_caps()
162 self.log.debug(_("VDU {0} tosca capabilites: {1}").
163 format(self.name, tosca_caps))
164
165 def get_props(props):
166 properties = {}
167 for key in props.keys():
168 value = props[key]
169 if isinstance(value, dict):
170 if 'get_property' in value:
171 val = self.get_property(value['get_property'])
172 value = val
173 properties[self.map_tosca_name_to_mano(key)] = value
174 return properties
175
176 for key, value in tosca_caps.items():
177 if key in ToscaNfvVnf.TOSCA_CAPS:
178 new_key = self.map_tosca_name_to_mano(key)
179 props = get_props(value)
180 if 'id' in props:
181 props['id'] = str(props['id'])
182 if 'protocol' in props:
183 props.pop('protocol')
184
185 # There is only one instance of mgmt interface, but others
186 # are a list
187 if key == 'mgmt_interface':
188 self.properties[new_key] = props
189 elif key == 'http_endpoint':
190 if new_key not in self.properties:
191 self.properties[new_key] = []
192 self.properties[new_key].append(props)
193 else:
194 if new_key not in self.properties:
195 self.properties[new_key] = []
196 self.properties[new_key].append(props)
197
198 self.log.debug(_("VDU {0} properties: {1}").
199 format(self.name, self.properties))
200
201 def handle_requirements(self, nodes, policies, vnf_type_to_vdus_map):
202 tosca_reqs = self.get_tosca_reqs()
203 for req in tosca_reqs:
204 for key, value in req.items():
205 if 'target' in value:
206 self._reqs[key] = value['target']
207
208 for policy in policies:
209 if hasattr(policy, '_vnf_name') and policy._vnf_name == self.name:
210 self._policies.append(policy)
211
212
213 if self.vnf_type in vnf_type_to_vdus_map:
214 for vdu_node_name in vnf_type_to_vdus_map[self.vnf_type]:
215 node = self.get_node_with_name(vdu_node_name, nodes)
216 if node:
217 self._vdus.append(node)
218 node._vnf = self
219 # Add the VDU id to mgmt-intf
220 if 'mgmt-interface' in self.properties:
221 self.properties['mgmt-interface']['vdu-id'] = \
222 node.id
223 if 'vdu' in self.properties['mgmt-interface']:
224 # Older yang
225 self.properties['mgmt-interface'].pop('vdu')
226 else:
227 err_msg = _("VNF {0}, VDU {1} specified not found"). \
228 format(self.name, target)
229 self.log.error(err_msg)
230 raise ValidationError(message=err_msg)
231
232 def generate_yang_model_gi(self, nsd, vnfds):
233 vnfd_cat = RwVnfdYang.YangData_Vnfd_VnfdCatalog()
234 vnfd = vnfd_cat.vnfd.add()
235 props = convert_keys_to_python(self.properties)
236 for key in ToscaNfvVnf.IGNORE_PROPS:
237 if key in props:
238 props.pop(key)
239 try:
240 vnfd.from_dict(props)
241 except Exception as e:
242 err_msg = _("{0} Exception updating vnfd from dict {1}: {2}"). \
243 format(self, props, e)
244 self.log.error(err_msg)
245 raise e
246 vnfds.append(vnfd_cat)
247
248 # Update the VDU properties
249 for vdu in self._vdus:
250 vdu.generate_yang_submodel_gi(vnfd)
251 for policy in self._policies:
252 policy.generate_yang_submodel_gi(vnfd)
253
254 # Update constituent vnfd in nsd
255 try:
256 props = convert_keys_to_python(self._const_vnfd)
257 nsd.constituent_vnfd.add().from_dict(props)
258 except Exception as e:
259 err_msg = _("{0} Exception constituent vnfd from dict {1}: {2}"). \
260 format(self, props, e)
261 self.log.error(err_msg)
262 raise e
263
264 # Update the vnf configuration info in mgmt_interface
265 props = convert_keys_to_python(self._vnf_config)
266 try:
267 vnfd.vnf_configuration.from_dict(props)
268 except Exception as e:
269 err_msg = _("{0} Exception vnfd mgmt intf from dict {1}: {2}"). \
270 format(self, props, e)
271 self.log.error(err_msg)
272 raise e
273
274 def generate_yang_model(self, nsd, vnfds, use_gi=False):
275 """Generate yang model for the node"""
276 self.log.debug(_("Generate YANG model for {0}").
277 format(self))
278
279 for key in ToscaNfvVnf.IGNORE_PROPS:
280 if key in self.properties:
281 self.properties.pop(key)
282
283 if use_gi:
284 return self.generate_yang_model_gi(nsd, vnfds)
285
286 vnfd = {}
287 vnfd.update(self.properties)
288 # Update vnf configuration on mgmt interface
289 vnfd['mgmt-interface']['vnf-configuration'] = self._vnf_config
290
291 # Update the VDU properties
292 vnfd['vdu'] = []
293 for vdu in self._vdus:
294 vnfd['vdu'].append(vdu.generate_yang_submodel())
295
296 vnfds.append(vnfd)
297
298 # Update constituent vnfd in nsd
299 if 'constituent-vnfd' not in nsd:
300 nsd['constituent-vnfd'] = []
301 nsd['constituent-vnfd'].append(self._const_vnfd)
302
303 def generate_nsd_constiuent(self, nsd, vnf_id):
304 self._const_vnfd['vnfd-id-ref'] = vnf_id
305 props = convert_keys_to_python(self._const_vnfd)
306 nsd.constituent_vnfd.add().from_dict(props)
307
308
309 def get_member_vnf_index(self):
310 return self._const_vnfd['member-vnf-index']
311
312 def get_supporting_files(self, files, desc_id=None):
313 files[self.id] = []
314 for vdu in self._vdus:
315 if vdu.image:
316 files[self.id].append({
317 'type': 'image',
318 'name': vdu.image,
319 },)
320 if vdu.cloud_init:
321 files[self.id].append({
322 'type': 'cloud_init',
323 'name': vdu.cloud_init,
324 },)
325 if self.logo is not None:
326 files[desc_id] = []
327 file_location = "../icons/{}".format(self.logo)
328 files[desc_id].append({
329 'type': 'icons',
330 'name': file_location,
331 },)