5c02cbbf6c0188b7dcc6fa40fe0031a9107ff508
[osm/SO.git] / examples / ping_pong_ns / rift / mano / examples / ping_pong_nsd.py
1 #!/usr/bin/env python3
2
3 #
4 # Copyright 2016 RIFT.IO Inc
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19
20 import argparse
21 import os
22 import shutil
23 import sys
24 import uuid
25
26 import gi
27 gi.require_version('RwYang', '1.0')
28 gi.require_version('RwVnfdYang', '1.0')
29 gi.require_version('VnfdYang', '1.0')
30 gi.require_version('RwNsdYang', '1.0')
31 gi.require_version('NsdYang', '1.0')
32
33
34 from gi.repository import (
35 RwNsdYang,
36 NsdYang,
37 RwVnfdYang,
38 VnfdYang,
39 RwYang,
40 )
41
42
43 try:
44 import rift.mano.config_data.config as config_data
45 except ImportError:
46 # Load modules from common which are not yet installed
47 path = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + "../../../common/python/rift/mano")
48 sys.path.append(path)
49
50 import config_data.config as config_data
51
52
53 NUM_PING_INSTANCES = 1
54 MAX_VNF_INSTANCES_PER_NS = 10
55 use_epa = False
56 aws = False
57 pingcount = NUM_PING_INSTANCES
58 use_ping_cloud_init_file = ""
59 use_pong_cloud_init_file = ""
60
61 PING_USERDATA_FILE = '''#cloud-config
62 password: fedora
63 chpasswd: { expire: False }
64 ssh_pwauth: True
65 runcmd:
66 - [ systemctl, daemon-reload ]
67 - [ systemctl, enable, ping.service ]
68 - [ systemctl, start, --no-block, ping.service ]
69 - [ ifup, eth1 ]
70 '''
71
72 PONG_USERDATA_FILE = '''#cloud-config
73 password: fedora
74 chpasswd: { expire: False }
75 ssh_pwauth: True
76 runcmd:
77 - [ systemctl, daemon-reload ]
78 - [ systemctl, enable, pong.service ]
79 - [ systemctl, start, --no-block, pong.service ]
80 - [ ifup, eth1 ]
81 '''
82
83
84 class UnknownVNFError(Exception):
85 pass
86
87
88 class ManoDescriptor(object):
89 def __init__(self, name):
90 self.name = name
91 self.descriptor = None
92
93 def write_to_file(self, module_list, outdir, output_format):
94 model = RwYang.Model.create_libncx()
95 for module in module_list:
96 model.load_module(module)
97
98 if output_format == 'json':
99 with open('%s/%s.json' % (outdir, self.name), "w") as fh:
100 fh.write(self.descriptor.to_json(model))
101 elif output_format.strip() == 'xml':
102 with open('%s/%s.xml' % (outdir, self.name), "w") as fh:
103 fh.write(self.descriptor.to_xml_v2(model))
104 elif output_format.strip() == 'yaml':
105 with open('%s/%s.yaml' % (outdir, self.name), "w") as fh:
106 fh.write(self.descriptor.to_yaml(model))
107 else:
108 raise Exception("Invalid output format for the descriptor")
109
110 def get_json(self, module_list):
111 model = RwYang.Model.create_libncx()
112 for module in module_list:
113 model.load_module(module)
114 print(self.descriptor.to_json(model))
115
116
117 class VirtualNetworkFunction(ManoDescriptor):
118 def __init__(self, name, instance_count=1):
119 self.vnfd_catalog = None
120 self.vnfd = None
121 self.instance_count = instance_count
122 self._placement_groups = []
123 super(VirtualNetworkFunction, self).__init__(name)
124
125 def add_placement_group(self, group):
126 self._placement_groups.append(group)
127
128 def add_vnf_access_point(self, mano_ut=False):
129 vnfd = self.descriptor.vnfd[0]
130 vnfap = vnfd.vnfap
131 cap = vnfap.create_capability()
132 cap.from_dict({
133 "name": "mgmt_ip",
134 "description": "Management address",
135 "attribute": "../../../../mgmt-interface, ip-address",
136 })
137 vnfap.capability.append(cap)
138 cap = vnfap.create_capability()
139 cap.from_dict({
140 "name": "mgmt_port",
141 "description": "Management port",
142 "xpath": "../../../../mgmt-interface/port",
143 })
144 vnfap.capability.append(cap)
145 cap = vnfap.create_capability()
146 cap.from_dict({
147 "name": "username",
148 "description": "Management username",
149 "value": "admin"
150 })
151 vnfap.capability.append(cap)
152 cap = vnfap.create_capability()
153 cap.from_dict({
154 "name": "password",
155 "description": "Management password",
156 "value": "admin"
157 })
158 vnfap.capability.append(cap)
159
160 # Check if pong
161 if 'pong_' in self.name:
162 cap = vnfap.create_capability()
163 cap.from_dict({
164 "name": "service_ip",
165 "description": "IP on which Pong service is listening",
166 "attribute": "../../../../connection-point[name='pong_vnfd/cp0'], ip-address"
167 })
168 vnfap.capability.append(cap)
169 cap = vnfap.create_capability()
170 cap.from_dict({
171 "name": "service_port",
172 "description": "Port on which server listens for incoming data packets",
173 "value": "5555"
174 })
175 vnfap.capability.append(cap)
176
177 else:
178 cap = vnfap.create_capability()
179 cap.from_dict({
180 "name": "rate",
181 "description": "Rate of packet generation",
182 "value": "5"
183 })
184 vnfap.capability.append(cap)
185
186 dep = vnfap.create_dependency()
187 dep.from_dict({
188 "name": "service_ip",
189 "description": "IP on which Pong service is listening",
190 "mandatory": "true",
191 })
192 dep.config_primitive_name_ref.append('config')
193 vnfap.dependency.append(dep)
194 dep = vnfap.create_dependency()
195 dep.from_dict({
196 "name": "service_port",
197 "description": "Port on which Pong service is listening",
198 "mandatory": False,
199 })
200 dep.config_primitive_name_ref.append('config')
201 vnfap.dependency.append(dep)
202
203 def add_ping_config(self, mano_ut=False, use_ns_init_conf=False):
204 vnfd = self.descriptor.vnfd[0]
205 # Add vnf configuration
206 vnf_config = vnfd.vnf_configuration
207
208 vnf_config.config_attributes.config_delay = 60
209
210 # Add config primitive
211 vnf_config.create_config_primitive()
212 prim = VnfdYang.ConfigPrimitive.from_dict({
213 "name": "config",
214 "parameter": [
215 {"name": "mgmt_ip", "data_type": "STRING"},
216 {"name": "mgmt_port", "data_type": "INTEGER"},
217 {"name": "username", "data_type": "STRING"},
218 {"name": "password", "data_type": "STRING"},
219 {"name": "service_ip", "data_type": "STRING"},
220 {"name": "service_port", "data_type": "INTEGER",
221 "default_value": "5555"},
222 ],
223 "user_defined_script": "ping-setup.py",
224 })
225 vnf_config.config_primitive.append(prim)
226
227 prim = VnfdYang.ConfigPrimitive.from_dict({
228 "name": "set-rate",
229 "parameter": [
230 {"name": "mgmt_ip", "data_type": "STRING"},
231 {"name": "mgmt_port", "data_type": "INTEGER"},
232 {"name": "username", "data_type": "STRING"},
233 {"name": "password", "data_type": "STRING"},
234 {"name": "rate", "data_type": "INTEGER",
235 "default_value": "5"},
236 ],
237 "user_defined_script": "ping-set-rate.py",
238 })
239 vnf_config.config_primitive.append(prim)
240
241 prim = VnfdYang.ConfigPrimitive.from_dict({
242 "name": "start-stop",
243 "parameter": [
244 {"name": "mgmt_ip", "data_type": "STRING"},
245 {"name": "mgmt_port", "data_type": "INTEGER"},
246 {"name": "username", "data_type": "STRING"},
247 {"name": "password", "data_type": "STRING"},
248 {"name": "start", "data_type": "BOOLEAN",
249 "default_value": "true"}
250 ],
251 "user_defined_script": "ping-start-stop.py",
252 })
253 vnf_config.config_primitive.append(prim)
254
255 # Add initial config primitive
256 vnf_config.create_initial_config_primitive()
257 init_config = VnfdYang.InitialConfigPrimitive.from_dict(
258 {
259 "seq": 1,
260 "config_primitive_ref": "config",
261 }
262 )
263 vnf_config.initial_config_primitive.append(init_config)
264
265 init_config = VnfdYang.InitialConfigPrimitive.from_dict(
266 {
267 "seq": 2,
268 "config_primitive_ref": "set-rate",
269 },
270 )
271 vnf_config.initial_config_primitive.append(init_config)
272
273 if use_ns_init_conf is False:
274 init_config = VnfdYang.InitialConfigPrimitive.from_dict(
275 {
276 "seq": 3,
277 "config_primitive_ref": "start-stop",
278 },
279 )
280 vnf_config.initial_config_primitive.append(init_config)
281
282 def add_pong_config(self, mano_ut=False, use_ns_init_conf=False):
283 vnfd = self.descriptor.vnfd[0]
284 # Add vnf configuration
285 vnf_config = vnfd.vnf_configuration
286
287 # Add config primitive
288 vnf_config.create_config_primitive()
289 prim = VnfdYang.ConfigPrimitive.from_dict({
290 "name": "config",
291 "parameter": [
292 {"name": "mgmt_ip", "data_type": "STRING"},
293 {"name": "mgmt_port", "data_type": "INTEGER"},
294 {"name": "username", "data_type": "STRING"},
295 {"name": "password", "data_type": "STRING"},
296 {"name": "service_ip", "data_type": "STRING"},
297 {"name": "service_port", "data_type": "INTEGER"},
298 ],
299 "user_defined_script": "ping-setup.py",
300 })
301 vnf_config.config_primitive.append(prim)
302
303 prim = VnfdYang.ConfigPrimitive.from_dict({
304 "name": "start-stop",
305 "parameter": [
306 {"name": "mgmt_ip", "data_type": "STRING"},
307 {"name": "mgmt_port", "data_type": "INTEGER"},
308 {"name": "username", "data_type": "STRING"},
309 {"name": "password", "data_type": "STRING"},
310 {"name": "start", "data_type": "BOOLEAN",
311 "default_value": "true"}
312 ],
313 "user_defined_script": "ping-start-stop.py",
314 })
315 vnf_config.config_primitive.append(prim)
316
317 # Add initial config primitive
318 vnf_config.create_initial_config_primitive()
319 init_config = VnfdYang.InitialConfigPrimitive.from_dict(
320 {
321 "seq": 1,
322 "config_primitive_ref": "config",
323 }
324 )
325 vnf_config.initial_config_primitive.append(init_config)
326
327 if use_ns_init_conf is False:
328 init_config = VnfdYang.InitialConfigPrimitive.from_dict(
329 {
330 "seq": 2,
331 "config_primitive_ref": "start-stop",
332 },
333 )
334 vnf_config.initial_config_primitive.append(init_config)
335
336 def compose(self, image_name, cloud_init="", cloud_init_file="", endpoint=None, mon_params=[],
337 mon_port=8888, mgmt_port=8888, num_vlr_count=1, num_ivlr_count=1,
338 num_vms=1, image_md5sum=None, mano_ut=False, use_ns_init_conf=False,
339 use_vca_conf=False):
340 self.descriptor = RwVnfdYang.YangData_Vnfd_VnfdCatalog()
341 self.id = str(uuid.uuid1())
342 vnfd = self.descriptor.vnfd.add()
343 vnfd.id = self.id
344 vnfd.name = self.name
345 vnfd.short_name = self.name
346 vnfd.vendor = 'RIFT.io'
347 vnfd.logo = 'rift_logo.png'
348 vnfd.description = 'This is an example RIFT.ware VNF'
349 vnfd.version = '1.0'
350
351 self.vnfd = vnfd
352
353 if mano_ut is True:
354 internal_vlds = []
355 for i in range(num_ivlr_count):
356 internal_vld = vnfd.internal_vld.add()
357 internal_vld.id = 'ivld%s' % i
358 internal_vld.name = 'fabric%s' % i
359 internal_vld.short_name = 'fabric%s' % i
360 internal_vld.description = 'Virtual link for internal fabric%s' % i
361 internal_vld.type_yang = 'ELAN'
362 internal_vlds.append(internal_vld)
363
364 for i in range(num_vlr_count):
365 cp = vnfd.connection_point.add()
366 cp.type_yang = 'VPORT'
367 cp.name = '%s/cp%d' % (self.name, i)
368
369 if endpoint is not None:
370 endp = VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd_HttpEndpoint(
371 path=endpoint, port=mon_port, polling_interval_secs=2
372 )
373 vnfd.http_endpoint.append(endp)
374
375 # Monitoring params
376 for monp_dict in mon_params:
377 monp = VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd_MonitoringParam.from_dict(monp_dict)
378 monp.http_endpoint_ref = endpoint
379 vnfd.monitoring_param.append(monp)
380
381
382 for i in range(num_vms):
383 # VDU Specification
384 vdu = vnfd.vdu.add()
385 vdu.id = 'iovdu_%s' % i
386 vdu.name = 'iovdu_%s' % i
387 vdu.count = 1
388 # vdu.mgmt_vpci = '0000:00:20.0'
389
390 # specify the VM flavor
391 if use_epa:
392 vdu.vm_flavor.vcpu_count = 4
393 vdu.vm_flavor.memory_mb = 1024
394 vdu.vm_flavor.storage_gb = 4
395 else:
396 vdu.vm_flavor.vcpu_count = 1
397 vdu.vm_flavor.memory_mb = 512
398 vdu.vm_flavor.storage_gb = 4
399
400 # Management interface
401 mgmt_intf = vnfd.mgmt_interface
402 mgmt_intf.vdu_id = vdu.id
403 mgmt_intf.port = mgmt_port
404 mgmt_intf.dashboard_params.path = endpoint
405 mgmt_intf.dashboard_params.port = mgmt_port
406
407 if cloud_init_file and len(cloud_init_file):
408 vdu.cloud_init_file = cloud_init_file
409 else:
410 vdu.cloud_init = cloud_init
411 if aws:
412 vdu.cloud_init += " - [ systemctl, restart, --no-block, elastic-network-interfaces.service ]\n"
413
414 # Add VNF access point
415 self.add_vnf_access_point(mano_ut=mano_ut)
416 if 'pong_' in self.name:
417 self.add_pong_config(mano_ut=mano_ut, use_ns_init_conf=use_ns_init_conf)
418 else:
419 self.add_ping_config(mano_ut=mano_ut, use_ns_init_conf=use_ns_init_conf)
420
421 # sepcify the guest EPA
422 if use_epa:
423 vdu.guest_epa.trusted_execution = False
424 vdu.guest_epa.mempage_size = 'LARGE'
425 vdu.guest_epa.cpu_pinning_policy = 'DEDICATED'
426 vdu.guest_epa.cpu_thread_pinning_policy = 'PREFER'
427 vdu.guest_epa.numa_node_policy.node_cnt = 2
428 vdu.guest_epa.numa_node_policy.mem_policy = 'STRICT'
429
430 node = vdu.guest_epa.numa_node_policy.node.add()
431 node.id = 0
432 node.memory_mb = 512
433 vcpu = node.vcpu.add()
434 vcpu.id = 0
435 vcpu = node.vcpu.add()
436 vcpu.id = 1
437
438 node = vdu.guest_epa.numa_node_policy.node.add()
439 node.id = 1
440 node.memory_mb = 512
441 vcpu = node.vcpu.add()
442 vcpu.id = 2
443 vcpu = node.vcpu.add()
444 vcpu.id = 3
445
446 # specify the vswitch EPA
447 vdu.vswitch_epa.ovs_acceleration = 'DISABLED'
448 vdu.vswitch_epa.ovs_offload = 'DISABLED'
449
450 # Specify the hypervisor EPA
451 vdu.hypervisor_epa.type_yang = 'PREFER_KVM'
452
453 # Specify the host EPA
454 # vdu.host_epa.cpu_model = 'PREFER_SANDYBRIDGE'
455 # vdu.host_epa.cpu_arch = 'PREFER_X86_64'
456 # vdu.host_epa.cpu_vendor = 'PREFER_INTEL'
457 # vdu.host_epa.cpu_socket_count = 2
458 # vdu.host_epa.cpu_core_count = 8
459 # vdu.host_epa.cpu_core_thread_count = 2
460 # vdu.host_epa.cpu_feature = ['PREFER_AES', 'REQUIRE_VME', 'PREFER_MMX','REQUIRE_SSE2']
461
462 if aws:
463 vdu.image = 'rift-ping-pong'
464 else:
465 vdu.image = image_name
466 if image_md5sum is not None:
467 vdu.image_checksum = image_md5sum
468
469 if mano_ut is True:
470 for i in range(num_ivlr_count):
471 internal_cp = vdu.internal_connection_point.add()
472 if vnfd.name.find("ping") >= 0:
473 cp_name = "ping"
474 else:
475 cp_name = "pong"
476 internal_cp.name = cp_name + "/icp{}".format(i)
477 internal_cp.id = cp_name + "/icp{}".format(i)
478 internal_cp.type_yang = 'VPORT'
479 ivld_cp = internal_vlds[i].internal_connection_point.add()
480 ivld_cp.id_ref = internal_cp.id
481
482 internal_interface = vdu.internal_interface.add()
483 internal_interface.name = 'fab%d' % i
484 internal_interface.vdu_internal_connection_point_ref = internal_cp.id
485 internal_interface.virtual_interface.type_yang = 'VIRTIO'
486
487 # internal_interface.virtual_interface.vpci = '0000:00:1%d.0'%i
488
489 for i in range(num_vlr_count):
490 external_interface = vdu.external_interface.add()
491 external_interface.name = 'eth%d' % i
492 external_interface.vnfd_connection_point_ref = '%s/cp%d' % (self.name, i)
493 if use_epa:
494 external_interface.virtual_interface.type_yang = 'VIRTIO'
495 else:
496 external_interface.virtual_interface.type_yang = 'VIRTIO'
497 # external_interface.virtual_interface.vpci = '0000:00:2%d.0'%i
498
499 for group in self._placement_groups:
500 placement_group = vnfd.placement_groups.add()
501 placement_group.name = group.name
502 placement_group.requirement = group.requirement
503 placement_group.strategy = group.strategy
504 if group.vdu_list:
505 ### Add specific VDUs to placement group
506 for vdu in group.vdu_list:
507 member_vdu = placement_group.member_vdus.add()
508 member_vdu.member_vdu_ref = vdu.id
509 else:
510 ### Add all VDUs to placement group
511 for vdu in vnfd.vdu:
512 member_vdu = placement_group.member_vdus.add()
513 member_vdu.member_vdu_ref = vdu.id
514
515
516 def write_to_file(self, outdir, output_format):
517 dirpath = "%s/%s" % (outdir, self.name)
518 if not os.path.exists(dirpath):
519 os.makedirs(dirpath)
520 super(VirtualNetworkFunction, self).write_to_file(['vnfd', 'rw-vnfd'],
521 dirpath,
522 output_format)
523 self.add_scripts(outdir)
524
525 def add_scripts(self, outdir):
526 script_dir = os.path.join(outdir, self.name, 'cloud_init')
527 try:
528 os.makedirs(script_dir)
529 except OSError:
530 if not os.path.isdir(script_dir):
531 raise
532
533 if 'ping' in self.name:
534 script_file = os.path.join(script_dir, 'ping_cloud_init.cfg')
535 cfg = PING_USERDATA_FILE
536 else:
537 script_file = os.path.join(script_dir, 'pong_cloud_init.cfg')
538 cfg = PONG_USERDATA_FILE
539
540 with open(script_file, "w") as f:
541 f.write("{}".format(cfg))
542
543
544 class NetworkService(ManoDescriptor):
545 def __init__(self, name):
546 super(NetworkService, self).__init__(name)
547 self._scale_groups = []
548 self.vnfd_config = {}
549 self._placement_groups = []
550
551 def ping_config(self, mano_ut, use_ns_init_conf):
552 suffix = ''
553 if mano_ut:
554 ping_cfg = r'''
555 #!/bin/bash
556
557 echo "!!!!!!!! Executed ping Configuration !!!!!!!!!"
558 '''
559 else:
560 ping_cfg = r'''
561 #!/bin/bash
562
563 # Rest API config
564 ping_mgmt_ip='<rw_mgmt_ip>'
565 ping_mgmt_port=18888
566
567 # VNF specific configuration
568 pong_server_ip='<rw_connection_point_name pong_vnfd%s/cp0>'
569 ping_rate=5
570 server_port=5555
571
572 # Make rest API calls to configure VNF
573 curl -D /dev/stdout \
574 -H "Accept: application/vnd.yang.data+xml" \
575 -H "Content-Type: application/vnd.yang.data+json" \
576 -X POST \
577 -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
578 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server
579 rc=$?
580 if [ $rc -ne 0 ]
581 then
582 echo "Failed to set server info for ping!"
583 exit $rc
584 fi
585
586 curl -D /dev/stdout \
587 -H "Accept: application/vnd.yang.data+xml" \
588 -H "Content-Type: application/vnd.yang.data+json" \
589 -X POST \
590 -d "{\"rate\":$ping_rate}" \
591 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/rate
592 rc=$?
593 if [ $rc -ne 0 ]
594 then
595 echo "Failed to set ping rate!"
596 exit $rc
597 fi
598
599 ''' % suffix
600 if use_ns_init_conf:
601 ping_cfg += "exit 0\n"
602 else:
603 ping_cfg +='''
604 output=$(curl -D /dev/stdout \
605 -H "Accept: application/vnd.yang.data+xml" \
606 -H "Content-Type: application/vnd.yang.data+json" \
607 -X POST \
608 -d "{\"enable\":true}" \
609 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/adminstatus/state)
610 if [[ $output == *"Internal Server Error"* ]]
611 then
612 echo $output
613 exit 3
614 else
615 echo $output
616 fi
617
618 exit 0
619 '''
620 return ping_cfg
621
622 def pong_config(self, mano_ut, use_ns_init_conf):
623 suffix = ''
624 if mano_ut:
625 pong_cfg = r'''
626 #!/bin/bash
627
628 echo "!!!!!!!! Executed pong Configuration !!!!!!!!!"
629 '''
630 else:
631 pong_cfg = r'''
632 #!/bin/bash
633
634 # Rest API configuration
635 pong_mgmt_ip='<rw_mgmt_ip>'
636 pong_mgmt_port=18889
637 # username=<rw_username>
638 # password=<rw_password>
639
640 # VNF specific configuration
641 pong_server_ip='<rw_connection_point_name pong_vnfd%s/cp0>'
642 server_port=5555
643
644 # Make Rest API calls to configure VNF
645 curl -D /dev/stdout \
646 -H "Accept: application/vnd.yang.data+xml" \
647 -H "Content-Type: application/vnd.yang.data+json" \
648 -X POST \
649 -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
650 http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/server
651 rc=$?
652 if [ $rc -ne 0 ]
653 then
654 echo "Failed to set server(own) info for pong!"
655 exit $rc
656 fi
657
658 ''' % suffix
659
660 if use_ns_init_conf:
661 pong_cfg += "exit 0\n"
662 else:
663 pong_cfg +='''
664 curl -D /dev/stdout \
665 -H "Accept: application/vnd.yang.data+xml" \
666 -H "Content-Type: application/vnd.yang.data+json" \
667 -X POST \
668 -d "{\"enable\":true}" \
669 http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/adminstatus/state
670 rc=$?
671 if [ $rc -ne 0 ]
672 then
673 echo "Failed to enable pong service!"
674 exit $rc
675 fi
676
677 exit 0
678 '''
679 return pong_cfg
680
681 def pong_fake_juju_config(self, vnf_config):
682
683 if vnf_config:
684 # Select "script" configuration
685 vnf_config.juju.charm = 'clearwater-aio-proxy'
686
687 # Set the initital-config
688 vnf_config.create_initial_config_primitive()
689 init_config = VnfdYang.InitialConfigPrimitive.from_dict({
690 "seq": 1,
691 "name": "config",
692 "parameter": [
693 {"name": "proxied_ip", "value": "<rw_mgmt_ip>"},
694 ]
695 })
696 vnf_config.initial_config_primitive.append(init_config)
697
698 init_config_action = VnfdYang.InitialConfigPrimitive.from_dict({
699 "seq": 2,
700 "name": "action1",
701 "parameter": [
702 {"name": "Pong Connection Point", "value": "pong_vnfd/cp0"},
703 ]
704 })
705 vnf_config.initial_config_primitive.append(init_config_action)
706 init_config_action = VnfdYang.InitialConfigPrimitive.from_dict({
707 "seq": 3,
708 "name": "action2",
709 "parameter": [
710 {"name": "Ping Connection Point", "value": "ping_vnfd/cp0"},
711 ]
712 })
713 vnf_config.initial_config_primitive.append(init_config_action)
714
715 # Config parameters can be taken from config.yaml and
716 # actions from actions.yaml in the charm
717 # Config to set the home domain
718 vnf_config.create_config_primitive()
719 config = VnfdYang.ConfigPrimitive.from_dict({
720 "name": "config",
721 "parameter": [
722 {"name": "home_domain", "data_type": "STRING"},
723 {"name": "base_number", "data_type": "STRING"},
724 {"name": "number_count", "data_type": "INTEGER"},
725 {"name": "password", "data_type": "STRING"},
726 ]
727 })
728 vnf_config.config_primitive.append(config)
729
730 config = VnfdYang.ConfigPrimitive.from_dict({
731 "name": "create-update-user",
732 # "user-defined-script":"/tmp/test.py",
733 "parameter": [
734 {"name": "number", "data_type": "STRING", "mandatory": True},
735 {"name": "password", "data_type": "STRING", "mandatory": True},
736 ]
737 })
738 vnf_config.config_primitive.append(config)
739
740 config = VnfdYang.ConfigPrimitive.from_dict({
741 "name": "delete-user",
742 "parameter": [
743 {"name": "number", "data_type": "STRING", "mandatory": True},
744 ]
745 })
746 vnf_config.config_primitive.append(config)
747
748 def default_config(self, const_vnfd, vnfd, mano_ut, use_ns_init_conf):
749 vnf_config = vnfd.vnfd.vnf_configuration
750
751 vnf_config.config_attributes.config_priority = 0
752 vnf_config.config_attributes.config_delay = 0
753
754 # Select "script" configuration
755 vnf_config.script.script_type = 'bash'
756
757 if vnfd.name == 'pong_vnfd' or vnfd.name == 'pong_vnfd_with_epa' or vnfd.name == 'pong_vnfd_aws':
758 vnf_config.config_attributes.config_priority = 1
759 vnf_config.config_template = self.pong_config(mano_ut, use_ns_init_conf)
760 # First priority config delay will delay the entire NS config delay
761 if mano_ut is False:
762 vnf_config.config_attributes.config_delay = 60
763 else:
764 # This is PONG and inside mano_ut
765 # This is test only
766 vnf_config.config_attributes.config_delay = 10
767 # vnf_config.config_template = self.pong_config(vnf_config, use_ns_init_conf)
768
769 if vnfd.name == 'ping_vnfd' or vnfd.name == 'ping_vnfd_with_epa' or vnfd.name == 'ping_vnfd_aws':
770 vnf_config.config_attributes.config_priority = 2
771 vnf_config.config_template = self.ping_config(mano_ut, use_ns_init_conf)
772
773 def ns_config(self, nsd, vnfd_list, mano_ut):
774 # Used by scale group
775 if mano_ut:
776 nsd.service_primitive.add().from_dict(
777 {
778 "name": "ping config",
779 "user_defined_script": "{}".format(os.path.join(
780 os.environ['RIFT_ROOT'],
781 'modules/core/mano',
782 'examples/ping_pong_ns/rift/mano/examples',
783 'ping_config_ut.sh'))
784 })
785 else:
786 nsd.service_primitive.add().from_dict(
787 {
788 "name": "ping config",
789 "user_defined_script": "ping_config.py"
790 })
791
792 def ns_initial_config(self, nsd):
793 nsd.initial_config_primitive.add().from_dict(
794 {
795 "seq": 1,
796 "name": "start traffic",
797 "user_defined_script": "start_traffic.py",
798 "parameter": [
799 {
800 'name': 'userid',
801 'value': 'rift',
802 },
803 ],
804 }
805 )
806
807 def add_scale_group(self, scale_group):
808 self._scale_groups.append(scale_group)
809
810 def add_placement_group(self, placement_group):
811 self._placement_groups.append(placement_group)
812
813 def create_mon_params(self, vnfds):
814 NsdMonParam = NsdYang.YangData_Nsd_NsdCatalog_Nsd_MonitoringParam
815 param_id = 1
816 for vnfd_obj in vnfds:
817 for mon_param in vnfd_obj.vnfd.monitoring_param:
818 nsd_monp = NsdMonParam.from_dict({
819 'id': str(param_id),
820 'name': mon_param.name,
821 'aggregation_type': "AVERAGE",
822 'value_type': mon_param.value_type,
823 'vnfd_monitoring_param': [
824 {'vnfd_id_ref': vnfd_obj.vnfd.id,
825 'vnfd_monitoring_param_ref': mon_param.id}]
826 })
827
828 self.nsd.monitoring_param.append(nsd_monp)
829 param_id += 1
830
831
832
833
834 def compose(self, vnfd_list, cpgroup_list, mano_ut,
835 use_ns_init_conf=True,
836 use_vca_conf=False):
837
838 if mano_ut:
839 # Disable NS initial config primitive
840 use_ns_init_conf=False
841
842 self.descriptor = RwNsdYang.YangData_Nsd_NsdCatalog()
843 self.id = str(uuid.uuid1())
844 nsd = self.descriptor.nsd.add()
845 self.nsd = nsd
846 nsd.id = self.id
847 nsd.name = self.name
848 nsd.short_name = self.name
849 nsd.vendor = 'RIFT.io'
850 nsd.logo = 'rift_logo.png'
851 nsd.description = 'Toy NS'
852 nsd.version = '1.0'
853 nsd.input_parameter_xpath.append(
854 NsdYang.YangData_Nsd_NsdCatalog_Nsd_InputParameterXpath(
855 xpath="/nsd:nsd-catalog/nsd:nsd/nsd:vendor",
856 )
857 )
858
859 ip_profile = nsd.ip_profiles.add()
860 ip_profile.name = "InterVNFLink"
861 ip_profile.description = "Inter VNF Link"
862 ip_profile.ip_profile_params.ip_version = "ipv4"
863 ip_profile.ip_profile_params.subnet_address = "31.31.31.0/24"
864 ip_profile.ip_profile_params.gateway_address = "31.31.31.210"
865
866 vld_id = 1
867 for cpgroup in cpgroup_list:
868 vld = nsd.vld.add()
869 vld.id = 'ping_pong_vld%s' % vld_id
870 vld_id += 1
871 vld.name = 'ping_pong_vld' # hard coded
872 vld.short_name = vld.name
873 vld.vendor = 'RIFT.io'
874 vld.description = 'Toy VL'
875 vld.version = '1.0'
876 vld.type_yang = 'ELAN'
877 vld.ip_profile_ref = 'InterVNFLink'
878 for cp in cpgroup:
879 cpref = vld.vnfd_connection_point_ref.add()
880 cpref.member_vnf_index_ref = cp[0]
881 cpref.vnfd_id_ref = cp[1]
882 cpref.vnfd_connection_point_ref = cp[2]
883
884 vnfd_index_map = {}
885 member_vnf_index = 1
886 for vnfd in vnfd_list:
887 for i in range(vnfd.instance_count):
888 constituent_vnfd = nsd.constituent_vnfd.add()
889 constituent_vnfd.member_vnf_index = member_vnf_index
890 vnfd_index_map[vnfd] = member_vnf_index
891
892 # Set the start by default to false for ping vnfd,
893 # if scaling is enabled
894 if (len(self._scale_groups) and
895 vnfd.descriptor.vnfd[0].name == 'ping_vnfd'):
896 constituent_vnfd.start_by_default = False
897
898 constituent_vnfd.vnfd_id_ref = vnfd.descriptor.vnfd[0].id
899 if use_vca_conf is False:
900 self.default_config(constituent_vnfd, vnfd, mano_ut,
901 use_ns_init_conf)
902 member_vnf_index += 1
903
904 # Enable config primitives if either mano_ut or
905 # scale groups are enabled
906 if mano_ut or len(self._scale_groups):
907 self.ns_config(nsd, vnfd_list, mano_ut)
908
909 # Add NS initial config to start traffic
910 if use_ns_init_conf:
911 self.ns_initial_config(nsd)
912
913 for scale_group in self._scale_groups:
914 group_desc = nsd.scaling_group_descriptor.add()
915 group_desc.name = scale_group.name
916 group_desc.max_instance_count = scale_group.max_count
917 group_desc.min_instance_count = scale_group.min_count
918 for vnfd, count in scale_group.vnfd_count_map.items():
919 member = group_desc.vnfd_member.add()
920 member.member_vnf_index_ref = vnfd_index_map[vnfd]
921 member.count = count
922
923 for trigger in scale_group.config_action:
924 config_action = group_desc.scaling_config_action.add()
925 config_action.trigger = trigger
926 config = scale_group.config_action[trigger]
927 config_action.ns_config_primitive_name_ref = config['ns-config-primitive-name-ref']
928
929 for placement_group in self._placement_groups:
930 group = nsd.placement_groups.add()
931 group.name = placement_group.name
932 group.strategy = placement_group.strategy
933 group.requirement = placement_group.requirement
934 for member_vnfd in placement_group.vnfd_list:
935 member = group.member_vnfd.add()
936 member.vnfd_id_ref = member_vnfd.descriptor.vnfd[0].id
937 member.member_vnf_index_ref = vnfd_index_map[member_vnfd]
938
939 # self.create_mon_params(vnfd_list)
940
941 def write_config(self, outdir, vnfds):
942
943 converter = config_data.ConfigPrimitiveConvertor()
944 yaml_data = converter.extract_nsd_config(self.nsd)
945
946 ns_config_dir = os.path.join(outdir, self.name, "ns_config")
947 os.makedirs(ns_config_dir, exist_ok=True)
948 vnf_config_dir = os.path.join(outdir, self.name, "vnf_config")
949 os.makedirs(vnf_config_dir, exist_ok=True)
950
951 if len(yaml_data):
952 with open('%s/%s.yaml' % (ns_config_dir, self.id), "w") as fh:
953 fh.write(yaml_data)
954
955 for i, vnfd in enumerate(vnfds, start=1):
956 yaml_data = converter.extract_vnfd_config(vnfd)
957
958 if len(yaml_data):
959 with open('%s/%s__%s.yaml' % (vnf_config_dir, vnfd.id, i), "w") as fh:
960 fh.write(yaml_data)
961
962 def write_initial_config_script(self, outdir):
963 script_name = 'start_traffic.py'
964
965 src_path = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
966 script_src = os.path.join(src_path, script_name)
967 if not os.path.exists(script_src):
968 src_path = os.path.join(os.environ['RIFT_ROOT'],
969 'modules/core/mano/examples/ping_pong_ns/rift/mano/examples')
970 script_src = os.path.join(src_path, script_name)
971
972 dest_path = os.path.join(outdir, 'scripts')
973 os.makedirs(dest_path, exist_ok=True)
974
975 shutil.copy2(script_src, dest_path)
976
977 def write_to_file(self, outdir, output_format):
978 dirpath = os.path.join(outdir, self.name)
979 if not os.path.exists(dirpath):
980 os.makedirs(dirpath)
981
982 super(NetworkService, self).write_to_file(["nsd", "rw-nsd"],
983 dirpath,
984 output_format)
985
986 # Write the initial config script
987 self.write_initial_config_script(dirpath)
988
989
990 def get_ping_mon_params(path):
991 return [
992 {
993 'id': '1',
994 'name': 'ping-request-tx-count',
995 'http_endpoint_ref': path,
996 'json_query_method': "NAMEKEY",
997 'value_type': "INT",
998 'description': 'no of ping requests',
999 'group_tag': 'Group1',
1000 'widget_type': 'COUNTER',
1001 'units': 'packets'
1002 },
1003
1004 {
1005 'id': '2',
1006 'name': 'ping-response-rx-count',
1007 'http_endpoint_ref': path,
1008 'json_query_method': "NAMEKEY",
1009 'value_type': "INT",
1010 'description': 'no of ping responses',
1011 'group_tag': 'Group1',
1012 'widget_type': 'COUNTER',
1013 'units': 'packets'
1014 },
1015 ]
1016
1017
1018 def get_pong_mon_params(path):
1019 return [
1020 {
1021 'id': '1',
1022 'name': 'ping-request-rx-count',
1023 'http_endpoint_ref': path,
1024 'json_query_method': "NAMEKEY",
1025 'value_type': "INT",
1026 'description': 'no of ping requests',
1027 'group_tag': 'Group1',
1028 'widget_type': 'COUNTER',
1029 'units': 'packets'
1030 },
1031
1032 {
1033 'id': '2',
1034 'name': 'ping-response-tx-count',
1035 'http_endpoint_ref': path,
1036 'json_query_method': "NAMEKEY",
1037 'value_type': "INT",
1038 'description': 'no of ping responses',
1039 'group_tag': 'Group1',
1040 'widget_type': 'COUNTER',
1041 'units': 'packets'
1042 },
1043 ]
1044
1045
1046 class ScaleGroup(object):
1047 def __init__(self, name, min_count=1, max_count=1):
1048 self.name = name
1049 self.min_count = min_count
1050 self.max_count = max_count
1051 self.vnfd_count_map = {}
1052 self.config_action = {}
1053
1054 def add_vnfd(self, vnfd, vnfd_count):
1055 self.vnfd_count_map[vnfd] = vnfd_count
1056
1057 def add_config(self):
1058 self.config_action['post_scale_out']= {'ns-config-primitive-name-ref':
1059 'ping config'}
1060
1061 class PlacementGroup(object):
1062 def __init__(self, name):
1063 self.name = name
1064 self.strategy = ''
1065 self.requirement = ''
1066
1067 def add_strategy(self, strategy):
1068 self.strategy = strategy
1069
1070 def add_requirement(self, requirement):
1071 self.requirement = requirement
1072
1073 class NsdPlacementGroup(PlacementGroup):
1074 def __init__(self, name):
1075 self.vnfd_list = []
1076 super(NsdPlacementGroup, self).__init__(name)
1077
1078 def add_member(self, vnfd):
1079 self.vnfd_list.append(vnfd)
1080
1081
1082 class VnfdPlacementGroup(PlacementGroup):
1083 def __init__(self, name):
1084 self.vdu_list = []
1085 super(VnfdPlacementGroup, self).__init__(name)
1086
1087 def add_member(self, vdu):
1088 self.vdu_list.append(vdu)
1089
1090
1091
1092
1093 def generate_ping_pong_descriptors(fmt="json",
1094 write_to_file=False,
1095 out_dir="./",
1096 pingcount=NUM_PING_INSTANCES,
1097 external_vlr_count=1,
1098 internal_vlr_count=1,
1099 num_vnf_vms=1,
1100 ping_md5sum=None,
1101 pong_md5sum=None,
1102 mano_ut=False,
1103 use_scale_group=False,
1104 ping_fmt=None,
1105 pong_fmt=None,
1106 nsd_fmt=None,
1107 use_mon_params=True,
1108 ping_userdata=None,
1109 pong_userdata=None,
1110 ex_ping_userdata=None,
1111 ex_pong_userdata=None,
1112 use_placement_group=True,
1113 use_ns_init_conf=True,
1114 use_vca_conf=True,
1115 ):
1116 # List of connection point groups
1117 # Each connection point group refers to a virtual link
1118 # the CP group consists of tuples of connection points
1119 cpgroup_list = []
1120 for i in range(external_vlr_count):
1121 cpgroup_list.append([])
1122
1123 suffix = ''
1124 ping = VirtualNetworkFunction("ping_vnfd%s" % (suffix), pingcount)
1125
1126 if use_placement_group:
1127 ### Add group name Eris
1128 group = VnfdPlacementGroup('Eris')
1129 group.add_strategy('COLOCATION')
1130 group.add_requirement('''Place this VM on the Kuiper belt object Eris''')
1131 ping.add_placement_group(group)
1132
1133 # ping = VirtualNetworkFunction("ping_vnfd", pingcount)
1134 if not ping_userdata:
1135 ping_userdata = PING_USERDATA_FILE
1136
1137 if ex_ping_userdata:
1138 ping_userdata = '''\
1139 {ping_userdata}
1140 {ex_ping_userdata}
1141 '''.format(
1142 ping_userdata=ping_userdata,
1143 ex_ping_userdata=ex_ping_userdata
1144 )
1145
1146 ping.compose(
1147 "Fedora-x86_64-20-20131211.1-sda-ping.qcow2",
1148 ping_userdata,
1149 use_ping_cloud_init_file,
1150 "api/v1/ping/stats",
1151 get_ping_mon_params("api/v1/ping/stats") if use_mon_params else [],
1152 mon_port=18888,
1153 mgmt_port=18888,
1154 num_vlr_count=external_vlr_count,
1155 num_ivlr_count=internal_vlr_count,
1156 num_vms=num_vnf_vms,
1157 image_md5sum=ping_md5sum,
1158 mano_ut=mano_ut,
1159 use_ns_init_conf=use_ns_init_conf,
1160 use_vca_conf=use_vca_conf,
1161 )
1162
1163 pong = VirtualNetworkFunction("pong_vnfd%s" % (suffix))
1164
1165 if use_placement_group:
1166 ### Add group name Weywot
1167 group = VnfdPlacementGroup('Weywot')
1168 group.add_strategy('COLOCATION')
1169 group.add_requirement('''Place this VM on the Kuiper belt object Weywot''')
1170 pong.add_placement_group(group)
1171
1172
1173 # pong = VirtualNetworkFunction("pong_vnfd")
1174
1175 if not pong_userdata:
1176 pong_userdata = PONG_USERDATA_FILE
1177
1178 if ex_pong_userdata:
1179 pong_userdata = '''\
1180 {pong_userdata}
1181 {ex_pong_userdata}
1182 '''.format(
1183 pong_userdata=pong_userdata,
1184 ex_pong_userdata=ex_pong_userdata
1185 )
1186
1187
1188 pong.compose(
1189 "Fedora-x86_64-20-20131211.1-sda-pong.qcow2",
1190 pong_userdata,
1191 use_pong_cloud_init_file,
1192 "api/v1/pong/stats",
1193 get_pong_mon_params("api/v1/pong/stats") if use_mon_params else [],
1194 mon_port=18889,
1195 mgmt_port=18889,
1196 num_vlr_count=external_vlr_count,
1197 num_ivlr_count=internal_vlr_count,
1198 num_vms=num_vnf_vms,
1199 image_md5sum=pong_md5sum,
1200 mano_ut=mano_ut,
1201 use_ns_init_conf=use_ns_init_conf,
1202 use_vca_conf=use_vca_conf,
1203 )
1204
1205 # Initialize the member VNF index
1206 member_vnf_index = 1
1207
1208 # define the connection point groups
1209 for index, cp_group in enumerate(cpgroup_list):
1210 desc_id = ping.descriptor.vnfd[0].id
1211 filename = 'ping_vnfd{}/cp{}'.format(suffix, index)
1212
1213 for idx in range(pingcount):
1214 cp_group.append((
1215 member_vnf_index,
1216 desc_id,
1217 filename,
1218 ))
1219
1220 member_vnf_index += 1
1221
1222 desc_id = pong.descriptor.vnfd[0].id
1223 filename = 'pong_vnfd{}/cp{}'.format(suffix, index)
1224
1225 cp_group.append((
1226 member_vnf_index,
1227 desc_id,
1228 filename,
1229 ))
1230
1231 member_vnf_index += 1
1232
1233 vnfd_list = [ping, pong]
1234
1235 nsd_catalog = NetworkService("ping_pong_nsd%s" % (suffix))
1236
1237 if use_scale_group:
1238 group = ScaleGroup("ping_group", max_count=10)
1239 group.add_vnfd(ping, 1)
1240 group.add_config()
1241 nsd_catalog.add_scale_group(group)
1242
1243 if use_placement_group:
1244 ### Add group name Orcus
1245 group = NsdPlacementGroup('Orcus')
1246 group.add_strategy('COLOCATION')
1247 group.add_requirement('''Place this VM on the Kuiper belt object Orcus''')
1248
1249 for member_vnfd in vnfd_list:
1250 group.add_member(member_vnfd)
1251
1252 nsd_catalog.add_placement_group(group)
1253
1254 ### Add group name Quaoar
1255 group = NsdPlacementGroup('Quaoar')
1256 group.add_strategy('COLOCATION')
1257 group.add_requirement('''Place this VM on the Kuiper belt object Quaoar''')
1258
1259 for member_vnfd in vnfd_list:
1260 group.add_member(member_vnfd)
1261
1262 nsd_catalog.add_placement_group(group)
1263
1264
1265 nsd_catalog.compose(vnfd_list,
1266 cpgroup_list,
1267 mano_ut,
1268 use_ns_init_conf=use_ns_init_conf,
1269 use_vca_conf=use_vca_conf,
1270 )
1271
1272 if write_to_file:
1273 ping.write_to_file(out_dir, ping_fmt if ping_fmt is not None else fmt)
1274 pong.write_to_file(out_dir, pong_fmt if ping_fmt is not None else fmt)
1275 nsd_catalog.write_config(out_dir, vnfd_list)
1276 nsd_catalog.write_to_file(out_dir, ping_fmt if nsd_fmt is not None else fmt)
1277
1278 return (ping, pong, nsd_catalog)
1279
1280
1281 def main(argv=sys.argv[1:]):
1282 global outdir, output_format, use_epa, aws, use_ping_cloud_init_file, use_pong_cloud_init_file
1283 parser = argparse.ArgumentParser()
1284 parser.add_argument('-o', '--outdir', default='.')
1285 parser.add_argument('-f', '--format', default='json')
1286 parser.add_argument('-e', '--epa', action="store_true", default=False)
1287 parser.add_argument('-a', '--aws', action="store_true", default=False)
1288 parser.add_argument('-n', '--pingcount', default=NUM_PING_INSTANCES)
1289 parser.add_argument('--ping-image-md5')
1290 parser.add_argument('--pong-image-md5')
1291 parser.add_argument('--ping-cloud-init', default=None)
1292 parser.add_argument('--pong-cloud-init', default=None)
1293 args = parser.parse_args()
1294 outdir = args.outdir
1295 output_format = args.format
1296 use_epa = args.epa
1297 aws = args.aws
1298 pingcount = args.pingcount
1299 use_ping_cloud_init_file = args.ping_cloud_init
1300 use_pong_cloud_init_file = args.pong_cloud_init
1301
1302 generate_ping_pong_descriptors(args.format, True, args.outdir, pingcount,
1303 ping_md5sum=args.ping_image_md5, pong_md5sum=args.pong_image_md5,
1304 mano_ut=False,
1305 use_scale_group=False,)
1306
1307 if __name__ == "__main__":
1308 main()