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