4 # Copyright 2016 RIFT.IO Inc
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
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')
34 from gi
.repository
import (
44 import rift
.mano
.config_data
.config
as config_data
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")
50 import config_data
.config
as config_data
53 NUM_PING_INSTANCES
= 1
54 MAX_VNF_INSTANCES_PER_NS
= 10
57 pingcount
= NUM_PING_INSTANCES
58 use_ping_cloud_init_file
= ""
59 use_pong_cloud_init_file
= ""
61 PING_USERDATA_FILE
= '''#cloud-config
63 chpasswd: { expire: False }
66 - [ systemctl, daemon-reload ]
67 - [ systemctl, enable, ping.service ]
68 - [ systemctl, start, --no-block, ping.service ]
72 PONG_USERDATA_FILE
= '''#cloud-config
74 chpasswd: { expire: False }
77 - [ systemctl, daemon-reload ]
78 - [ systemctl, enable, pong.service ]
79 - [ systemctl, start, --no-block, pong.service ]
84 class UnknownVNFError(Exception):
88 class ManoDescriptor(object):
89 def __init__(self
, name
):
91 self
.descriptor
= None
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
)
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
))
108 raise Exception("Invalid output format for the descriptor")
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
))
117 class VirtualNetworkFunction(ManoDescriptor
):
118 def __init__(self
, name
, instance_count
=1):
119 self
.vnfd_catalog
= None
121 self
.instance_count
= instance_count
122 self
._placement
_groups
= []
123 super(VirtualNetworkFunction
, self
).__init
__(name
)
125 def add_placement_group(self
, group
):
126 self
._placement
_groups
.append(group
)
128 def add_vnf_access_point(self
, mano_ut
=False):
129 vnfd
= self
.descriptor
.vnfd
[0]
131 cap
= vnfap
.create_capability()
134 "description": "Management address",
135 "attribute": "../../../../mgmt-interface, ip-address",
137 vnfap
.capability
.append(cap
)
138 cap
= vnfap
.create_capability()
141 "description": "Management port",
142 "xpath": "../../../../mgmt-interface/port",
144 vnfap
.capability
.append(cap
)
145 cap
= vnfap
.create_capability()
148 "description": "Management username",
151 vnfap
.capability
.append(cap
)
152 cap
= vnfap
.create_capability()
155 "description": "Management password",
158 vnfap
.capability
.append(cap
)
161 if 'pong_' in self
.name
:
162 cap
= vnfap
.create_capability()
164 "name": "service_ip",
165 "description": "IP on which Pong service is listening",
166 "attribute": "../../../../connection-point[name='pong_vnfd/cp0'], ip-address"
168 vnfap
.capability
.append(cap
)
169 cap
= vnfap
.create_capability()
171 "name": "service_port",
172 "description": "Port on which server listens for incoming data packets",
175 vnfap
.capability
.append(cap
)
178 cap
= vnfap
.create_capability()
181 "description": "Rate of packet generation",
184 vnfap
.capability
.append(cap
)
186 dep
= vnfap
.create_dependency()
188 "name": "service_ip",
189 "description": "IP on which Pong service is listening",
192 dep
.config_primitive_name_ref
.append('config')
193 vnfap
.dependency
.append(dep
)
194 dep
= vnfap
.create_dependency()
196 "name": "service_port",
197 "description": "Port on which Pong service is listening",
200 dep
.config_primitive_name_ref
.append('config')
201 vnfap
.dependency
.append(dep
)
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
208 vnf_config
.config_attributes
.config_delay
= 60
210 # Add config primitive
211 vnf_config
.create_config_primitive()
212 prim
= VnfdYang
.ConfigPrimitive
.from_dict({
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"},
223 "user_defined_script": "ping-setup.py",
225 vnf_config
.config_primitive
.append(prim
)
227 prim
= VnfdYang
.ConfigPrimitive
.from_dict({
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"},
237 "user_defined_script": "ping-set-rate.py",
239 vnf_config
.config_primitive
.append(prim
)
241 prim
= VnfdYang
.ConfigPrimitive
.from_dict({
242 "name": "start-stop",
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"}
251 "user_defined_script": "ping-start-stop.py",
253 vnf_config
.config_primitive
.append(prim
)
255 # Add initial config primitive
256 vnf_config
.create_initial_config_primitive()
257 init_config
= VnfdYang
.InitialConfigPrimitive
.from_dict(
260 "config_primitive_ref": "config",
263 vnf_config
.initial_config_primitive
.append(init_config
)
265 init_config
= VnfdYang
.InitialConfigPrimitive
.from_dict(
268 "config_primitive_ref": "set-rate",
271 vnf_config
.initial_config_primitive
.append(init_config
)
273 if use_ns_init_conf
is False:
274 init_config
= VnfdYang
.InitialConfigPrimitive
.from_dict(
277 "config_primitive_ref": "start-stop",
280 vnf_config
.initial_config_primitive
.append(init_config
)
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
287 # Add config primitive
288 vnf_config
.create_config_primitive()
289 prim
= VnfdYang
.ConfigPrimitive
.from_dict({
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"},
299 "user_defined_script": "ping-setup.py",
301 vnf_config
.config_primitive
.append(prim
)
303 prim
= VnfdYang
.ConfigPrimitive
.from_dict({
304 "name": "start-stop",
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"}
313 "user_defined_script": "ping-start-stop.py",
315 vnf_config
.config_primitive
.append(prim
)
317 # Add initial config primitive
318 vnf_config
.create_initial_config_primitive()
319 init_config
= VnfdYang
.InitialConfigPrimitive
.from_dict(
322 "config_primitive_ref": "config",
325 vnf_config
.initial_config_primitive
.append(init_config
)
327 if use_ns_init_conf
is False:
328 init_config
= VnfdYang
.InitialConfigPrimitive
.from_dict(
331 "config_primitive_ref": "start-stop",
334 vnf_config
.initial_config_primitive
.append(init_config
)
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,
340 self
.descriptor
= RwVnfdYang
.YangData_Vnfd_VnfdCatalog()
341 self
.id = str(uuid
.uuid1())
342 vnfd
= self
.descriptor
.vnfd
.add()
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'
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
)
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
)
369 if endpoint
is not None:
370 endp
= VnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd_HttpEndpoint(
371 path
=endpoint
, port
=mon_port
, polling_interval_secs
=2
373 vnfd
.http_endpoint
.append(endp
)
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
)
382 for i
in range(num_vms
):
385 vdu
.id = 'iovdu_%s' % i
386 vdu
.name
= 'iovdu_%s' % i
388 # vdu.mgmt_vpci = '0000:00:20.0'
390 # specify the VM flavor
392 vdu
.vm_flavor
.vcpu_count
= 4
393 vdu
.vm_flavor
.memory_mb
= 1024
394 vdu
.vm_flavor
.storage_gb
= 4
396 vdu
.vm_flavor
.vcpu_count
= 1
397 vdu
.vm_flavor
.memory_mb
= 512
398 vdu
.vm_flavor
.storage_gb
= 4
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
407 if cloud_init_file
and len(cloud_init_file
):
408 vdu
.cloud_init_file
= cloud_init_file
410 vdu
.cloud_init
= cloud_init
412 vdu
.cloud_init
+= " - [ systemctl, restart, --no-block, elastic-network-interfaces.service ]\n"
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
)
419 self
.add_ping_config(mano_ut
=mano_ut
, use_ns_init_conf
=use_ns_init_conf
)
421 # sepcify the guest 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'
430 node
= vdu
.guest_epa
.numa_node_policy
.node
.add()
433 vcpu
= node
.vcpu
.add()
435 vcpu
= node
.vcpu
.add()
438 node
= vdu
.guest_epa
.numa_node_policy
.node
.add()
441 vcpu
= node
.vcpu
.add()
443 vcpu
= node
.vcpu
.add()
446 # specify the vswitch EPA
447 vdu
.vswitch_epa
.ovs_acceleration
= 'DISABLED'
448 vdu
.vswitch_epa
.ovs_offload
= 'DISABLED'
450 # Specify the hypervisor EPA
451 vdu
.hypervisor_epa
.type_yang
= 'PREFER_KVM'
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']
463 vdu
.image
= 'rift-ping-pong'
465 vdu
.image
= image_name
466 if image_md5sum
is not None:
467 vdu
.image_checksum
= image_md5sum
470 for i
in range(num_ivlr_count
):
471 internal_cp
= vdu
.internal_connection_point
.add()
472 if vnfd
.name
.find("ping") >= 0:
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
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'
487 # internal_interface.virtual_interface.vpci = '0000:00:1%d.0'%i
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
)
494 external_interface
.virtual_interface
.type_yang
= 'VIRTIO'
496 external_interface
.virtual_interface
.type_yang
= 'VIRTIO'
497 # external_interface.virtual_interface.vpci = '0000:00:2%d.0'%i
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
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
510 ### Add all VDUs to placement group
512 member_vdu
= placement_group
.member_vdus
.add()
513 member_vdu
.member_vdu_ref
= vdu
.id
516 def write_to_file(self
, outdir
, output_format
):
517 dirpath
= "%s/%s" % (outdir
, self
.name
)
518 if not os
.path
.exists(dirpath
):
520 super(VirtualNetworkFunction
, self
).write_to_file(['vnfd', 'rw-vnfd'],
523 self
.add_scripts(outdir
)
525 def add_scripts(self
, outdir
):
526 script_dir
= os
.path
.join(outdir
, self
.name
, 'cloud_init')
528 os
.makedirs(script_dir
)
530 if not os
.path
.isdir(script_dir
):
533 if 'ping' in self
.name
:
534 script_file
= os
.path
.join(script_dir
, 'ping_cloud_init.cfg')
535 cfg
= PING_USERDATA_FILE
537 script_file
= os
.path
.join(script_dir
, 'pong_cloud_init.cfg')
538 cfg
= PONG_USERDATA_FILE
540 with
open(script_file
, "w") as f
:
541 f
.write("{}".format(cfg
))
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
= []
551 def ping_config(self
, mano_ut
, use_ns_init_conf
):
557 echo "!!!!!!!! Executed ping Configuration !!!!!!!!!"
564 ping_mgmt_ip='<rw_mgmt_ip>'
567 # VNF specific configuration
568 pong_server_ip='<rw_connection_point_name pong_vnfd%s/cp0>'
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" \
577 -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
578 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server
582 echo "Failed to set server info for ping!"
586 curl -D /dev/stdout \
587 -H "Accept: application/vnd.yang.data+xml" \
588 -H "Content-Type: application/vnd.yang.data+json" \
590 -d "{\"rate\":$ping_rate}" \
591 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/rate
595 echo "Failed to set ping rate!"
601 ping_cfg
+= "exit 0\n"
604 output=$(curl -D /dev/stdout \
605 -H "Accept: application/vnd.yang.data+xml" \
606 -H "Content-Type: application/vnd.yang.data+json" \
608 -d "{\"enable\":true}" \
609 http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/adminstatus/state)
610 if [[ $output == *"Internal Server Error"* ]]
622 def pong_config(self
, mano_ut
, use_ns_init_conf
):
628 echo "!!!!!!!! Executed pong Configuration !!!!!!!!!"
634 # Rest API configuration
635 pong_mgmt_ip='<rw_mgmt_ip>'
637 # username=<rw_username>
638 # password=<rw_password>
640 # VNF specific configuration
641 pong_server_ip='<rw_connection_point_name pong_vnfd%s/cp0>'
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" \
649 -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \
650 http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/server
654 echo "Failed to set server(own) info for pong!"
661 pong_cfg
+= "exit 0\n"
664 curl -D /dev/stdout \
665 -H "Accept: application/vnd.yang.data+xml" \
666 -H "Content-Type: application/vnd.yang.data+json" \
668 -d "{\"enable\":true}" \
669 http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/adminstatus/state
673 echo "Failed to enable pong service!"
681 def pong_fake_juju_config(self
, vnf_config
):
684 # Select "script" configuration
685 vnf_config
.juju
.charm
= 'clearwater-aio-proxy'
687 # Set the initital-config
688 vnf_config
.create_initial_config_primitive()
689 init_config
= VnfdYang
.InitialConfigPrimitive
.from_dict({
693 {"name": "proxied_ip", "value": "<rw_mgmt_ip>"},
696 vnf_config
.initial_config_primitive
.append(init_config
)
698 init_config_action
= VnfdYang
.InitialConfigPrimitive
.from_dict({
702 {"name": "Pong Connection Point", "value": "pong_vnfd/cp0"},
705 vnf_config
.initial_config_primitive
.append(init_config_action
)
706 init_config_action
= VnfdYang
.InitialConfigPrimitive
.from_dict({
710 {"name": "Ping Connection Point", "value": "ping_vnfd/cp0"},
713 vnf_config
.initial_config_primitive
.append(init_config_action
)
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({
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"},
728 vnf_config
.config_primitive
.append(config
)
730 config
= VnfdYang
.ConfigPrimitive
.from_dict({
731 "name": "create-update-user",
732 # "user-defined-script":"/tmp/test.py",
734 {"name": "number", "data_type": "STRING", "mandatory": True},
735 {"name": "password", "data_type": "STRING", "mandatory": True},
738 vnf_config
.config_primitive
.append(config
)
740 config
= VnfdYang
.ConfigPrimitive
.from_dict({
741 "name": "delete-user",
743 {"name": "number", "data_type": "STRING", "mandatory": True},
746 vnf_config
.config_primitive
.append(config
)
748 def default_config(self
, const_vnfd
, vnfd
, mano_ut
, use_ns_init_conf
):
749 vnf_config
= vnfd
.vnfd
.vnf_configuration
751 vnf_config
.config_attributes
.config_priority
= 0
752 vnf_config
.config_attributes
.config_delay
= 0
754 # Select "script" configuration
755 vnf_config
.script
.script_type
= 'bash'
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
762 vnf_config
.config_attributes
.config_delay
= 60
764 # This is PONG and inside mano_ut
766 vnf_config
.config_attributes
.config_delay
= 10
767 # vnf_config.config_template = self.pong_config(vnf_config, use_ns_init_conf)
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
)
773 def ns_config(self
, nsd
, vnfd_list
, mano_ut
):
774 # Used by scale group
776 nsd
.service_primitive
.add().from_dict(
778 "name": "ping config",
779 "user_defined_script": "{}".format(os
.path
.join(
780 os
.environ
['RIFT_ROOT'],
782 'examples/ping_pong_ns/rift/mano/examples',
783 'ping_config_ut.sh'))
786 nsd
.service_primitive
.add().from_dict(
788 "name": "ping config",
789 "user_defined_script": "ping_config.py"
792 def ns_initial_config(self
, nsd
):
793 nsd
.initial_config_primitive
.add().from_dict(
796 "name": "start traffic",
797 "user_defined_script": "start_traffic.py",
807 def add_scale_group(self
, scale_group
):
808 self
._scale
_groups
.append(scale_group
)
810 def add_placement_group(self
, placement_group
):
811 self
._placement
_groups
.append(placement_group
)
813 def create_mon_params(self
, vnfds
):
814 NsdMonParam
= NsdYang
.YangData_Nsd_NsdCatalog_Nsd_MonitoringParam
816 for vnfd_obj
in vnfds
:
817 for mon_param
in vnfd_obj
.vnfd
.monitoring_param
:
818 nsd_monp
= NsdMonParam
.from_dict({
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}]
828 self
.nsd
.monitoring_param
.append(nsd_monp
)
834 def compose(self
, vnfd_list
, cpgroup_list
, mano_ut
,
835 use_ns_init_conf
=True,
839 # Disable NS initial config primitive
840 use_ns_init_conf
=False
842 self
.descriptor
= RwNsdYang
.YangData_Nsd_NsdCatalog()
843 self
.id = str(uuid
.uuid1())
844 nsd
= self
.descriptor
.nsd
.add()
848 nsd
.short_name
= self
.name
849 nsd
.vendor
= 'RIFT.io'
850 nsd
.logo
= 'rift_logo.png'
851 nsd
.description
= 'Toy NS'
853 nsd
.input_parameter_xpath
.append(
854 NsdYang
.YangData_Nsd_NsdCatalog_Nsd_InputParameterXpath(
855 xpath
="/nsd:nsd-catalog/nsd:nsd/nsd:vendor",
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"
867 for cpgroup
in cpgroup_list
:
869 vld
.id = 'ping_pong_vld%s' % vld_id
871 vld
.name
= 'ping_pong_vld' # hard coded
872 vld
.short_name
= vld
.name
873 vld
.vendor
= 'RIFT.io'
874 vld
.description
= 'Toy VL'
876 vld
.type_yang
= 'ELAN'
877 vld
.ip_profile_ref
= 'InterVNFLink'
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]
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
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
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
,
902 member_vnf_index
+= 1
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
)
909 # Add NS initial config to start traffic
911 self
.ns_initial_config(nsd
)
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
]
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']
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
]
939 # self.create_mon_params(vnfd_list)
941 def write_config(self
, outdir
, vnfds
):
943 converter
= config_data
.ConfigPrimitiveConvertor()
944 yaml_data
= converter
.extract_nsd_config(self
.nsd
)
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)
952 with
open('%s/%s.yaml' % (ns_config_dir
, self
.id), "w") as fh
:
955 for i
, vnfd
in enumerate(vnfds
, start
=1):
956 yaml_data
= converter
.extract_vnfd_config(vnfd
)
959 with
open('%s/%s__%s.yaml' % (vnf_config_dir
, vnfd
.id, i
), "w") as fh
:
962 def write_initial_config_script(self
, outdir
):
963 script_name
= 'start_traffic.py'
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
)
972 dest_path
= os
.path
.join(outdir
, 'scripts')
973 os
.makedirs(dest_path
, exist_ok
=True)
975 shutil
.copy2(script_src
, dest_path
)
977 def write_to_file(self
, outdir
, output_format
):
978 dirpath
= os
.path
.join(outdir
, self
.name
)
979 if not os
.path
.exists(dirpath
):
982 super(NetworkService
, self
).write_to_file(["nsd", "rw-nsd"],
986 # Write the initial config script
987 self
.write_initial_config_script(dirpath
)
990 def get_ping_mon_params(path
):
994 'name': 'ping-request-tx-count',
995 'http_endpoint_ref': path
,
996 'json_query_method': "NAMEKEY",
998 'description': 'no of ping requests',
999 'group_tag': 'Group1',
1000 'widget_type': 'COUNTER',
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',
1018 def get_pong_mon_params(path
):
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',
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',
1046 class ScaleGroup(object):
1047 def __init__(self
, name
, min_count
=1, max_count
=1):
1049 self
.min_count
= min_count
1050 self
.max_count
= max_count
1051 self
.vnfd_count_map
= {}
1052 self
.config_action
= {}
1054 def add_vnfd(self
, vnfd
, vnfd_count
):
1055 self
.vnfd_count_map
[vnfd
] = vnfd_count
1057 def add_config(self
):
1058 self
.config_action
['post_scale_out']= {'ns-config-primitive-name-ref':
1061 class PlacementGroup(object):
1062 def __init__(self
, name
):
1065 self
.requirement
= ''
1067 def add_strategy(self
, strategy
):
1068 self
.strategy
= strategy
1070 def add_requirement(self
, requirement
):
1071 self
.requirement
= requirement
1073 class NsdPlacementGroup(PlacementGroup
):
1074 def __init__(self
, name
):
1076 super(NsdPlacementGroup
, self
).__init
__(name
)
1078 def add_member(self
, vnfd
):
1079 self
.vnfd_list
.append(vnfd
)
1082 class VnfdPlacementGroup(PlacementGroup
):
1083 def __init__(self
, name
):
1085 super(VnfdPlacementGroup
, self
).__init
__(name
)
1087 def add_member(self
, vdu
):
1088 self
.vdu_list
.append(vdu
)
1093 def generate_ping_pong_descriptors(fmt
="json",
1094 write_to_file
=False,
1096 pingcount
=NUM_PING_INSTANCES
,
1097 external_vlr_count
=1,
1098 internal_vlr_count
=1,
1103 use_scale_group
=False,
1107 use_mon_params
=True,
1110 ex_ping_userdata
=None,
1111 ex_pong_userdata
=None,
1112 use_placement_group
=True,
1113 use_ns_init_conf
=True,
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
1120 for i
in range(external_vlr_count
):
1121 cpgroup_list
.append([])
1124 ping
= VirtualNetworkFunction("ping_vnfd%s" % (suffix
), pingcount
)
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
)
1133 # ping = VirtualNetworkFunction("ping_vnfd", pingcount)
1134 if not ping_userdata
:
1135 ping_userdata
= PING_USERDATA_FILE
1137 if ex_ping_userdata
:
1138 ping_userdata
= '''\
1142 ping_userdata
=ping_userdata
,
1143 ex_ping_userdata
=ex_ping_userdata
1147 "Fedora-x86_64-20-20131211.1-sda-ping.qcow2",
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 [],
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
,
1159 use_ns_init_conf
=use_ns_init_conf
,
1160 use_vca_conf
=use_vca_conf
,
1163 pong
= VirtualNetworkFunction("pong_vnfd%s" % (suffix
))
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
)
1173 # pong = VirtualNetworkFunction("pong_vnfd")
1175 if not pong_userdata
:
1176 pong_userdata
= PONG_USERDATA_FILE
1178 if ex_pong_userdata
:
1179 pong_userdata
= '''\
1183 pong_userdata
=pong_userdata
,
1184 ex_pong_userdata
=ex_pong_userdata
1189 "Fedora-x86_64-20-20131211.1-sda-pong.qcow2",
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 [],
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
,
1201 use_ns_init_conf
=use_ns_init_conf
,
1202 use_vca_conf
=use_vca_conf
,
1205 # Initialize the member VNF index
1206 member_vnf_index
= 1
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
)
1213 for idx
in range(pingcount
):
1220 member_vnf_index
+= 1
1222 desc_id
= pong
.descriptor
.vnfd
[0].id
1223 filename
= 'pong_vnfd{}/cp{}'.format(suffix
, index
)
1231 member_vnf_index
+= 1
1233 vnfd_list
= [ping
, pong
]
1235 nsd_catalog
= NetworkService("ping_pong_nsd%s" % (suffix
))
1238 group
= ScaleGroup("ping_group", max_count
=10)
1239 group
.add_vnfd(ping
, 1)
1241 nsd_catalog
.add_scale_group(group
)
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''')
1249 for member_vnfd
in vnfd_list
:
1250 group
.add_member(member_vnfd
)
1252 nsd_catalog
.add_placement_group(group
)
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''')
1259 for member_vnfd
in vnfd_list
:
1260 group
.add_member(member_vnfd
)
1262 nsd_catalog
.add_placement_group(group
)
1265 nsd_catalog
.compose(vnfd_list
,
1268 use_ns_init_conf
=use_ns_init_conf
,
1269 use_vca_conf
=use_vca_conf
,
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
)
1278 return (ping
, pong
, nsd_catalog
)
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
1298 pingcount
= args
.pingcount
1299 use_ping_cloud_init_file
= args
.ping_cloud_init
1300 use_pong_cloud_init_file
= args
.pong_cloud_init
1302 generate_ping_pong_descriptors(args
.format
, True, args
.outdir
, pingcount
,
1303 ping_md5sum
=args
.ping_image_md5
, pong_md5sum
=args
.pong_image_md5
,
1305 use_scale_group
=False,)
1307 if __name__
== "__main__":