d84a912e2309ea9ca03d8d8826a6cf152bae4bd5
[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 compose(self, image_name, cloud_init="", cloud_init_file="", endpoint=None, mon_params=[],
129 mon_port=8888, mgmt_port=8888, num_vlr_count=1, num_ivlr_count=1,
130 num_vms=1, image_md5sum=None, mano_ut=False):
131 self.descriptor = RwVnfdYang.YangData_Vnfd_VnfdCatalog()
132 self.id = str(uuid.uuid1())
133 vnfd = self.descriptor.vnfd.add()
134 vnfd.id = self.id
135 vnfd.name = self.name
136 vnfd.short_name = self.name
137 vnfd.vendor = 'RIFT.io'
138 vnfd.logo = 'rift_logo.png'
139 vnfd.description = 'This is an example RIFT.ware VNF'
140 vnfd.version = '1.0'
141
142 self.vnfd = vnfd
143
144 if mano_ut is True:
145 internal_vlds = []
146 for i in range(num_ivlr_count):
147 internal_vld = vnfd.internal_vld.add()
148 internal_vld.id = 'ivld%s' % i
149 internal_vld.name = 'fabric%s' % i
150 internal_vld.short_name = 'fabric%s' % i
151 internal_vld.description = 'Virtual link for internal fabric%s' % i
152 internal_vld.type_yang = 'ELAN'
153 internal_vlds.append(internal_vld)
154
155 for i in range(num_vlr_count):
156 cp = vnfd.connection_point.add()
157 cp.type_yang = 'VPORT'
158 cp.name = '%s/cp%d' % (self.name, i)
159
160 if endpoint is not None:
161 endp = VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd_HttpEndpoint(
162 path=endpoint, port=mon_port, polling_interval_secs=2
163 )
164 vnfd.http_endpoint.append(endp)
165
166 # Monitoring params
167 for monp_dict in mon_params:
168 monp = VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd_MonitoringParam.from_dict(monp_dict)
169 monp.http_endpoint_ref = endpoint
170 vnfd.monitoring_param.append(monp)
171
172
173 for i in range(num_vms):
174 # VDU Specification
175 vdu = vnfd.vdu.add()
176 vdu.id = 'iovdu_%s' % i
177 vdu.name = 'iovdu_%s' % i
178 vdu.count = 1
179 # vdu.mgmt_vpci = '0000:00:20.0'
180
181 # specify the VM flavor
182 if use_epa:
183 vdu.vm_flavor.vcpu_count = 4
184 vdu.vm_flavor.memory_mb = 1024
185 vdu.vm_flavor.storage_gb = 4
186 else:
187 vdu.vm_flavor.vcpu_count = 1
188 vdu.vm_flavor.memory_mb = 512
189 vdu.vm_flavor.storage_gb = 4
190
191 # Management interface
192 mgmt_intf = vnfd.mgmt_interface
193 mgmt_intf.vdu_id = vdu.id
194 mgmt_intf.port = mgmt_port
195 mgmt_intf.dashboard_params.path = endpoint
196 mgmt_intf.dashboard_params.port = mgmt_port
197
198 if cloud_init_file and len(cloud_init_file):
199 vdu.cloud_init_file = cloud_init_file
200 else:
201 vdu.cloud_init = cloud_init
202 if aws:
203 vdu.cloud_init += " - [ systemctl, restart, --no-block, elastic-network-interfaces.service ]\n"
204
205 # sepcify the guest EPA
206 if use_epa:
207 vdu.guest_epa.trusted_execution = False
208 vdu.guest_epa.mempage_size = 'LARGE'
209 vdu.guest_epa.cpu_pinning_policy = 'DEDICATED'
210 vdu.guest_epa.cpu_thread_pinning_policy = 'PREFER'
211 vdu.guest_epa.numa_node_policy.node_cnt = 2
212 vdu.guest_epa.numa_node_policy.mem_policy = 'STRICT'
213
214 node = vdu.guest_epa.numa_node_policy.node.add()
215 node.id = 0
216 node.memory_mb = 512
217 vcpu = node.vcpu.add()
218 vcpu.id = 0
219 vcpu = node.vcpu.add()
220 vcpu.id = 1
221
222 node = vdu.guest_epa.numa_node_policy.node.add()
223 node.id = 1
224 node.memory_mb = 512
225 vcpu = node.vcpu.add()
226 vcpu.id = 2
227 vcpu = node.vcpu.add()
228 vcpu.id = 3
229
230 # specify the vswitch EPA
231 vdu.vswitch_epa.ovs_acceleration = 'DISABLED'
232 vdu.vswitch_epa.ovs_offload = 'DISABLED'
233
234 # Specify the hypervisor EPA
235 vdu.hypervisor_epa.type_yang = 'PREFER_KVM'
236
237 # Specify the host EPA
238 # vdu.host_epa.cpu_model = 'PREFER_SANDYBRIDGE'
239 # vdu.host_epa.cpu_arch = 'PREFER_X86_64'
240 # vdu.host_epa.cpu_vendor = 'PREFER_INTEL'
241 # vdu.host_epa.cpu_socket_count = 2
242 # vdu.host_epa.cpu_core_count = 8
243 # vdu.host_epa.cpu_core_thread_count = 2
244 # vdu.host_epa.cpu_feature = ['PREFER_AES', 'REQUIRE_VME', 'PREFER_MMX','REQUIRE_SSE2']
245
246 if aws:
247 vdu.image = 'rift-ping-pong'
248 else:
249 vdu.image = image_name
250 if image_md5sum is not None:
251 vdu.image_checksum = image_md5sum
252
253 if mano_ut is True:
254 for i in range(num_ivlr_count):
255 internal_cp = vdu.internal_connection_point.add()
256 if vnfd.name.find("ping") >= 0:
257 cp_name = "ping"
258 else:
259 cp_name = "pong"
260 internal_cp.name = cp_name + "/icp{}".format(i)
261 internal_cp.id = cp_name + "/icp{}".format(i)
262 internal_cp.type_yang = 'VPORT'
263 ivld_cp = internal_vlds[i].internal_connection_point_ref.add()
264 ivld_cp.id_ref = internal_cp.id
265
266 internal_interface = vdu.internal_interface.add()
267 internal_interface.name = 'fab%d' % i
268 internal_interface.vdu_internal_connection_point_ref = internal_cp.id
269 internal_interface.virtual_interface.type_yang = 'VIRTIO'
270
271 # internal_interface.virtual_interface.vpci = '0000:00:1%d.0'%i
272
273 for i in range(num_vlr_count):
274 external_interface = vdu.external_interface.add()
275 external_interface.name = 'eth%d' % i
276 external_interface.vnfd_connection_point_ref = '%s/cp%d' % (self.name, i)
277 if use_epa:
278 external_interface.virtual_interface.type_yang = 'VIRTIO'
279 else:
280 external_interface.virtual_interface.type_yang = 'VIRTIO'
281 # external_interface.virtual_interface.vpci = '0000:00:2%d.0'%i
282
283 for group in self._placement_groups:
284 placement_group = vnfd.placement_groups.add()
285 placement_group.name = group.name
286 placement_group.requirement = group.requirement
287 placement_group.strategy = group.strategy
288 if group.vdu_list:
289 ### Add specific VDUs to placement group
290 for vdu in group.vdu_list:
291 member_vdu = placement_group.member_vdus.add()
292 member_vdu.member_vdu_ref = vdu.id
293 else:
294 ### Add all VDUs to placement group
295 for vdu in vnfd.vdu:
296 member_vdu = placement_group.member_vdus.add()
297 member_vdu.member_vdu_ref = vdu.id
298
299
300 def write_to_file(self, outdir, output_format):
301 dirpath = "%s/%s" % (outdir, self.name)
302 if not os.path.exists(dirpath):
303 os.makedirs(dirpath)
304 super(VirtualNetworkFunction, self).write_to_file(['vnfd', 'rw-vnfd'],
305 dirpath,
306 output_format)
307 self.add_scripts(outdir)
308
309 def add_scripts(self, outdir):
310 script_dir = os.path.join(outdir, self.name, 'cloud_init')
311 try:
312 os.makedirs(script_dir)
313 except OSError:
314 if not os.path.isdir(script_dir):
315 raise
316
317 if 'ping' in self.name:
318 script_file = os.path.join(script_dir, 'ping_cloud_init.cfg')
319 cfg = PING_USERDATA_FILE
320 else:
321 script_file = os.path.join(script_dir, 'pong_cloud_init.cfg')
322 cfg = PONG_USERDATA_FILE
323
324 with open(script_file, "w") as f:
325 f.write("{}".format(cfg))
326
327
328 class NetworkService(ManoDescriptor):
329 def __init__(self, name):
330 super(NetworkService, self).__init__(name)
331 self._scale_groups = []
332 self.vnfd_config = {}
333 self._placement_groups = []
334
335 def ping_config(self, mano_ut, use_ns_init_conf):
336 suffix = ''
337 if mano_ut:
338 ping_cfg = r'''
339 #!/bin/bash
340
341 echo "!!!!!!!! Executed ping Configuration !!!!!!!!!"
342 '''
343 else:
344 ping_cfg = r'''
345 #!/bin/bash
346
347 # Rest API config
348 ping_mgmt_ip='<rw_mgmt_ip>'
349 ping_mgmt_port=18888
350
351 # VNF specific configuration
352 pong_server_ip='<rw_connection_point_name pong_vnfd%s/cp0>'
353 ping_rate=5
354 server_port=5555
355
356 # Make rest API calls to configure VNF
357 curl -D /dev/stdout \
358 -H "Accept: application/vnd.yang.data+xml" \
359 -H "Content-Type: application/vnd.yang.data+json" \
360 -X POST \
361 -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
362 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server
363 rc=$?
364 if [ $rc -ne 0 ]
365 then
366 echo "Failed to set server info for ping!"
367 exit $rc
368 fi
369
370 curl -D /dev/stdout \
371 -H "Accept: application/vnd.yang.data+xml" \
372 -H "Content-Type: application/vnd.yang.data+json" \
373 -X POST \
374 -d "{\"rate\":$ping_rate}" \
375 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/rate
376 rc=$?
377 if [ $rc -ne 0 ]
378 then
379 echo "Failed to set ping rate!"
380 exit $rc
381 fi
382
383 ''' % suffix
384 if use_ns_init_conf:
385 ping_cfg += "exit 0\n"
386 else:
387 ping_cfg +='''
388 output=$(curl -D /dev/stdout \
389 -H "Accept: application/vnd.yang.data+xml" \
390 -H "Content-Type: application/vnd.yang.data+json" \
391 -X POST \
392 -d "{\"enable\":true}" \
393 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/adminstatus/state)
394 if [[ $output == *"Internal Server Error"* ]]
395 then
396 echo $output
397 exit 3
398 else
399 echo $output
400 fi
401
402 exit 0
403 '''
404 return ping_cfg
405
406 def pong_config(self, mano_ut, use_ns_init_conf):
407 suffix = ''
408 if mano_ut:
409 pong_cfg = r'''
410 #!/bin/bash
411
412 echo "!!!!!!!! Executed pong Configuration !!!!!!!!!"
413 '''
414 else:
415 pong_cfg = r'''
416 #!/bin/bash
417
418 # Rest API configuration
419 pong_mgmt_ip='<rw_mgmt_ip>'
420 pong_mgmt_port=18889
421 # username=<rw_username>
422 # password=<rw_password>
423
424 # VNF specific configuration
425 pong_server_ip='<rw_connection_point_name pong_vnfd%s/cp0>'
426 server_port=5555
427
428 # Make Rest API calls to configure VNF
429 curl -D /dev/stdout \
430 -H "Accept: application/vnd.yang.data+xml" \
431 -H "Content-Type: application/vnd.yang.data+json" \
432 -X POST \
433 -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
434 http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/server
435 rc=$?
436 if [ $rc -ne 0 ]
437 then
438 echo "Failed to set server(own) info for pong!"
439 exit $rc
440 fi
441
442 ''' % suffix
443
444 if use_ns_init_conf:
445 pong_cfg += "exit 0\n"
446 else:
447 pong_cfg +='''
448 curl -D /dev/stdout \
449 -H "Accept: application/vnd.yang.data+xml" \
450 -H "Content-Type: application/vnd.yang.data+json" \
451 -X POST \
452 -d "{\"enable\":true}" \
453 http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/adminstatus/state
454 rc=$?
455 if [ $rc -ne 0 ]
456 then
457 echo "Failed to enable pong service!"
458 exit $rc
459 fi
460
461 exit 0
462 '''
463 return pong_cfg
464
465 def pong_fake_juju_config(self, vnf_config):
466
467 if vnf_config:
468 # Select "script" configuration
469 vnf_config.juju.charm = 'clearwater-aio-proxy'
470
471 # Set the initital-config
472 vnf_config.create_initial_config_primitive()
473 init_config = VnfdYang.InitialConfigPrimitive.from_dict({
474 "seq": 1,
475 "name": "config",
476 "parameter": [
477 {"name": "proxied_ip", "value": "<rw_mgmt_ip>"},
478 ]
479 })
480 vnf_config.initial_config_primitive.append(init_config)
481
482 init_config_action = VnfdYang.InitialConfigPrimitive.from_dict({
483 "seq": 2,
484 "name": "action1",
485 "parameter": [
486 {"name": "Pong Connection Point", "value": "pong_vnfd/cp0"},
487 ]
488 })
489 vnf_config.initial_config_primitive.append(init_config_action)
490 init_config_action = VnfdYang.InitialConfigPrimitive.from_dict({
491 "seq": 3,
492 "name": "action2",
493 "parameter": [
494 {"name": "Ping Connection Point", "value": "ping_vnfd/cp0"},
495 ]
496 })
497 vnf_config.initial_config_primitive.append(init_config_action)
498
499 # Config parameters can be taken from config.yaml and
500 # actions from actions.yaml in the charm
501 # Config to set the home domain
502 vnf_config.create_service_primitive()
503 config = VnfdYang.ServicePrimitive.from_dict({
504 "name": "config",
505 "parameter": [
506 {"name": "home_domain", "data_type": "STRING"},
507 {"name": "base_number", "data_type": "STRING"},
508 {"name": "number_count", "data_type": "INTEGER"},
509 {"name": "password", "data_type": "STRING"},
510 ]
511 })
512 vnf_config.service_primitive.append(config)
513
514 config = VnfdYang.ServicePrimitive.from_dict({
515 "name": "create-update-user",
516 # "user-defined-script":"/tmp/test.py",
517 "parameter": [
518 {"name": "number", "data_type": "STRING", "mandatory": True},
519 {"name": "password", "data_type": "STRING", "mandatory": True},
520 ]
521 })
522 vnf_config.service_primitive.append(config)
523
524 config = VnfdYang.ServicePrimitive.from_dict({
525 "name": "delete-user",
526 "parameter": [
527 {"name": "number", "data_type": "STRING", "mandatory": True},
528 ]
529 })
530 vnf_config.service_primitive.append(config)
531
532 def default_config(self, const_vnfd, vnfd, mano_ut, use_ns_init_conf):
533 vnf_config = vnfd.vnfd.vnf_configuration
534
535 vnf_config.config_attributes.config_priority = 0
536 vnf_config.config_attributes.config_delay = 0
537
538 # Select "script" configuration
539 vnf_config.script.script_type = 'bash'
540
541 if vnfd.name == 'pong_vnfd' or vnfd.name == 'pong_vnfd_with_epa' or vnfd.name == 'pong_vnfd_aws':
542 vnf_config.config_attributes.config_priority = 1
543 vnf_config.config_template = self.pong_config(mano_ut, use_ns_init_conf)
544 # First priority config delay will delay the entire NS config delay
545 if mano_ut is False:
546 vnf_config.config_attributes.config_delay = 60
547 else:
548 # This is PONG and inside mano_ut
549 # This is test only
550 vnf_config.config_attributes.config_delay = 10
551 # vnf_config.config_template = self.pong_config(vnf_config, use_ns_init_conf)
552
553 if vnfd.name == 'ping_vnfd' or vnfd.name == 'ping_vnfd_with_epa' or vnfd.name == 'ping_vnfd_aws':
554 vnf_config.config_attributes.config_priority = 2
555 vnf_config.config_template = self.ping_config(mano_ut, use_ns_init_conf)
556
557 def ns_config(self, nsd, vnfd_list, mano_ut):
558 # Used by scale group
559 if mano_ut:
560 nsd.service_primitive.add().from_dict(
561 {
562 "name": "ping config",
563 "user_defined_script": "{}".format(os.path.join(
564 os.environ['RIFT_ROOT'],
565 'modules/core/mano',
566 'examples/ping_pong_ns/rift/mano/examples',
567 'ping_config_ut.sh'))
568 })
569 else:
570 nsd.service_primitive.add().from_dict(
571 {
572 "name": "ping config",
573 "user_defined_script": "ping_config.py"
574 })
575
576 def ns_initial_config(self, nsd):
577 nsd.initial_config_primitive.add().from_dict(
578 {
579 "seq": 1,
580 "name": "start traffic",
581 "user_defined_script": "start_traffic.py",
582 "parameter": [
583 {
584 'name': 'userid',
585 'value': 'rift',
586 },
587 ],
588 }
589 )
590
591 def add_scale_group(self, scale_group):
592 self._scale_groups.append(scale_group)
593
594 def add_placement_group(self, placement_group):
595 self._placement_groups.append(placement_group)
596
597 def create_mon_params(self, vnfds):
598 NsdMonParam = NsdYang.YangData_Nsd_NsdCatalog_Nsd_MonitoringParam
599 param_id = 1
600 for vnfd_obj in vnfds:
601 for mon_param in vnfd_obj.vnfd.monitoring_param:
602 nsd_monp = NsdMonParam.from_dict({
603 'id': str(param_id),
604 'name': mon_param.name,
605 'aggregation_type': "AVERAGE",
606 'value_type': mon_param.value_type,
607 'vnfd_monitoring_param': [
608 {'vnfd_id_ref': vnfd_obj.vnfd.id,
609 'vnfd_monitoring_param_ref': mon_param.id}]
610 })
611
612 self.nsd.monitoring_param.append(nsd_monp)
613 param_id += 1
614
615
616
617
618 def compose(self, vnfd_list, cpgroup_list, mano_ut, use_ns_init_conf=True):
619
620 if mano_ut:
621 # Disable NS initial config primitive
622 use_ns_init_conf=False
623
624 self.descriptor = RwNsdYang.YangData_Nsd_NsdCatalog()
625 self.id = str(uuid.uuid1())
626 nsd = self.descriptor.nsd.add()
627 self.nsd = nsd
628 nsd.id = self.id
629 nsd.name = self.name
630 nsd.short_name = self.name
631 nsd.vendor = 'RIFT.io'
632 nsd.logo = 'rift_logo.png'
633 nsd.description = 'Toy NS'
634 nsd.version = '1.0'
635 nsd.input_parameter_xpath.append(
636 NsdYang.YangData_Nsd_NsdCatalog_Nsd_InputParameterXpath(
637 xpath="/nsd:nsd-catalog/nsd:nsd/nsd:vendor",
638 )
639 )
640
641 ip_profile = nsd.ip_profiles.add()
642 ip_profile.name = "InterVNFLink"
643 ip_profile.description = "Inter VNF Link"
644 ip_profile.ip_profile_params.ip_version = "ipv4"
645 ip_profile.ip_profile_params.subnet_address = "31.31.31.0/24"
646 ip_profile.ip_profile_params.gateway_address = "31.31.31.210"
647
648 vld_id = 1
649 for cpgroup in cpgroup_list:
650 vld = nsd.vld.add()
651 vld.id = 'ping_pong_vld%s' % vld_id
652 vld_id += 1
653 vld.name = 'ping_pong_vld' # hard coded
654 vld.short_name = vld.name
655 vld.vendor = 'RIFT.io'
656 vld.description = 'Toy VL'
657 vld.version = '1.0'
658 vld.type_yang = 'ELAN'
659 vld.ip_profile_ref = 'InterVNFLink'
660 for cp in cpgroup:
661 cpref = vld.vnfd_connection_point_ref.add()
662 cpref.member_vnf_index_ref = cp[0]
663 cpref.vnfd_id_ref = cp[1]
664 cpref.vnfd_connection_point_ref = cp[2]
665
666 vnfd_index_map = {}
667 member_vnf_index = 1
668 for vnfd in vnfd_list:
669 for i in range(vnfd.instance_count):
670 constituent_vnfd = nsd.constituent_vnfd.add()
671 constituent_vnfd.member_vnf_index = member_vnf_index
672 vnfd_index_map[vnfd] = member_vnf_index
673
674 # Set the start by default to false for ping vnfd,
675 # if scaling is enabled
676 if (len(self._scale_groups) and
677 vnfd.descriptor.vnfd[0].name == 'ping_vnfd'):
678 constituent_vnfd.start_by_default = False
679
680 constituent_vnfd.vnfd_id_ref = vnfd.descriptor.vnfd[0].id
681 self.default_config(constituent_vnfd, vnfd, mano_ut,
682 use_ns_init_conf,)
683 member_vnf_index += 1
684
685 # Enable config primitives if either mano_ut or
686 # scale groups are enabled
687 if mano_ut or len(self._scale_groups):
688 self.ns_config(nsd, vnfd_list, mano_ut)
689
690 # Add NS initial config to start traffic
691 if use_ns_init_conf:
692 self.ns_initial_config(nsd)
693
694 for scale_group in self._scale_groups:
695 group_desc = nsd.scaling_group_descriptor.add()
696 group_desc.name = scale_group.name
697 group_desc.max_instance_count = scale_group.max_count
698 group_desc.min_instance_count = scale_group.min_count
699 for vnfd, count in scale_group.vnfd_count_map.items():
700 member = group_desc.vnfd_member.add()
701 member.member_vnf_index_ref = vnfd_index_map[vnfd]
702 member.count = count
703
704 for trigger in scale_group.config_action:
705 config_action = group_desc.scaling_config_action.add()
706 config_action.trigger = trigger
707 config = scale_group.config_action[trigger]
708 config_action.ns_config_primitive_name_ref = config['ns-config-primitive-name-ref']
709
710 for placement_group in self._placement_groups:
711 group = nsd.placement_groups.add()
712 group.name = placement_group.name
713 group.strategy = placement_group.strategy
714 group.requirement = placement_group.requirement
715 for member_vnfd in placement_group.vnfd_list:
716 member = group.member_vnfd.add()
717 member.vnfd_id_ref = member_vnfd.descriptor.vnfd[0].id
718 member.member_vnf_index_ref = vnfd_index_map[member_vnfd]
719
720 # self.create_mon_params(vnfd_list)
721
722 def write_config(self, outdir, vnfds):
723
724 converter = config_data.ConfigPrimitiveConvertor()
725 yaml_data = converter.extract_nsd_config(self.nsd)
726
727 ns_config_dir = os.path.join(outdir, self.name, "ns_config")
728 os.makedirs(ns_config_dir, exist_ok=True)
729 vnf_config_dir = os.path.join(outdir, self.name, "vnf_config")
730 os.makedirs(vnf_config_dir, exist_ok=True)
731
732 if len(yaml_data):
733 with open('%s/%s.yaml' % (ns_config_dir, self.id), "w") as fh:
734 fh.write(yaml_data)
735
736 for i, vnfd in enumerate(vnfds, start=1):
737 yaml_data = converter.extract_vnfd_config(vnfd)
738
739 if len(yaml_data):
740 with open('%s/%s__%s.yaml' % (vnf_config_dir, vnfd.id, i), "w") as fh:
741 fh.write(yaml_data)
742
743 def write_initial_config_script(self, outdir):
744 script_name = 'start_traffic.py'
745
746 src_path = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
747 script_src = os.path.join(src_path, script_name)
748 if not os.path.exists(script_src):
749 src_path = os.path.join(os.environ['RIFT_ROOT'],
750 'modules/core/mano/examples/ping_pong_ns/rift/mano/examples')
751 script_src = os.path.join(src_path, script_name)
752
753 dest_path = os.path.join(outdir, 'scripts')
754 os.makedirs(dest_path, exist_ok=True)
755
756 shutil.copy2(script_src, dest_path)
757
758 def write_to_file(self, outdir, output_format):
759 dirpath = os.path.join(outdir, self.name)
760 if not os.path.exists(dirpath):
761 os.makedirs(dirpath)
762
763 super(NetworkService, self).write_to_file(["nsd", "rw-nsd"],
764 dirpath,
765 output_format)
766
767 # Write the initial config script
768 self.write_initial_config_script(dirpath)
769
770
771 def get_ping_mon_params(path):
772 return [
773 {
774 'id': '1',
775 'name': 'ping-request-tx-count',
776 'http_endpoint_ref': path,
777 'json_query_method': "NAMEKEY",
778 'value_type': "INT",
779 'description': 'no of ping requests',
780 'group_tag': 'Group1',
781 'widget_type': 'COUNTER',
782 'units': 'packets'
783 },
784
785 {
786 'id': '2',
787 'name': 'ping-response-rx-count',
788 'http_endpoint_ref': path,
789 'json_query_method': "NAMEKEY",
790 'value_type': "INT",
791 'description': 'no of ping responses',
792 'group_tag': 'Group1',
793 'widget_type': 'COUNTER',
794 'units': 'packets'
795 },
796 ]
797
798
799 def get_pong_mon_params(path):
800 return [
801 {
802 'id': '1',
803 'name': 'ping-request-rx-count',
804 'http_endpoint_ref': path,
805 'json_query_method': "NAMEKEY",
806 'value_type': "INT",
807 'description': 'no of ping requests',
808 'group_tag': 'Group1',
809 'widget_type': 'COUNTER',
810 'units': 'packets'
811 },
812
813 {
814 'id': '2',
815 'name': 'ping-response-tx-count',
816 'http_endpoint_ref': path,
817 'json_query_method': "NAMEKEY",
818 'value_type': "INT",
819 'description': 'no of ping responses',
820 'group_tag': 'Group1',
821 'widget_type': 'COUNTER',
822 'units': 'packets'
823 },
824 ]
825
826
827 class ScaleGroup(object):
828 def __init__(self, name, min_count=1, max_count=1):
829 self.name = name
830 self.min_count = min_count
831 self.max_count = max_count
832 self.vnfd_count_map = {}
833 self.config_action = {}
834
835 def add_vnfd(self, vnfd, vnfd_count):
836 self.vnfd_count_map[vnfd] = vnfd_count
837
838 def add_config(self):
839 self.config_action['post_scale_out']= {'ns-config-primitive-name-ref':
840 'ping config'}
841
842 class PlacementGroup(object):
843 def __init__(self, name):
844 self.name = name
845 self.strategy = ''
846 self.requirement = ''
847
848 def add_strategy(self, strategy):
849 self.strategy = strategy
850
851 def add_requirement(self, requirement):
852 self.requirement = requirement
853
854 class NsdPlacementGroup(PlacementGroup):
855 def __init__(self, name):
856 self.vnfd_list = []
857 super(NsdPlacementGroup, self).__init__(name)
858
859 def add_member(self, vnfd):
860 self.vnfd_list.append(vnfd)
861
862
863 class VnfdPlacementGroup(PlacementGroup):
864 def __init__(self, name):
865 self.vdu_list = []
866 super(VnfdPlacementGroup, self).__init__(name)
867
868 def add_member(self, vdu):
869 self.vdu_list.append(vdu)
870
871
872
873
874 def generate_ping_pong_descriptors(fmt="json",
875 write_to_file=False,
876 out_dir="./",
877 pingcount=NUM_PING_INSTANCES,
878 external_vlr_count=1,
879 internal_vlr_count=1,
880 num_vnf_vms=1,
881 ping_md5sum=None,
882 pong_md5sum=None,
883 mano_ut=False,
884 use_scale_group=False,
885 ping_fmt=None,
886 pong_fmt=None,
887 nsd_fmt=None,
888 use_mon_params=True,
889 ping_userdata=None,
890 pong_userdata=None,
891 ex_ping_userdata=None,
892 ex_pong_userdata=None,
893 use_placement_group=True,
894 use_ns_init_conf=True,
895 ):
896 # List of connection point groups
897 # Each connection point group refers to a virtual link
898 # the CP group consists of tuples of connection points
899 cpgroup_list = []
900 for i in range(external_vlr_count):
901 cpgroup_list.append([])
902
903 suffix = ''
904 ping = VirtualNetworkFunction("ping_vnfd%s" % (suffix), pingcount)
905
906 if use_placement_group:
907 ### Add group name Eris
908 group = VnfdPlacementGroup('Eris')
909 group.add_strategy('COLOCATION')
910 group.add_requirement('''Place this VM on the Kuiper belt object Eris''')
911 ping.add_placement_group(group)
912
913 # ping = VirtualNetworkFunction("ping_vnfd", pingcount)
914 if not ping_userdata:
915 ping_userdata = PING_USERDATA_FILE
916
917 if ex_ping_userdata:
918 ping_userdata = '''\
919 {ping_userdata}
920 {ex_ping_userdata}
921 '''.format(
922 ping_userdata=ping_userdata,
923 ex_ping_userdata=ex_ping_userdata
924 )
925
926 ping.compose(
927 "Fedora-x86_64-20-20131211.1-sda-ping.qcow2",
928 ping_userdata,
929 use_ping_cloud_init_file,
930 "api/v1/ping/stats",
931 get_ping_mon_params("api/v1/ping/stats") if use_mon_params else [],
932 mon_port=18888,
933 mgmt_port=18888,
934 num_vlr_count=external_vlr_count,
935 num_ivlr_count=internal_vlr_count,
936 num_vms=num_vnf_vms,
937 image_md5sum=ping_md5sum,
938 mano_ut=mano_ut,
939 )
940
941 pong = VirtualNetworkFunction("pong_vnfd%s" % (suffix))
942
943 if use_placement_group:
944 ### Add group name Weywot
945 group = VnfdPlacementGroup('Weywot')
946 group.add_strategy('COLOCATION')
947 group.add_requirement('''Place this VM on the Kuiper belt object Weywot''')
948 pong.add_placement_group(group)
949
950
951 # pong = VirtualNetworkFunction("pong_vnfd")
952
953 if not pong_userdata:
954 pong_userdata = PONG_USERDATA_FILE
955
956 if ex_pong_userdata:
957 pong_userdata = '''\
958 {pong_userdata}
959 {ex_pong_userdata}
960 '''.format(
961 pong_userdata=pong_userdata,
962 ex_pong_userdata=ex_pong_userdata
963 )
964
965
966 pong.compose(
967 "Fedora-x86_64-20-20131211.1-sda-pong.qcow2",
968 pong_userdata,
969 use_pong_cloud_init_file,
970 "api/v1/pong/stats",
971 get_pong_mon_params("api/v1/pong/stats") if use_mon_params else [],
972 mon_port=18889,
973 mgmt_port=18889,
974 num_vlr_count=external_vlr_count,
975 num_ivlr_count=internal_vlr_count,
976 num_vms=num_vnf_vms,
977 image_md5sum=pong_md5sum,
978 mano_ut=mano_ut,
979 )
980
981 # Initialize the member VNF index
982 member_vnf_index = 1
983
984 # define the connection point groups
985 for index, cp_group in enumerate(cpgroup_list):
986 desc_id = ping.descriptor.vnfd[0].id
987 filename = 'ping_vnfd{}/cp{}'.format(suffix, index)
988
989 for idx in range(pingcount):
990 cp_group.append((
991 member_vnf_index,
992 desc_id,
993 filename,
994 ))
995
996 member_vnf_index += 1
997
998 desc_id = pong.descriptor.vnfd[0].id
999 filename = 'pong_vnfd{}/cp{}'.format(suffix, index)
1000
1001 cp_group.append((
1002 member_vnf_index,
1003 desc_id,
1004 filename,
1005 ))
1006
1007 member_vnf_index += 1
1008
1009 vnfd_list = [ping, pong]
1010
1011 nsd_catalog = NetworkService("ping_pong_nsd%s" % (suffix))
1012
1013 if use_scale_group:
1014 group = ScaleGroup("ping_group", max_count=10)
1015 group.add_vnfd(ping, 1)
1016 group.add_config()
1017 nsd_catalog.add_scale_group(group)
1018
1019 if use_placement_group:
1020 ### Add group name Orcus
1021 group = NsdPlacementGroup('Orcus')
1022 group.add_strategy('COLOCATION')
1023 group.add_requirement('''Place this VM on the Kuiper belt object Orcus''')
1024
1025 for member_vnfd in vnfd_list:
1026 group.add_member(member_vnfd)
1027
1028 nsd_catalog.add_placement_group(group)
1029
1030 ### Add group name Quaoar
1031 group = NsdPlacementGroup('Quaoar')
1032 group.add_strategy('COLOCATION')
1033 group.add_requirement('''Place this VM on the Kuiper belt object Quaoar''')
1034
1035 for member_vnfd in vnfd_list:
1036 group.add_member(member_vnfd)
1037
1038 nsd_catalog.add_placement_group(group)
1039
1040
1041 nsd_catalog.compose(vnfd_list,
1042 cpgroup_list,
1043 mano_ut,
1044 use_ns_init_conf=use_ns_init_conf,)
1045
1046 if write_to_file:
1047 ping.write_to_file(out_dir, ping_fmt if ping_fmt is not None else fmt)
1048 pong.write_to_file(out_dir, pong_fmt if ping_fmt is not None else fmt)
1049 nsd_catalog.write_config(out_dir, vnfd_list)
1050 nsd_catalog.write_to_file(out_dir, ping_fmt if nsd_fmt is not None else fmt)
1051
1052 return (ping, pong, nsd_catalog)
1053
1054
1055 def main(argv=sys.argv[1:]):
1056 global outdir, output_format, use_epa, aws, use_ping_cloud_init_file, use_pong_cloud_init_file
1057 parser = argparse.ArgumentParser()
1058 parser.add_argument('-o', '--outdir', default='.')
1059 parser.add_argument('-f', '--format', default='json')
1060 parser.add_argument('-e', '--epa', action="store_true", default=False)
1061 parser.add_argument('-a', '--aws', action="store_true", default=False)
1062 parser.add_argument('-n', '--pingcount', default=NUM_PING_INSTANCES)
1063 parser.add_argument('--ping-image-md5')
1064 parser.add_argument('--pong-image-md5')
1065 parser.add_argument('--ping-cloud-init', default=None)
1066 parser.add_argument('--pong-cloud-init', default=None)
1067 args = parser.parse_args()
1068 outdir = args.outdir
1069 output_format = args.format
1070 use_epa = args.epa
1071 aws = args.aws
1072 pingcount = args.pingcount
1073 use_ping_cloud_init_file = args.ping_cloud_init
1074 use_pong_cloud_init_file = args.pong_cloud_init
1075
1076 generate_ping_pong_descriptors(args.format, True, args.outdir, pingcount,
1077 ping_md5sum=args.ping_image_md5, pong_md5sum=args.pong_image_md5,
1078 mano_ut=False,
1079 use_scale_group=False,)
1080
1081 if __name__ == "__main__":
1082 main()