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