1 # A simple test to exercise the libraries' functionality
7 import osm_im
.vnfd
as vnfd_catalog
8 import osm_im
.nsd
as nsd_catalog
9 from pyangbind
.lib
.serialise
import pybindJSONDecoder
12 from n2vc
.vnf
import N2VC
17 - id: rift_ping_pong_ns
20 short-name: ping_pong_ns
23 description: RIFT.io sample ping pong network service
25 - member-vnf-index: '1'
26 vnfd-id-ref: rift_ping_vnf
27 - member-vnf-index: '2'
28 vnfd-id-ref: rift_pong_vnf
29 initial-service-primitive:
39 user-defined-script: start_traffic.py
40 input-parameter-xpath:
41 - xpath: /nsd:nsd-catalog/nsd:nsd/nsd:vendor
43 - description: Inter VNF Link
45 gateway-address: 31.31.31.210
47 subnet-address: 31.31.31.0/24
50 start-address: 31.31.31.2
54 - member-vnf-index-ref: '1'
55 vnfd-id-ref: rift_ping_vnf
56 - member-vnf-index-ref: '2'
57 vnfd-id-ref: rift_pong_vnf
59 requirement: Place this VM on the Kuiper belt object Orcus
62 - member-vnf-index-ref: '1'
63 vnfd-id-ref: rift_ping_vnf
64 - member-vnf-index-ref: '2'
65 vnfd-id-ref: rift_pong_vnf
67 requirement: Place this VM on the Kuiper belt object Quaoar
71 description: Management VL
74 vim-network-name: mgmt
79 vnfd-connection-point-ref:
80 - member-vnf-index-ref: '1'
81 vnfd-connection-point-ref: ping_vnfd/cp0
82 vnfd-id-ref: rift_ping_vnf
83 - member-vnf-index-ref: '2'
84 vnfd-connection-point-ref: pong_vnfd/cp0
85 vnfd-id-ref: rift_pong_vnf
88 ip-profile-ref: InterVNFLink
94 vnfd-connection-point-ref:
95 - member-vnf-index-ref: '1'
96 vnfd-connection-point-ref: ping_vnfd/cp1
97 vnfd-id-ref: rift_ping_vnf
98 - member-vnf-index-ref: '2'
99 vnfd-connection-point-ref: pong_vnfd/cp1
100 vnfd-id-ref: rift_pong_vnf
112 description: This is an example RIFT.ware VNF
114 - name: ping_vnfd/cp0
116 - name: ping_vnfd/cp1
119 - path: api/v1/ping/stats
123 path: api/v1/ping/stats
129 - member-vdu-ref: iovdu_0
131 requirement: Place this VM on the Kuiper belt object Eris
134 - cloud-init-file: ping_cloud_init.cfg
142 external-connection-point-ref: ping_vnfd/cp0
148 external-connection-point-ref: ping_vnfd/cp1
150 image: Fedora-x86_64-20-20131211.1-sda-ping.qcow2
164 default-value: <rw_mgmt_ip>
167 default-value: fedora
170 default-value: fedora
173 name: ssh-private-key
189 - name: start-traffic
191 initial-config-primitive:
209 NSD_DICT
= {'name': 'ping_pong_ns', 'short-name': 'ping_pong_ns', 'ip-profiles': [{'ip-profile-params': {'ip-version': 'ipv4', 'dhcp-params': {'count': 200, 'start-address': '31.31.31.2'}, 'subnet-address': '31.31.31.0/24', 'gateway-address': '31.31.31.210'}, 'description': 'Inter VNF Link', 'name': 'InterVNFLink'}], 'logo': 'rift_logo.png', 'description': 'RIFT.io sample ping pong network service', '_admin': {'storage': {'folder': 'd9bc2e64-dfec-4c36-a8bb-c4667e8d7a53', 'tarfile': 'pkg', 'file': 'ping_pong_ns', 'path': '/app/storage/', 'fs': 'local'}, 'created': 1521127984.6414561, 'modified': 1521127984.6414561, 'projects_write': ['admin'], 'projects_read': ['admin']}, 'placement-groups': [{'member-vnfd': [{'member-vnf-index-ref': '1', 'vnfd-id-ref': 'rift_ping_vnf'}, {'member-vnf-index-ref': '2', 'vnfd-id-ref': 'rift_pong_vnf'}], 'name': 'Orcus', 'strategy': 'COLOCATION', 'requirement': 'Place this VM on the Kuiper belt object Orcus'}, {'member-vnfd': [{'member-vnf-index-ref': '1', 'vnfd-id-ref': 'rift_ping_vnf'}, {'member-vnf-index-ref': '2', 'vnfd-id-ref': 'rift_pong_vnf'}], 'name': 'Quaoar', 'strategy': 'COLOCATION', 'requirement': 'Place this VM on the Kuiper belt object Quaoar'}], 'input-parameter-xpath': [{'xpath': '/nsd:nsd-catalog/nsd:nsd/nsd:vendor'}], 'version': '1.1', 'vld': [{'name': 'mgmt', 'short-name': 'mgmt', 'mgmt-network': 'true', 'vim-network-name': 'mgmt', 'version': '1.0', 'vnfd-connection-point-ref': [{'vnfd-connection-point-ref': 'ping_vnfd/cp0', 'member-vnf-index-ref': '1', 'vnfd-id-ref': 'rift_ping_vnf'}, {'vnfd-connection-point-ref': 'pong_vnfd/cp0', 'member-vnf-index-ref': '2', 'vnfd-id-ref': 'rift_pong_vnf'}], 'description': 'Management VL', 'vendor': 'RIFT.io', 'type': 'ELAN', 'id': 'mgmt'}, {'ip-profile-ref': 'InterVNFLink', 'name': 'data_vl', 'short-name': 'data_vl', 'version': '1.0', 'vnfd-connection-point-ref': [{'vnfd-connection-point-ref': 'ping_vnfd/cp1', 'member-vnf-index-ref': '1', 'vnfd-id-ref': 'rift_ping_vnf'}, {'vnfd-connection-point-ref': 'pong_vnfd/cp1', 'member-vnf-index-ref': '2', 'vnfd-id-ref': 'rift_pong_vnf'}], 'description': 'Data VL', 'vendor': 'RIFT.io', 'type': 'ELAN', 'id': 'ping_pong_vl1'}], 'constituent-vnfd': [{'member-vnf-index': '1', 'vnfd-id-ref': 'rift_ping_vnf'}, {'member-vnf-index': '2', 'vnfd-id-ref': 'rift_pong_vnf'}], '_id': 'd9bc2e64-dfec-4c36-a8bb-c4667e8d7a53', 'vendor': 'RIFT.io', 'id': 'rift_ping_pong_ns', 'initial-service-primitive': [{'parameter': [{'name': 'port', 'value': 5555}, {'name': 'ssh-username', 'value': 'fedora'}, {'name': 'ssh-password', 'value': 'fedora'}], 'name': 'start traffic', 'seq': '1', 'user-defined-script': 'start_traffic.py'}]}
212 VNFD_PING_DICT
= {'name': 'ping_vnf', 'short-name': 'ping_vnf', 'mgmt-interface': {'port': '18888', 'cp': 'ping_vnfd/cp0', 'dashboard-params': {'port': '18888', 'path': 'api/v1/ping/stats'}}, 'description': 'This is an example RIFT.ware VNF', 'connection-point': [{'type': 'VPORT', 'name': 'ping_vnfd/cp0'}, {'type': 'VPORT', 'name': 'ping_vnfd/cp1'}], '_admin': {'storage': {'folder': '9ad8de93-cfcc-4da9-9795-d7dc5fec184e', 'fs': 'local', 'file': 'ping_vnf', 'path': '/app/storage/', 'tarfile': 'pkg'}, 'created': 1521127972.1878572, 'modified': 1521127972.1878572, 'projects_write': ['admin'], 'projects_read': ['admin']}, 'vnf-configuration': {'initial-config-primitive': [{'parameter': [{'name': 'ssh-hostname', 'value': '<rw_mgmt_ip>'}, {'name': 'ssh-username', 'value': 'ubuntu'}, {'name': 'ssh-password', 'value': 'ubuntu'}, {'name': 'mode', 'value': 'ping'}], 'name': 'config', 'seq': '1'}, {'name': 'start', 'seq': '2'}], 'juju': {'charm': 'pingpong'}, 'config-primitive': [{'name': 'start'}, {'name': 'stop'}, {'name': 'restart'}, {'parameter': [{'data-type': 'STRING', 'name': 'ssh-hostname', 'default-value': '<rw_mgmt_ip>'}, {'data-type': 'STRING', 'name': 'ssh-username', 'default-value': 'ubuntu'}, {'data-type': 'STRING', 'name': 'ssh-password', 'default-value': 'ubuntu'}, {'data-type': 'STRING', 'name': 'ssh-private-key'}, {'data-type': 'STRING', 'name': 'mode', 'read-only': 'true', 'default-value': 'ping'}], 'name': 'config'}, {'parameter': [{'data-type': 'STRING', 'name': 'server-ip'}, {'data-type': 'INTEGER', 'name': 'server-port'}], 'name': 'set-server'}, {'parameter': [{'data-type': 'INTEGER', 'name': 'rate', 'default-value': '5'}], 'name': 'set-rate'}, {'name': 'start-traffic'}, {'name': 'stop-traffic'}]}, 'placement-groups': [{'member-vdus': [{'member-vdu-ref': 'iovdu_0'}], 'name': 'Eris', 'strategy': 'COLOCATION', 'requirement': 'Place this VM on the Kuiper belt object Eris'}], 'http-endpoint': [{'port': '18888', 'path': 'api/v1/ping/stats'}], 'version': '1.1', 'logo': 'rift_logo.png', 'vdu': [{'vm-flavor': {'vcpu-count': '1', 'storage-gb': '20', 'memory-mb': '2048'}, 'count': '1', 'interface': [{'type': 'EXTERNAL', 'name': 'eth0', 'position': 0, 'virtual-interface': {'type': 'VIRTIO'}, 'external-connection-point-ref': 'ping_vnfd/cp0'}, {'type': 'EXTERNAL', 'name': 'eth1', 'position': 1, 'virtual-interface': {'type': 'VIRTIO'}, 'external-connection-point-ref': 'ping_vnfd/cp1'}], 'name': 'iovdu_0', 'image': 'xenial', 'id': 'iovdu_0', 'cloud-init-file': 'ping_cloud_init.cfg'}], '_id': '9ad8de93-cfcc-4da9-9795-d7dc5fec184e', 'vendor': 'RIFT.io', 'id': 'rift_ping_vnf'}
214 VNFD_PONG_DICT
= {'name': 'pong_vnf', 'short-name': 'pong_vnf', 'mgmt-interface': {'port': '18888', 'cp': 'pong_vnfd/cp0', 'dashboard-params': {'port': '18888', 'path': 'api/v1/pong/stats'}}, 'description': 'This is an example RIFT.ware VNF', 'connection-point': [{'type': 'VPORT', 'name': 'pong_vnfd/cp0'}, {'type': 'VPORT', 'name': 'pong_vnfd/cp1'}], '_admin': {'storage': {'folder': '9ad8de93-cfcc-4da9-9795-d7dc5fec184e', 'fs': 'local', 'file': 'pong_vnf', 'path': '/app/storage/', 'tarfile': 'pkg'}, 'created': 1521127972.1878572, 'modified': 1521127972.1878572, 'projects_write': ['admin'], 'projects_read': ['admin']}, 'vnf-configuration': {'initial-config-primitive': [{'parameter': [{'name': 'ssh-hostname', 'value': '<rw_mgmt_ip>'}, {'name': 'ssh-username', 'value': 'ubuntu'}, {'name': 'ssh-password', 'value': 'ubuntu'}, {'name': 'mode', 'value': 'pong'}], 'name': 'config', 'seq': '1'}, {'name': 'start', 'seq': '2'}], 'juju': {'charm': 'pingpong'}, 'config-primitive': [{'name': 'start'}, {'name': 'stop'}, {'name': 'restart'}, {'parameter': [{'data-type': 'STRING', 'name': 'ssh-hostname', 'default-value': '<rw_mgmt_ip>'}, {'data-type': 'STRING', 'name': 'ssh-username', 'default-value': 'ubuntu'}, {'data-type': 'STRING', 'name': 'ssh-password', 'default-value': 'ubuntu'}, {'data-type': 'STRING', 'name': 'ssh-private-key'}, {'data-type': 'STRING', 'name': 'mode', 'read-only': 'true', 'default-value': 'pong'}], 'name': 'config'}, {'parameter': [{'data-type': 'STRING', 'name': 'server-ip'}, {'data-type': 'INTEGER', 'name': 'server-port'}], 'name': 'set-server'}, {'parameter': [{'data-type': 'INTEGER', 'name': 'rate', 'default-value': '5'}], 'name': 'set-rate'}, {'name': 'start-traffic'}, {'name': 'stop-traffic'}]}, 'placement-groups': [{'member-vdus': [{'member-vdu-ref': 'iovdu_0'}], 'name': 'Eris', 'strategy': 'COLOCATION', 'requirement': 'Place this VM on the Kuiper belt object Eris'}], 'http-endpoint': [{'port': '18888', 'path': 'api/v1/pong/stats'}], 'version': '1.1', 'logo': 'rift_logo.png', 'vdu': [{'vm-flavor': {'vcpu-count': '1', 'storage-gb': '20', 'memory-mb': '2048'}, 'count': '1', 'interface': [{'type': 'EXTERNAL', 'name': 'eth0', 'position': 0, 'virtual-interface': {'type': 'VIRTIO'}, 'external-connection-point-ref': 'ping_vnfd/cp0'}, {'type': 'EXTERNAL', 'name': 'eth1', 'position': 1, 'virtual-interface': {'type': 'VIRTIO'}, 'external-connection-point-ref': 'ping_vnfd/cp1'}], 'name': 'iovdu_0', 'image': 'xenial', 'id': 'iovdu_0', 'cloud-init-file': 'pong_cloud_init.cfg'}], '_id': '9ad8de93-cfcc-4da9-9795-d7dc5fec184e', 'vendor': 'RIFT.io', 'id': 'rift_pong_vnf'}
217 class PythonTest(unittest
.TestCase
):
222 self
.log
= logging
.getLogger()
223 self
.log
.level
= logging
.DEBUG
225 self
.loop
= asyncio
.new_event_loop()
226 asyncio
.set_event_loop(None)
228 # Extract parameters from the environment in order to run our test
229 vca_host
= os
.getenv('VCA_HOST', '127.0.0.1')
230 vca_port
= os
.getenv('VCA_PORT', 17070)
231 vca_user
= os
.getenv('VCA_USER', 'admin')
232 vca_charms
= os
.getenv('VCA_CHARMS', None)
233 vca_secret
= os
.getenv('VCA_SECRET', None)
240 artifacts
=vca_charms
,
244 self
.loop
.run_until_complete(self
.n2vc
.logout())
246 def get_vnf_descriptor(self
, descriptor
):
247 vnfd
= vnfd_catalog
.vnfd()
249 data
= yaml
.load(descriptor
)
250 pybindJSONDecoder
.load_ietf_json(data
, None, None, obj
=vnfd
)
255 def get_ns_descriptor(self
, descriptor
):
256 nsd
= nsd_catalog
.nsd()
258 data
= yaml
.load(descriptor
)
259 pybindJSONDecoder
.load_ietf_json(data
, None, None, obj
=nsd
)
264 # def test_descriptor(self):
265 # """Test loading and parsing a descriptor."""
266 # nsd = self.get_ns_descriptor(NSD_YAML)
267 # vnfd = self.get_vnf_descriptor(VNFD_VCA_YAML)
271 # def test_yang_to_dict(self):
272 # # Test the conversion of the native object returned by pybind to a dict
273 # # Extract parameters from the environment in order to run our test
275 # nsd = self.get_ns_descriptor(NSD_YAML)
276 # new = yang_to_dict(nsd)
277 # self.assertEqual(NSD_DICT, new)
279 def n2vc_callback(self
, model_name
, application_name
, workload_status
, task
=None):
280 """We pass the vnfd when setting up the callback, so expect it to be
281 returned as a tuple."""
282 if workload_status
and not task
:
283 self
.log
.debug("Callback: workload status \"{}\"".format(workload_status
))
285 if workload_status
in ["blocked"]:
286 task
= asyncio
.ensure_future(
287 self
.n2vc
.ExecutePrimitive(
293 'ssh-hostname': '10.195.8.78',
294 'ssh-username': 'ubuntu',
295 'ssh-password': 'ubuntu'
299 task
.add_done_callback(functools
.partial(self
.n2vc_callback
, None, None, None))
301 elif workload_status
in ["active"]:
302 self
.log
.debug("Removing charm")
303 task
= asyncio
.ensure_future(
304 self
.n2vc
.RemoveCharms(model_name
, application_name
, self
.n2vc_callback
, model_name
, application_name
)
306 task
.add_done_callback(functools
.partial(self
.n2vc_callback
, None, None, None))
311 def test_deploy_application(self
):
312 stream_handler
= logging
.StreamHandler(sys
.stdout
)
313 self
.log
.addHandler(stream_handler
)
315 self
.log
.info("Log handler installed")
317 vnfd_ping
= VNFD_PING_DICT
318 vnfd_pong
= VNFD_PONG_DICT
319 if nsd
and vnfd_ping
and vnfd_pong
:
320 vca_charms
= os
.getenv('VCA_CHARMS', None)
322 config
= vnfd_ping
['vnf-configuration']
323 self
.assertIsNotNone(config
)
325 juju
= config
['juju']
326 self
.assertIsNotNone(juju
)
328 charm
= juju
['charm']
329 self
.assertIsNotNone(charm
)
331 charm_dir
= "{}/{}".format(vca_charms
, charm
)
332 # n.callback_status = self.callback_status
334 # Setting this to an IP that will fail the initial config.
335 # This will be detected in the callback, which will execute
336 # the "config" primitive with the right IP address.
338 'rw_mgmt_ip': '127.0.0.1'
341 # self.loop.run_until_complete(n.CreateNetworkService(nsd))
342 # task = asyncio.ensure_future(n.DeployCharms(vnfd, nsd=nsd, artifacts=charm_dir))
343 # task = asyncio.ensure_future(n.DeployCharms(vnfd, nsd=nsd, artifacts=charm_dir))
346 ping_vnf_name
= self
.n2vc
.FormatApplicationName(ns_name
, vnfd_ping
['name'])
347 pong_vnf_name
= self
.n2vc
.FormatApplicationName(ns_name
, vnfd_pong
['name'])
349 self
.loop
.run_until_complete(self
.n2vc
.DeployCharms(ns_name
, ping_vnf_name
, vnfd_ping
, charm_dir
, params
, {}, self
.n2vc_callback
))
350 self
.loop
.run_until_complete(self
.n2vc
.DeployCharms(ns_name
, pong_vnf_name
, vnfd_pong
, charm_dir
, params
, {}, self
.n2vc_callback
))
351 self
.loop
.run_forever()
353 # self.loop.run_until_complete(n.GetMetrics(vnfd, nsd=nsd))
355 # ExecutePrimitive(self, nsd, vnfd, vnf_member_index, primitive, callback, *callback_args, **params):
357 # self.loop.run_until_complete(n.DestroyNetworkService(nsd))
359 # self.loop.run_until_complete(self.n2vc.logout())
361 self
.log
.removeHandler(stream_handler
)
363 # def test_deploy_application(self):
365 # nsd = self.get_ns_descriptor(NSD_YAML)
366 # vnfd = self.get_vnf_descriptor(VNFD_VCA_YAML)
368 # # 1) Test that we're parsing the data correctly
369 # for vnfd_yang in vnfd.vnfd_catalog.vnfd.itervalues():
370 # vnfd_rec = vnfd_yang.get()
371 # # Each vnfd may have a charm
373 # config = vnfd_rec.get('vnf-configuration')
374 # self.assertIsNotNone(config)
376 # juju = config.get('juju')
377 # self.assertIsNotNone(juju)
379 # charm = juju.get('charm')
380 # self.assertIsNotNone(charm)
382 # # 2) Exercise the data by deploying the charms
384 # # Extract parameters from the environment in order to run our test
385 # vca_host = os.getenv('VCA_HOST', '127.0.0.1')
386 # vca_port = os.getenv('VCA_PORT', 17070)
387 # vca_user = os.getenv('VCA_USER', 'admin')
388 # vca_charms = os.getenv('VCA_CHARMS', None)
389 # vca_secret = os.getenv('VCA_SECRET', None)
391 # # server='10.195.8.254',
394 # # secret='74e7aa0cc9cb294de3af294bd76b4604'
401 # artifacts=vca_charms,
404 # n.callback_status = self.callback_status
406 # self.loop.run_until_complete(n.CreateNetworkService(nsd))
407 # self.loop.run_until_complete(n.DeployCharms(vnfd, nsd=nsd))
408 # # self.loop.run_until_complete(n.GetMetrics(vnfd, nsd=nsd))
410 # # self.loop.run_until_complete(n.RemoveCharms(nsd, vnfd))
411 # self.loop.run_until_complete(n.DestroyNetworkService(nsd))
413 # self.loop.run_until_complete(n.logout())
416 def callback_status(self
, nsd
, vnfd
, workload_status
):
417 """An example callback.
419 This is an example of how a client using N2VC can receive periodic
420 updates on the status of a vnfd
424 print("Workload status: {}".format(workload_status
))
426 def test_deploy_multivdu_application(self
):
427 """Deploy a multi-vdu vnf that uses multiple charms."""
430 def test_remove_application(self
):
433 def test_get_metrics(self
):