From 42d88e6b4854c4088e8b2c42ef5155274612db97 Mon Sep 17 00:00:00 2001 From: Adam Israel Date: Mon, 16 Jul 2018 14:18:41 -0400 Subject: [PATCH 1/1] Fix bug #501 This fixes bug #501, where initial-config-primitive always expected a parameter to be present. Signed-off-by: Adam Israel --- n2vc/vnf.py | 8 +- tests/test_primitive_no_parameter.py | 274 +++++++++++++++++++++++++++ 2 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 tests/test_primitive_no_parameter.py diff --git a/n2vc/vnf.py b/n2vc/vnf.py index bd6b4f9..d6c87dc 100644 --- a/n2vc/vnf.py +++ b/n2vc/vnf.py @@ -297,7 +297,7 @@ class N2VC: ######################################## app = await self.get_application(model, application_name) if app: - raise JujuApplicationExists("Can't deploy application \"{}\" to model \"{}\" because it already exists.".format(application_name, model)) + raise JujuApplicationExists("Can't deploy application \"{}\" to model \"{}\" because it already exists.".format(application_name, model_name)) ################################################################ # Register this application with the model-level event monitor # @@ -375,10 +375,14 @@ class N2VC: else: seq = primitive['seq'] + params = {} + if 'parameter' in primitive: + params = primitive['parameter'] + primitives[seq] = { 'name': primitive['name'], 'parameters': self._map_primitive_parameters( - primitive['parameter'], + params, {'': rw_mgmt_ip} ), } diff --git a/tests/test_primitive_no_parameter.py b/tests/test_primitive_no_parameter.py new file mode 100644 index 0000000..8ac9380 --- /dev/null +++ b/tests/test_primitive_no_parameter.py @@ -0,0 +1,274 @@ +# A simple test to exercise the libraries' functionality +import asyncio +import functools +import os +import sys +import logging +import unittest +import yaml +from n2vc.vnf import N2VC + +NSD_YAML = """ +nsd:nsd-catalog: + nsd: + - id: multicharmvdu-ns + name: multicharmvdu-ns + short-name: multicharmvdu-ns + description: NS with 1 VNF + version: '1.0' + logo: osm.png + constituent-vnfd: + - vnfd-id-ref: multicharmvdu-vnf + member-vnf-index: '1' + vld: + - id: datanet + name: datanet + short-name: datanet + type: ELAN + vnfd-connection-point-ref: + - vnfd-id-ref: multicharmvdu-vnf + member-vnf-index-ref: '1' + vnfd-connection-point-ref: vnf-data +""" + +VNFD_YAML = """ +vnfd:vnfd-catalog: + vnfd: + - id: multicharmvdu-vnf + name: multicharmvdu-vnf + short-name: multicharmvdu-vnf + version: '1.0' + description: A VNF consisting of 1 VDUs w/charm + logo: osm.png + connection-point: + - id: vnf-data + name: vnf-data + short-name: vnf-data + type: VPORT + mgmt-interface: + cp: vnf-data + internal-vld: + - id: internal + name: internal + short-name: internal + type: ELAN + internal-connection-point: + - id-ref: dataVM-internal + vdu: + - id: dataVM + name: dataVM + image: xenial + count: '1' + vm-flavor: + vcpu-count: '1' + memory-mb: '1024' + storage-gb: '10' + interface: + - name: dataVM-eth0 + position: '1' + type: INTERNAL + virtual-interface: + type: VIRTIO + internal-connection-point-ref: dataVM-internal + - name: dataVM-xe0 + position: '2' + type: EXTERNAL + virtual-interface: + type: VIRTIO + external-connection-point-ref: vnf-data + internal-connection-point: + - id: dataVM-internal + name: dataVM-internal + short-name: dataVM-internal + type: VPORT + vdu-configuration: + juju: + charm: simple + initial-config-primitive: + - seq: '1' + name: config + parameter: + - name: ssh-hostname + value: + - name: ssh-username + value: ubuntu + - name: ssh-password + value: ubuntu + - seq: '2' + name: touch + parameter: + - name: filename + value: '/home/ubuntu/first-touch-dataVM' + - seq: '3' + name: start + config-primitive: + - name: touch + parameter: + - name: filename + data-type: STRING + default-value: '/home/ubuntu/touched' +""" + +class PythonTest(unittest.TestCase): + n2vc = None + + def setUp(self): + + self.log = logging.getLogger() + self.log.level = logging.DEBUG + + self.loop = asyncio.get_event_loop() + + # self.loop = asyncio.new_event_loop() + # asyncio.set_event_loop(None) + + # Extract parameters from the environment in order to run our test + vca_host = os.getenv('VCA_HOST', '127.0.0.1') + vca_port = os.getenv('VCA_PORT', 17070) + vca_user = os.getenv('VCA_USER', 'admin') + vca_charms = os.getenv('VCA_CHARMS', None) + vca_secret = os.getenv('VCA_SECRET', None) + self.n2vc = N2VC( + log=self.log, + server=vca_host, + port=vca_port, + user=vca_user, + secret=vca_secret, + artifacts=vca_charms, + ) + + def tearDown(self): + self.loop.run_until_complete(self.n2vc.logout()) + + def get_descriptor(self, descriptor): + desc = None + try: + tmp = yaml.load(descriptor) + + # Remove the envelope + root = list(tmp.keys())[0] + if root == "nsd:nsd-catalog": + desc = tmp['nsd:nsd-catalog']['nsd'][0] + elif root == "vnfd:vnfd-catalog": + desc = tmp['vnfd:vnfd-catalog']['vnfd'][0] + except ValueError: + assert False + return desc + + def n2vc_callback(self, model_name, application_name, workload_status, task=None): + """We pass the vnfd when setting up the callback, so expect it to be + returned as a tuple.""" + if workload_status and not task: + self.log.debug("Callback: workload status \"{}\"".format(workload_status)) + + if workload_status in ["blocked"]: + task = asyncio.ensure_future( + self.n2vc.ExecutePrimitive( + model_name, + application_name, + "config", + None, + params={ + 'ssh-hostname': '10.195.8.78', + 'ssh-username': 'ubuntu', + 'ssh-password': 'ubuntu' + } + ) + ) + task.add_done_callback(functools.partial(self.n2vc_callback, None, None, None)) + pass + elif workload_status in ["active"]: + self.log.debug("Removing charm") + task = asyncio.ensure_future( + self.n2vc.RemoveCharms(model_name, application_name, self.n2vc_callback) + ) + task.add_done_callback(functools.partial(self.n2vc_callback, None, None, None)) + + def test_deploy_application(self): + stream_handler = logging.StreamHandler(sys.stdout) + self.log.addHandler(stream_handler) + try: + self.log.info("Log handler installed") + nsd = self.get_descriptor(NSD_YAML) + vnfd = self.get_descriptor(VNFD_YAML) + + if nsd and vnfd: + + vca_charms = os.getenv('VCA_CHARMS', None) + + params = {} + vnf_index = 0 + + def deploy(): + """An inner function to do the deployment of a charm from + either a vdu or vnf. + """ + charm_dir = "{}/{}".format(vca_charms, charm) + + # Setting this to an IP that will fail the initial config. + # This will be detected in the callback, which will execute + # the "config" primitive with the right IP address. + params['rw_mgmt_ip'] = '10.195.8.78' + + # self.loop.run_until_complete(n.CreateNetworkService(nsd)) + ns_name = "default" + + vnf_name = self.n2vc.FormatApplicationName( + ns_name, + vnfd['name'], + str(vnf_index), + ) + + self.loop.run_until_complete( + self.n2vc.DeployCharms( + ns_name, + vnf_name, + vnfd, + charm_dir, + params, + {}, + self.n2vc_callback + ) + ) + + # Check if the VDUs in this VNF have a charm + for vdu in vnfd['vdu']: + vdu_config = vdu.get('vdu-configuration') + if vdu_config: + juju = vdu_config['juju'] + self.assertIsNotNone(juju) + + charm = juju['charm'] + self.assertIsNotNone(charm) + + params['initial-config-primitive'] = vdu_config['initial-config-primitive'] + + deploy() + vnf_index += 1 + + # Check if this VNF has a charm + vnf_config = vnfd.get("vnf-configuration") + if vnf_config: + juju = vnf_config['juju'] + self.assertIsNotNone(juju) + + charm = juju['charm'] + self.assertIsNotNone(charm) + + params['initial-config-primitive'] = vnf_config['initial-config-primitive'] + + deploy() + vnf_index += 1 + + self.loop.run_forever() + + # self.loop.run_until_complete(n.GetMetrics(vnfd, nsd=nsd)) + + # Test actions + # ExecutePrimitive(self, nsd, vnfd, vnf_member_index, primitive, callback, *callback_args, **params): + + # self.loop.run_until_complete(n.DestroyNetworkService(nsd)) + + # self.loop.run_until_complete(self.n2vc.logout()) + finally: + self.log.removeHandler(stream_handler) -- 2.17.1