* YANG to TOSCA VNFFG Support
[osm/SO.git] / common / python / rift / mano / yang_translator / rwmano / yang / yang_nsd.py
1 # Copyright 2016 RIFT.io Inc
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15
16 from copy import deepcopy
17 import os
18
19 from rift.mano.yang_translator.common.exception import ValidationError
20 from rift.mano.yang_translator.common.utils import _
21 from rift.mano.yang_translator.rwmano.syntax.tosca_resource \
22 import ToscaResource
23 from rift.mano.yang_translator.rwmano.yang.yang_vld import YangVld
24 from collections import OrderedDict
25
26 TARGET_CLASS_NAME = 'YangNsd'
27
28
29 class YangNsd(ToscaResource):
30 '''Class for RIFT.io YANG NS descriptor translation to TOSCA type.'''
31
32 yangtype = 'nsd'
33
34 OTHER_FIELDS = (SCALE_GRP, CONF_PRIM,
35 USER_DEF_SCRIPT, SCALE_ACT,
36 TRIGGER, NS_CONF_PRIM_REF,
37 CONST_VNFD, VNFD_MEMBERS,
38 MIN_INST_COUNT, MAX_INST_COUNT,
39 INPUT_PARAM_XPATH, CONFIG_ACTIONS,
40 INITIAL_CFG,) = \
41 ('scaling_group_descriptor', 'service_primitive',
42 'user_defined_script', 'scaling_config_action',
43 'trigger', 'ns_config_primitive_name_ref',
44 'constituent_vnfd', 'vnfd_member',
45 'min_instance_count', 'max_instance_count',
46 'input_parameter_xpath', 'config_actions',
47 'initial_config_primitive',)
48
49 def __init__(self,
50 log,
51 name,
52 type_,
53 yang,
54 vnfd_files):
55 super(YangNsd, self).__init__(log,
56 name,
57 type_,
58 yang)
59 self.props = {}
60 self.inputs = []
61 self.vnfds = {}
62 self.vlds = {}
63 self.conf_prims = []
64 self.scale_grps = []
65 self.initial_cfg = []
66 self.placement_groups = []
67 self.vnf_id_to_vnf_map = {}
68 self.vnfd_files = vnfd_files
69 self.vld_to_vnf_map = {}
70 self.vnf_to_vld_map = {}
71 self._vnf_vld_conn_point_map = {}
72 self.vnffgds = {}
73 self.forwarding_paths = {}
74 self.substitution_mapping_forwarder = []
75 self.vnfd_sfc_map = None
76
77 def handle_yang(self, vnfds):
78 self.log.debug(_("Process NSD desc {0}: {1}").
79 format(self.name, self.yang))
80
81 def process_input_param(param):
82 if self.XPATH in param:
83 val = param.pop(self.XPATH)
84 # Strip namesapce, catalog and nsd part
85 self.inputs.append({
86 self.NAME:
87 self.map_yang_name_to_tosca(
88 val.replace('/nsd:nsd-catalog/nsd:nsd/nsd:', ''))})
89 if len(param):
90 self.log.warn(_("{0}, Did not process the following for "
91 "input param {1}: {2}").
92 format(self, self.inputs, param))
93 self.log.debug(_("{0}, inputs: {1}").format(self, self.inputs[-1]))
94
95 def process_const_vnfd(cvnfd):
96 # Get the matching VNFD
97 vnfd_id = cvnfd.pop(self.VNFD_ID_REF)
98 for vnfd in vnfds:
99 if vnfd.type == self.VNFD and vnfd.id == vnfd_id:
100 self.vnf_id_to_vnf_map[vnfd_id] = vnfd.name
101 self.vnfds[cvnfd.pop(self.MEM_VNF_INDEX)] = vnfd
102 if self.START_BY_DFLT in cvnfd:
103 vnfd.props[self.START_BY_DFLT] = \
104 cvnfd.pop(self.START_BY_DFLT)
105 break
106
107 if len(cvnfd):
108 self.log.warn(_("{0}, Did not process the following for "
109 "constituent vnfd {1}: {2}").
110 format(self, vnfd_id, cvnfd))
111 self.log.debug(_("{0}, VNFD: {1}").format(self, self.vnfds))
112
113 def process_scale_grp(dic):
114 sg = {}
115 self.log.debug(_("{0}, scale group: {1}").format(self, dic))
116 fields = [self.NAME, self.MIN_INST_COUNT, self.MAX_INST_COUNT]
117 for key in fields:
118 if key in dic:
119 sg[key] = dic.pop(key)
120
121 membs = {}
122 for vnfd_memb in dic.pop(self.VNFD_MEMBERS):
123 vnfd_idx = vnfd_memb[self.MEM_VNF_INDEX_REF]
124 if vnfd_idx in self.vnfds:
125 membs[self.vnfds[vnfd_idx].name] = \
126 vnfd_memb[self.COUNT]
127 sg['vnfd_members'] = membs
128
129 trigs = {}
130 if self.SCALE_ACT in dic:
131 for sg_act in dic.pop(self.SCALE_ACT):
132 # Validate the primitive
133 prim = sg_act.pop(self.NS_CONF_PRIM_REF)
134 for cprim in self.conf_prims:
135 if cprim[self.NAME] == prim:
136 trigs[sg_act.pop(self.TRIGGER)] = prim
137 break
138 if len(sg_act):
139 err_msg = (_("{0}, Did not find config-primitive {1}").
140 format(self, prim))
141 self.log.error(err_msg)
142 raise ValidationError(message=err_msg)
143 sg[self.CONFIG_ACTIONS] = trigs
144
145 if len(dic):
146 self.log.warn(_("{0}, Did not process all fields for {1}").
147 format(self, dic))
148 self.log.debug(_("{0}, Scale group {1}").format(self, sg))
149 self.scale_grps.append(sg)
150
151 def process_initial_config(dic):
152 icp = {}
153 self.log.debug(_("{0}, initial config: {1}").format(self, dic))
154 for key in [self.NAME, self.SEQ, self.USER_DEF_SCRIPT]:
155 if key in dic:
156 icp[key] = dic.pop(key)
157
158 params = {}
159 if self.PARAM in dic:
160 for p in dic.pop(self.PARAM):
161 if (self.NAME in p and
162 self.VALUE in p):
163 params[p[self.NAME]] = p[self.VALUE]
164 else:
165 # TODO (pjoseph): Need to add support to read the
166 # config file and get the value from that
167 self.log.warn(_("{0}, Got parameter without value: {1}").
168 format(self, p))
169 if len(params):
170 icp[self.PARAM] = params
171
172 if len(dic):
173 self.log.warn(_("{0}, Did not process all fields for {1}").
174 format(self, dic))
175 self.log.debug(_("{0}, Initial config {1}").format(self, icp))
176 self.initial_cfg.append({self.PROPERTIES : icp})
177
178 def process_vld(vld, dic):
179 vld_conf = {}
180 vld_prop = {}
181 ip_profile_vld = None
182 vld_name = None
183 if 'ip_profile_ref' in vld:
184 ip_profile_name = vld['ip_profile_ref']
185 if 'ip_profiles' in dic:
186 for ip_prof in dic['ip_profiles']:
187 if ip_profile_name == ip_prof['name']:
188 ip_profile_vld = ip_prof
189 if 'name' in vld:
190 vld_name = vld['name'].replace('-','_').replace(' ','')
191 if 'description' in vld:
192 vld_conf['description'] = vld['description']
193 if 'vendor' in vld:
194 vld_conf['vendor'] = vld['vendor']
195 if ip_profile_vld:
196 if 'ip_profile_params' in ip_profile_vld:
197 ip_param = ip_profile_vld['ip_profile_params']
198 if 'gateway_address' in ip_param:
199 vld_conf['gateway_ip'] = ip_param['gateway_address']
200 if 'subnet_address' in ip_param:
201 vld_conf['cidr'] = ip_param['subnet_address']
202 if 'ip_version' in ip_param:
203 vld_conf['ip_version'] = ip_param['ip_version'].replace('ipv','')
204
205 if vld_name:
206 vld_prop = {vld_name :
207 {
208 'type': self.T_ELAN,
209 self.PROPERTIES : vld_conf
210 }}
211 self.vlds[vld_name] = { 'type': self.T_ELAN,
212 self.PROPERTIES : vld_conf
213 }
214
215 self.vld_to_vnf_map[vld_name] = []
216 if 'vnfd_connection_point_ref' in vld:
217 for vnfd_ref in vld['vnfd_connection_point_ref']:
218 vnf_name = self.vnf_id_to_vnf_map[vnfd_ref['vnfd_id_ref']]
219 if vnf_name in self.vnf_to_vld_map:
220 self.vnf_to_vld_map[vnf_name].append(vld_name)
221 self._vnf_vld_conn_point_map[vnf_name].\
222 append((vld_name ,vnfd_ref['vnfd_connection_point_ref']))
223 else:
224 self.vnf_to_vld_map[vnf_name] = []
225 self._vnf_vld_conn_point_map[vnf_name] = []
226 self.vnf_to_vld_map[vnf_name].append(vld_name)
227 self._vnf_vld_conn_point_map[vnf_name].\
228 append((vld_name ,vnfd_ref['vnfd_connection_point_ref']))
229
230 def process_placement_group(placement_groups):
231 for i in range(0, len(placement_groups)):
232 placement_group = placement_groups[i]
233 pg_name = "placement_{0}".format(i)
234 pg_config = {}
235 targets = []
236 if 'name' in placement_group:
237 pg_config['name'] = placement_group['name']
238 if 'requirement' in placement_group:
239 pg_config['requirement'] = placement_group['requirement']
240 if 'strategy' in placement_group:
241 pg_config['strategy'] = placement_group['strategy']
242 if 'member_vnfd' in placement_group:
243 for member_vnfd in placement_group['member_vnfd']:
244 targets.append(self.vnf_id_to_vnf_map[member_vnfd['vnfd_id_ref']])
245 placement = { pg_name : {
246 'type': self.T_PLACEMENT,
247 self.PROPERTIES: pg_config,
248 self.TARGETS : str(targets)
249 }
250 }
251 self.placement_groups.append(placement)
252
253 def process_vnffgd(vnffgs, dic):
254 associated_cp_names = []
255 all_cp_names = []
256 vnfd_sfc_map = {}
257
258 conn_point_to_conection_node = {}
259 conn_point_to_vnf_name_map = {}
260
261 unigue_id_forwarder_path_map = OrderedDict()
262 forwarder_name_to_constitent_vnf_map = OrderedDict()
263 unique_id_classifier_map = OrderedDict()
264 fp_path_count = 1
265 forwarder_count = 1
266
267 vnffg_to_unique_id_rsp_map = OrderedDict()
268 vnffg_to_unique_id_classifier_map = OrderedDict()
269 vnffg_to_associated_cp_names = OrderedDict()
270 rsp_associated_cp_names = OrderedDict()
271 vnffg_to_forwarder_map = OrderedDict()
272 for vnffg in vnffgs:
273 unique_id_rsp_map = {}
274 for rs in vnffg['rsp']:
275 unique_id_rsp_map[str(rs['id'])] = rs
276 for class_identifier in vnffg['classifier']:
277 unique_id_classifier_map[str(class_identifier['rsp_id_ref'])] = class_identifier
278 associated_cp_names.append(class_identifier['vnfd_connection_point_ref'])
279 all_cp_names.append(class_identifier['vnfd_connection_point_ref'])
280 conn_point_to_vnf_name_map[class_identifier['vnfd_connection_point_ref']] = self.vnf_id_to_vnf_map[class_identifier['vnfd_id_ref']]
281 vnfd_sfc_map[self.vnf_id_to_vnf_map[class_identifier['vnfd_id_ref']]] = class_identifier['vnfd_connection_point_ref']
282
283 rsp_associated_cp_names[str(class_identifier['rsp_id_ref'])] = class_identifier['vnfd_connection_point_ref']
284
285 vnffg_to_unique_id_rsp_map[vnffg['name']] = unique_id_rsp_map
286 vnffg_to_forwarder_map[vnffg['name']] = []
287
288 for vnffg in vnffgs:
289 prop = {}
290 fp_members = []
291
292
293 prop['type'] = self.T_VNFFG
294 prop[self.DESC] = "Test"
295 prop[self.PROPERTIES] = {}
296 if 'vendor' in vnffg:
297 prop[self.PROPERTIES]['vendor'] = vnffg['vendor']
298 if 'name' in vnffg:
299 self.vnffgds[vnffg['name']] = prop
300
301 for rs_id, rs in vnffg_to_unique_id_rsp_map[vnffg['name']].items():
302 associated_cp_node_names = []
303 associated_vnf_names = []
304 number_of_endpoints = 0
305 if 'vnfd_connection_point_ref' in rs:
306 number_of_endpoints = number_of_endpoints + len(rs['vnfd_connection_point_ref'])
307 for vnf in rs['vnfd_connection_point_ref']:
308 associated_vnf_names.append(str(self.vnf_id_to_vnf_map[vnf['vnfd_id_ref']]))
309 associated_cp_names.append(vnf['vnfd_connection_point_ref'])
310 all_cp_names.append(vnf['vnfd_connection_point_ref'])
311 conn_point_to_vnf_name_map[vnf['vnfd_connection_point_ref']] = self.vnf_id_to_vnf_map[vnf['vnfd_id_ref']]
312 if "forwarder{}".format(fp_path_count) not in forwarder_name_to_constitent_vnf_map:
313 forwarder_name_to_constitent_vnf_map["forwarder{}".format(fp_path_count)] = associated_vnf_names
314 vnffg_to_forwarder_map[vnffg['name']].append("forwarder{}".format(fp_path_count))
315 fp_path_count = fp_path_count + 1
316
317 associated_cp_names = list(set(associated_cp_names))
318 for cp_name in associated_cp_names:
319 for idx, vnfd in self.vnfds.items():
320 for vdu in vnfd.vdus:
321 if cp_name == rsp_associated_cp_names[rs_id]:
322 if cp_name in vdu.conn_point_to_conection_node:
323 associated_cp_node_names.append(vdu.conn_point_to_conection_node[cp_name])
324 #conn_point_to_conection_node[cp_name] = vdu.conn_point_to_conection_node[cp_name]
325
326 for cp_name in all_cp_names:
327 for idx, vnfd in self.vnfds.items():
328 for vdu in vnfd.vdus:
329 if cp_name in vdu.conn_point_to_conection_node:
330 conn_point_to_conection_node[cp_name] = vdu.conn_point_to_conection_node[cp_name]
331
332 if len(associated_vnf_names) > 0:
333 associated_vnf_names = list(set(associated_vnf_names))
334 vnf_str = ", ".join(associated_vnf_names)
335 prop[self.PROPERTIES]['constituent_vnfs'] = "[{}]".format(vnf_str)
336 if len(associated_cp_node_names) > 0:
337 associated_cp_node_names = list(set(associated_cp_node_names))
338 connection_point_str = ", ".join(associated_cp_node_names)
339 prop[self.PROPERTIES]['connection_point'] = "[{}]".format(", ".join(associated_cp_node_names))
340
341 prop[self.PROPERTIES]['number_of_endpoints'] = number_of_endpoints
342 fp_name = "Forwarding_path{}".format(forwarder_count)
343 unigue_id_forwarder_path_map[fp_name] = rs_id
344 fp_members.append(fp_name)
345 forwarder_count = forwarder_count + 1
346
347 if len(fp_members) > 0:
348 prop['members'] = []
349 for fp in fp_members:
350 prop['members'].append(fp)
351
352 fp_count = 1
353 for fp, idx in unigue_id_forwarder_path_map.items():
354 for vnffg_name, unique_id_rsp_map in vnffg_to_unique_id_rsp_map.items():
355 if idx in unique_id_rsp_map:
356 prop = {}
357 prop['type'] = self.T_FP
358 prop[self.PROPERTIES] = {}
359 prop[self.PROPERTIES][self.DESC] = "Forwarder"
360 prop[self.PROPERTIES]['policy'] = {}
361 prop[self.PROPERTIES]['policy']['type'] = 'ACL'
362 prop[self.PROPERTIES]['policy']['criteria'] = []
363
364 prop[self.PROPERTIES]['path'] = []
365
366 rsp = unique_id_rsp_map[idx]
367 classifier = unique_id_classifier_map[idx]
368
369 for match in classifier['match_attributes']:
370 match_prop = {}
371 if 'source_port' in match:
372 port = "'{}'".format((match['source_port']))
373 prop[self.PROPERTIES]['policy']['criteria'].append({'source_port_range': port})
374 if 'destination_port' in match:
375 port = "'f'{}''".format((match['destination_port']))
376 prop[self.PROPERTIES]['policy']['criteria'].append({'destination_port_range': '5006'})
377 if 'ip_proto' in match:
378 port = match['ip_proto']
379 prop[self.PROPERTIES]['policy']['criteria'].append({'ip_proto': port})
380 if 'destination_ip_address' in match:
381 port = "'{}'".format((match['destination_ip_address']))
382 prop[self.PROPERTIES]['policy']['criteria'].append({'ip_dst_prefix': port})
383
384 if 'vnfd_connection_point_ref' in classifier:
385 if classifier['vnfd_connection_point_ref'] in conn_point_to_vnf_name_map:
386 if 'cp' not in prop[self.PROPERTIES]:
387 prop[self.PROPERTIES]['cp'] = {}
388 prop[self.PROPERTIES]['cp']['forwarder'] = conn_point_to_vnf_name_map[classifier['vnfd_connection_point_ref']]
389 prop[self.PROPERTIES]['cp']['capability'] = conn_point_to_conection_node[classifier['vnfd_connection_point_ref']]
390
391 for fp, vnf_list in forwarder_name_to_constitent_vnf_map.items():
392 for vnf in vnf_list:
393 for cp, vnf_name in conn_point_to_vnf_name_map.items():
394 if vnf == vnf_name:
395 self.substitution_mapping_forwarder.append((vnf, fp, conn_point_to_conection_node[cp]))
396
397 visited_forwarder = []
398 visited_path = None
399 for path, vnfs in forwarder_name_to_constitent_vnf_map.items():
400 for vnf in vnfs:
401 if (vnf not in visited_forwarder) and (path in vnffg_to_forwarder_map[vnffg_name]):
402 path_prop = {}
403 path_prop['forwarder'] = vnf
404 path_prop['capability'] = path
405 prop[self.PROPERTIES]['path'].append(path_prop)
406 visited_forwarder.append(vnf)
407 visited_path = path
408 forwarder_name_to_constitent_vnf_map.pop(visited_path)
409
410 self.forwarding_paths["Forwarding_path{}".format(fp_count)] = prop
411 fp_count = fp_count +1
412
413 self.vnfd_sfc_map = vnfd_sfc_map
414
415 dic = deepcopy(self.yang)
416 try:
417 for key in self.REQUIRED_FIELDS:
418 self.props[key] = dic.pop(key)
419
420 self.id = self.props[self.ID]
421
422 # Process constituent VNFDs
423 if self.CONST_VNFD in dic:
424 for cvnfd in dic.pop(self.CONST_VNFD):
425 process_const_vnfd(cvnfd)
426
427 # Process VLDs
428 if self.VLD in dic:
429 for vld_dic in dic.pop(self.VLD):
430 process_vld(vld_dic, dic)
431 #self.vlds.append(vld)
432
433 #Process VNFFG
434 if self.VNFFGD in dic:
435 process_vnffgd(dic[self.VNFFGD], dic)
436
437
438 #if self.
439
440 # Process config primitives
441 if self.CONF_PRIM in dic:
442 for cprim in dic.pop(self.CONF_PRIM):
443 conf_prim = {self.NAME: cprim.pop(self.NAME), self.DESC : 'TestDescription'}
444 if self.USER_DEF_SCRIPT in cprim:
445 conf_prim[self.USER_DEF_SCRIPT] = \
446 cprim.pop(self.USER_DEF_SCRIPT)
447 self.conf_prims.append(conf_prim)
448 else:
449 err_msg = (_("{0}, Only user defined script supported "
450 "in config-primitive for now {}: {}").
451 format(self, conf_prim, cprim))
452 self.log.error(err_msg)
453 raise ValidationError(message=err_msg)
454
455 # Process scaling group
456 if self.SCALE_GRP in dic:
457 for sg_dic in dic.pop(self.SCALE_GRP):
458 process_scale_grp(sg_dic)
459
460 # Process initial config primitives
461 if self.INITIAL_CFG in dic:
462 for icp_dic in dic.pop(self.INITIAL_CFG):
463 process_initial_config(icp_dic)
464
465 # Process the input params
466 if self.INPUT_PARAM_XPATH in dic:
467 for param in dic.pop(self.INPUT_PARAM_XPATH):
468 process_input_param(param)
469
470 if 'placement_groups' in dic:
471 process_placement_group(dic['placement_groups'])
472
473
474 self.remove_ignored_fields(dic)
475 if len(dic):
476 self.log.warn(_("{0}, Did not process the following for "
477 "NSD {1}: {2}").
478 format(self, self.props, dic))
479 self.log.debug(_("{0}, NSD: {1}").format(self, self.props))
480 except Exception as e:
481 err_msg = _("Exception processing NSD {0} : {1}"). \
482 format(self.name, e)
483 self.log.error(err_msg)
484 self.log.exception(e)
485 raise ValidationError(message=err_msg)
486
487 def generate_tosca_type(self):
488
489 self.log.debug(_("{0} Generate tosa types").
490 format(self))
491
492 tosca = {}
493 #tosca[self.DATA_TYPES] = {}
494 #tosca[self.NODE_TYPES] = {}
495 return tosca
496 for idx, vnfd in self.vnfds.items():
497 tosca = vnfd.generate_tosca_type(tosca)
498
499 for vld in self.vlds:
500 tosca = vld.generate_tosca_type(tosca)
501
502 # Generate type for config primitives
503 if self.GROUP_TYPES not in tosca:
504 tosca[self.GROUP_TYPES] = {}
505 if self.T_CONF_PRIM not in tosca[self.GROUP_TYPES]:
506 tosca[self.GROUP_TYPES][self.T_CONF_PRIM] = {
507 self.DERIVED_FROM: 'tosca.policies.Root',
508 self.PROPERTIES: {
509 'primitive': self.MAP
510 }}
511
512 # Generate type for scaling group
513 if self.POLICY_TYPES not in tosca:
514 tosca[self.POLICY_TYPES] = {}
515 if self.T_SCALE_GRP not in tosca[self.POLICY_TYPES]:
516 tosca[self.POLICY_TYPES][self.T_SCALE_GRP] = {
517 self.DERIVED_FROM: 'tosca.policies.Root',
518 self.PROPERTIES: {
519 self.NAME:
520 {self.TYPE: self.STRING},
521 self.MAX_INST_COUNT:
522 {self.TYPE: self.INTEGER},
523 self.MIN_INST_COUNT:
524 {self.TYPE: self.INTEGER},
525 'vnfd_members':
526 {self.TYPE: self.MAP},
527 self.CONFIG_ACTIONS:
528 {self.TYPE: self.MAP}
529 }}
530
531 if self.T_INITIAL_CFG not in tosca[self.POLICY_TYPES]:
532 tosca[self.POLICY_TYPES][self.T_INITIAL_CFG] = {
533 self.DERIVED_FROM: 'tosca.policies.Root',
534 self.PROPERTIES: {
535 self.NAME:
536 {self.TYPE: self.STRING},
537 self.SEQ:
538 {self.TYPE: self.INTEGER},
539 self.USER_DEF_SCRIPT:
540 {self.TYPE: self.STRING},
541 self.PARAM:
542 {self.TYPE: self.MAP},
543 }}
544
545 return tosca
546
547 def generate_tosca_template(self, tosca):
548 self.log.debug(_("{0}, Generate tosca template").
549 format(self, tosca))
550 # Add the standard entries
551 tosca['tosca_definitions_version'] = \
552 'tosca_simple_profile_for_nfv_1_0'
553 tosca[self.DESC] = self.props[self.DESC]
554 tosca[self.METADATA] = {
555 'ID': self.name,
556 self.VENDOR: self.props[self.VENDOR],
557 self.VERSION: self.props[self.VERSION],
558 }
559 if len(self.vnfd_files) > 0:
560 tosca[self.IMPORT] = []
561 imports = []
562 for vnfd_file in self.vnfd_files:
563 tosca[self.IMPORT].append('"{0}.yaml"'.format(vnfd_file))
564
565 tosca[self.TOPOLOGY_TMPL] = {}
566
567 # Add input params
568 '''
569 if len(self.inputs):
570 if self.INPUTS not in tosca[self.TOPOLOGY_TMPL]:
571 tosca[self.TOPOLOGY_TMPL][self.INPUTS] = {}
572 for inp in self.inputs:
573 entry = {inp[self.NAME]: {self.TYPE: self.STRING,
574 self.DESC:
575 'Translated from YANG'}}
576 tosca[self.TOPOLOGY_TMPL][self.INPUTS] = entry
577 '''
578 tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL] = {}
579
580 # Add the VNFDs and VLDs
581 for idx, vnfd in self.vnfds.items():
582 #vnfd.generate_vnf_template(tosca, idx)
583 node = {
584 'type' : vnfd.vnf_type,
585 self.PROPERTIES : {
586 self.ID : idx,
587 self.VENDOR : self.props[self.VENDOR],
588 self.VERSION : self.props[self.VERSION]
589 }
590 }
591 if vnfd.name in self.vnf_to_vld_map:
592 vld_list = self.vnf_to_vld_map[vnfd.name]
593 node[self.REQUIREMENTS] = []
594 for vld_idx in range(0, len(vld_list)):
595 vld_link_name = "{0}{1}".format("virtualLink", vld_idx + 1)
596 vld_prop = {}
597 vld_prop[vld_link_name] = vld_list[vld_idx]
598 node[self.REQUIREMENTS].append(vld_prop)
599 if vnfd.name in self._vnf_vld_conn_point_map:
600 vnf_vld_list = self._vnf_vld_conn_point_map[vnfd.name]
601 for vnf_vld in vnf_vld_list:
602 vnfd.generate_vld_link(vld_link_name, vnf_vld[1])
603
604 for sub_mapping in self.substitution_mapping_forwarder:
605 if sub_mapping[0] == vnfd.name:
606 vnfd.generate_forwarder_sub_mapping(sub_mapping)
607
608 for vnfd_name, cp_name in self.vnfd_sfc_map.items():
609 if vnfd.name == vnfd_name:
610 vnfd.generate_sfc_link(cp_name)
611
612
613
614 tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vnfd.name] = node
615
616 for vld_node_name in self.vlds:
617 tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vld_node_name] = self.vlds[vld_node_name]
618
619 for fp_name, fp in self.forwarding_paths.items():
620 tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][fp_name] = fp
621
622 # add the config primitives
623 if len(self.conf_prims):
624 if self.GROUPS not in tosca[self.TOPOLOGY_TMPL]:
625 tosca[self.TOPOLOGY_TMPL][self.GROUPS] = {}
626
627 conf_prims = {
628 self.TYPE: self.T_CONF_PRIM
629 }
630 conf_prims[self.MEMBERS] = [vnfd.name for vnfd in
631 self.vnfds.values()]
632 prims = {}
633 for confp in self.conf_prims:
634 prims[confp[self.NAME]] = {
635 self.USER_DEF_SCRIPT: confp[self.USER_DEF_SCRIPT]
636 }
637 conf_prims[self.PROPERTIES] = {
638 self.PRIMITIVES: prims
639 }
640 conf_prims[self.DESC] = 'Test'
641 #tosca[self.TOPOLOGY_TMPL][self.GROUPS][self.CONF_PRIM] = conf_prims
642
643
644 # Add the scale group
645 if len(self.scale_grps):
646 if self.POLICIES not in tosca[self.TOPOLOGY_TMPL]:
647 tosca[self.TOPOLOGY_TMPL][self.POLICIES] = []
648
649 for sg in self.scale_grps:
650 sgt = {
651 self.TYPE: self.T_SCALE_GRP,
652 }
653 sgt.update(sg)
654 tosca[self.TOPOLOGY_TMPL][self.POLICIES].append({
655 self.SCALE_GRP: sgt
656 })
657
658 # Add initial configs
659 if len(self.initial_cfg):
660 if self.POLICIES not in tosca[self.TOPOLOGY_TMPL]:
661 tosca[self.TOPOLOGY_TMPL][self.POLICIES] = []
662
663 for icp in self.initial_cfg:
664 if len(tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL]) > 0:
665 node_name = list(tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL].keys())[0]
666 icpt = {
667 self.TYPE: self.T_INITIAL_CFG,
668 self.TARGETS : "[{0}]".format(node_name)
669 }
670 icpt.update(icp)
671 tosca[self.TOPOLOGY_TMPL][self.POLICIES].append({
672 self.INITIAL_CFG: icpt
673 })
674
675 if len(self.placement_groups) > 0:
676 if self.POLICIES not in tosca[self.TOPOLOGY_TMPL]:
677 tosca[self.TOPOLOGY_TMPL][self.POLICIES] = []
678
679 for placment_group in self.placement_groups:
680 tosca[self.TOPOLOGY_TMPL][self.POLICIES].append(placment_group)
681
682 if len(self.vnffgds) > 0:
683 if self.GROUPS not in tosca[self.TOPOLOGY_TMPL]:
684 tosca[self.TOPOLOGY_TMPL][self.GROUPS] = {}
685 for vnffgd_name in self.vnffgds:
686 tosca[self.TOPOLOGY_TMPL][self.GROUPS][vnffgd_name] = self.vnffgds[vnffgd_name]
687
688
689 return tosca
690
691 def get_supporting_files(self):
692 files = []
693 # Get the config files for initial config
694 for icp in self.initial_cfg:
695 if 'properties' in icp:
696 if 'user_defined_script' in icp['properties']:
697 script = os.path.basename(icp['properties']['user_defined_script'])
698 files.append({
699 self.TYPE: 'script',
700 self.NAME: script,
701 self.DEST: "{}/{}".format(self.SCRIPT_DIR, script),
702 })
703
704 # TODO (pjoseph): Add support for config scripts,
705 # charms, etc
706
707 self.log.debug(_("{0}, supporting files: {1}").format(self, files))
708 return files