From 20ebb3ef9f52479ef0c1c15a52d0652dab40cd8e Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Tue, 5 Jun 2018 21:04:54 +0200 Subject: Add Vmtp as a new testcase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VMTP is a small python application that will automatically perform ping connectivity, round trip time measurement (latency) and TCP/UDP throughput. JIRA: FUNCTEST-980 Change-Id: I8e94fc52a429f505ac14e14bbb9d0a3b20996ba4 Signed-off-by: Cédric Ollivier --- docker/smoke/Dockerfile | 13 +- docker/smoke/testcases.yaml | 17 +++ functest/ci/config_aarch64_patch.yaml | 9 ++ functest/ci/config_patch.yaml | 8 ++ functest/ci/testcases.yaml | 17 +++ functest/opnfv_tests/openstack/vmtp/__init__.py | 0 functest/opnfv_tests/openstack/vmtp/vmtp.py | 153 ++++++++++++++++++++++++ functest/tests/unit/openstack/vmtp/__init__.py | 0 functest/tests/unit/openstack/vmtp/test_vmtp.py | 88 ++++++++++++++ tox.ini | 4 +- 10 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 functest/opnfv_tests/openstack/vmtp/__init__.py create mode 100644 functest/opnfv_tests/openstack/vmtp/vmtp.py create mode 100644 functest/tests/unit/openstack/vmtp/__init__.py create mode 100644 functest/tests/unit/openstack/vmtp/test_vmtp.py diff --git a/docker/smoke/Dockerfile b/docker/smoke/Dockerfile index 87b28f0a4..4d239e581 100644 --- a/docker/smoke/Dockerfile +++ b/docker/smoke/Dockerfile @@ -4,10 +4,12 @@ ARG BRANCH=master ARG OPENSTACK_TAG=stable/queens ARG REFSTACK_TARGET=2017.09 ARG PATROLE_TAG=0.3.0 +ARG VMTP_TAG=refs/changes/14/580914/4 -RUN apk --no-cache add --virtual .build-deps --update \ +RUN apk --no-cache add --update libxml2 libxslt && \ + apk --no-cache add --virtual .build-deps --update \ python-dev build-base linux-headers libffi-dev \ - openssl-dev libjpeg-turbo-dev && \ + openssl-dev libjpeg-turbo-dev libxml2-dev libxslt-dev && \ wget -q -O- https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=$OPENSTACK_TAG | \ sed -E s/^tempest==+\(.*\)$/-e\ git+https:\\/\\/github.com\\/openstack\\/tempest@\\1#egg=tempest/ \ > upper-constraints.txt && \ @@ -16,15 +18,18 @@ RUN apk --no-cache add --virtual .build-deps --update \ git clone https://github.com/openstack/patrole.git /src/patrole && \ (cd /src/patrole && git checkout $PATROLE_TAG) && \ update-requirements -s --source /src/openstack-requirements /src/patrole/ && \ + git clone https://github.com/openstack/vmtp.git /src/vmtp && \ + (cd /src/vmtp && git fetch origin $VMTP_TAG && git checkout FETCH_HEAD) && \ + update-requirements -s --source /src/openstack-requirements /src/vmtp/ && \ git clone --depth 1 https://github.com/openstack/neutron-tempest-plugin.git /src/neutron-tempest-plugin && \ update-requirements -s --source /src/openstack-requirements /src/neutron-tempest-plugin && \ git clone --depth 1 https://github.com/openstack/barbican-tempest-plugin.git /src/barbican-tempest-plugin && \ update-requirements -s --source /src/openstack-requirements /src/barbican-tempest-plugin/ && \ pip install --no-cache-dir --src /src -cupper-constraints.txt -cupper-constraints.opnfv.txt \ - /src/patrole /src/barbican-tempest-plugin /src/neutron-tempest-plugin && \ + /src/patrole /src/barbican-tempest-plugin /src/neutron-tempest-plugin /src/vmtp && \ virtualenv --system-site-packages /src/tempest/.venv && \ rm -r upper-constraints.txt upper-constraints.opnfv.txt \ - /src/patrole /src/barbican-tempest-plugin /src/neutron-tempest-plugin && \ + /src/patrole /src/barbican-tempest-plugin /src/neutron-tempest-plugin /src/vmtp && \ mkdir -p /home/opnfv/functest/data/refstack && \ wget "https://refstack.openstack.org/api/v1/guidelines/${REFSTACK_TARGET}/tests?target=compute&type=required&alias=true&flag=false" \ -O /home/opnfv/functest/data/refstack/defcore.txt && \ diff --git a/docker/smoke/testcases.yaml b/docker/smoke/testcases.yaml index 5a93a1d7c..0d16879ca 100644 --- a/docker/smoke/testcases.yaml +++ b/docker/smoke/testcases.yaml @@ -77,6 +77,23 @@ tiers: exclude: - 'test_networks_multiprovider_rbac' + - + case_name: vmtp + project_name: functest + criteria: 100 + blocking: false + description: >- + VMTP is a small python application that will automatically + perform ping connectivity, round trip time measurement + (latency) and TCP/UDP throughput + dependencies: + installer: '' + scenario: '' + run: + module: + 'functest.opnfv_tests.openstack.vmtp.vmtp' + class: 'Vmtp' + - case_name: shaker project_name: functest diff --git a/functest/ci/config_aarch64_patch.yaml b/functest/ci/config_aarch64_patch.yaml index b288641e1..00020af6a 100644 --- a/functest/ci/config_aarch64_patch.yaml +++ b/functest/ci/config_aarch64_patch.yaml @@ -94,6 +94,15 @@ os: hw_disk_bus: 'scsi' hw_scsi_model: 'virtio-scsi' + vmtp: + image: + /home/opnfv/functest/images/ubuntu-14.04-server-cloudimg-arm64-uefi1.img + extra_properties: + hw_firmware_type: 'uefi' + hw_video_model: 'vga' + hw_disk_bus: 'scsi' + hw_scsi_model: 'virtio-scsi' + shaker: image: /home/opnfv/functest/images/shaker-image-arm64.qcow2 extra_properties: diff --git a/functest/ci/config_patch.yaml b/functest/ci/config_patch.yaml index c2c6cb417..c2bfe33e7 100644 --- a/functest/ci/config_patch.yaml +++ b/functest/ci/config_patch.yaml @@ -54,6 +54,10 @@ fdio: flavor_extra_specs: {'hw:mem_page_size':'large'} extra_properties: {'hw_mem_page_size':'large'} flavor_ram: 1024 + vmtp: + flavor_extra_specs: {'hw:mem_page_size':'large'} + extra_properties: {'hw_mem_page_size':'large'} + flavor_ram: 2048 shaker: flavor_extra_specs: {'hw:mem_page_size':'large'} extra_properties: {'hw_mem_page_size':'large'} @@ -127,6 +131,10 @@ ovs: flavor_extra_specs: {'hw:mem_page_size':'large'} extra_properties: {'hw_mem_page_size':'large'} flavor_ram: 1024 + vmtp: + flavor_extra_specs: {'hw:mem_page_size':'large'} + extra_properties: {'hw_mem_page_size':'large'} + flavor_ram: 2048 shaker: flavor_extra_specs: {'hw:mem_page_size':'large'} extra_properties: {'hw_mem_page_size':'large'} diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml index 44685a145..48e64747f 100644 --- a/functest/ci/testcases.yaml +++ b/functest/ci/testcases.yaml @@ -302,6 +302,23 @@ tiers: exclude: - 'test_networks_multiprovider_rbac' + - + case_name: vmtp + project_name: functest + criteria: 100 + blocking: false + description: >- + VMTP is a small python application that will automatically + perform ping connectivity, round trip time measurement + (latency) and TCP/UDP throughput + dependencies: + installer: '' + scenario: '' + run: + module: + 'functest.opnfv_tests.openstack.vmtp.vmtp' + class: 'Vmtp' + - case_name: shaker project_name: functest diff --git a/functest/opnfv_tests/openstack/vmtp/__init__.py b/functest/opnfv_tests/openstack/vmtp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/functest/opnfv_tests/openstack/vmtp/vmtp.py b/functest/opnfv_tests/openstack/vmtp/vmtp.py new file mode 100644 index 000000000..52d1d6d75 --- /dev/null +++ b/functest/opnfv_tests/openstack/vmtp/vmtp.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python + +# Copyright (c) 2018 Orange and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 + +""" +VMTP_ is a small python application that will automatically perform ping +connectivity, round trip time measurement (latency) and TCP/UDP throughput +measurement for the following East/West flows on any OpenStack deployment: + +- VM to VM same network (private fixed IP, flow #1) +- VM to VM different network using fixed IP (same as intra-tenant L3 fixed IP, + flow #2) +- VM to VM different network using floating IP and NAT (same as floating IP + inter-tenant L3, flow #3) + +.. _VMTP: http://vmtp.readthedocs.io/en/latest/ +""" + +import json +import logging +import os +import subprocess +import tempfile +import time +import yaml + +from xtesting.core import testcase + +from functest.core import singlevm +from functest.utils import env + + +class Vmtp(singlevm.VmReady1): + """Class to run Vmtp_ as an OPNFV Functest testcase + + .. _Vmtp: http://vmtp.readthedocs.io/en/latest/ + """ + # pylint: disable=too-many-instance-attributes + + __logger = logging.getLogger(__name__) + + filename = ('/home/opnfv/functest/images/' + 'ubuntu-14.04-server-cloudimg-amd64-disk1.img') + flavor_ram = 2048 + flavor_vcpus = 1 + flavor_disk = 0 + + def __init__(self, **kwargs): + if "case_name" not in kwargs: + kwargs["case_name"] = 'vmtp' + super(Vmtp, self).__init__(**kwargs) + self.config = "{}/vmtp.conf".format(self.res_dir) + (_, self.privkey_filename) = tempfile.mkstemp() + (_, self.pubkey_filename) = tempfile.mkstemp() + + def generate_keys(self): + """Generate Keys + + Raises: Exception on error + """ + assert self.cloud + name = "vmtp_{}".format(self.guid) + self.__logger.info("Creating keypair with name: '%s'", name) + keypair = self.cloud.create_keypair(name) + self.__logger.debug("keypair: %s", keypair) + with open(self.privkey_filename, 'w') as key_file: + key_file.write(keypair.private_key) + with open(self.pubkey_filename, 'w') as key_file: + key_file.write(keypair.public_key) + self.cloud.delete_keypair(keypair.id) + + def write_config(self): + """Write vmtp.conf + + Raises: Exception on error + """ + assert self.cloud + if not os.path.exists(self.res_dir): + os.makedirs(self.res_dir) + cmd = ['vmtp', '-sc'] + output = subprocess.check_output(cmd) + self.__logger.info("%s\n%s", " ".join(cmd), output) + with open(self.config, "w+") as conf: + vmtp_conf = yaml.load(output) + vmtp_conf["private_key_file"] = self.privkey_filename + vmtp_conf["public_key_file"] = self.pubkey_filename + vmtp_conf["image_name"] = str(self.image.name) + vmtp_conf["router_name"] = "pns_router_{}".format(self.guid) + vmtp_conf["flavor_type"] = str(self.flavor.name) + vmtp_conf["internal_network_name"] = [ + "pns-internal-net_{}".format(self.guid), + "pns-internal-net2_{}".format(self.guid)] + vmtp_conf["vm_name_client"] = "TestClient_{}".format(self.guid) + vmtp_conf["vm_name_server"] = "TestServer_{}".format(self.guid) + vmtp_conf["security_group_name"] = "pns-security{}".format( + self.guid) + vmtp_conf["dns_nameservers"] = [env.get('NAMESERVER')] + conf.write(yaml.dump(vmtp_conf)) + + def run_vmtp(self): + """Run Vmtp and generate charts + + Raises: Exception on error + """ + assert self.cloud + cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir), + '-c', self.config] + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self.__logger.info("%s\n%s", " ".join(cmd), output) + cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir), + '{}/vmtp.json'.format(self.res_dir)] + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self.__logger.info("%s\n%s", " ".join(cmd), output) + with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file: + self.details = json.load(res_file) + + def run(self, **kwargs): + self.start_time = time.time() + status = testcase.TestCase.EX_RUN_ERROR + try: + assert self.cloud + self.image = self.publish_image() + self.flavor = self.create_flavor() + self.generate_keys() + self.write_config() + self.run_vmtp() + self.result = 100 + status = testcase.TestCase.EX_OK + except subprocess.CalledProcessError as cpe: + self.__logger.error( + "Exception when calling %s\n%s", cpe.cmd, cpe.output) + self.result = 0 + except Exception: # pylint: disable=broad-except + self.__logger.exception("Cannot run vmtp") + self.result = 0 + self.stop_time = time.time() + return status + + def clean(self): + try: + assert self.cloud + os.remove(self.privkey_filename) + os.remove(self.pubkey_filename) + self.cloud.delete_image(self.image) + self.cloud.delete_network("pns-internal-net_{}".format(self.guid)) + self.cloud.delete_network("pns-internal-net2_{}".format(self.guid)) + except Exception: # pylint: disable=broad-except + pass diff --git a/functest/tests/unit/openstack/vmtp/__init__.py b/functest/tests/unit/openstack/vmtp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/functest/tests/unit/openstack/vmtp/test_vmtp.py b/functest/tests/unit/openstack/vmtp/test_vmtp.py new file mode 100644 index 000000000..7f8cf40c7 --- /dev/null +++ b/functest/tests/unit/openstack/vmtp/test_vmtp.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +# Copyright (c) 2018 Orange and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 + +# pylint: disable=missing-docstring + +import logging +import unittest + +import mock +import munch +import shade + +from functest.opnfv_tests.openstack.vmtp import vmtp + + +class VmtpInitTesting(unittest.TestCase): + + def _test_exc_init(self): + testcase = vmtp.Vmtp() + self.assertEqual(testcase.case_name, "vmtp") + self.assertEqual(testcase.result, 0) + for func in ['generate_keys', 'write_config', 'run_vmtp']: + with self.assertRaises(AssertionError): + getattr(testcase, func)() + self.assertEqual(testcase.run(), testcase.EX_RUN_ERROR) + self.assertEqual(testcase.clean(), None) + + @mock.patch('os_client_config.get_config', side_effect=Exception) + def test_init1(self, *args): + self._test_exc_init() + args[0].assert_called_once_with() + + @mock.patch('os_client_config.get_config') + @mock.patch('shade.OpenStackCloud', side_effect=Exception) + def test_init2(self, *args): + self._test_exc_init() + args[0].assert_called_once_with(cloud_config=mock.ANY) + args[1].assert_called_once_with() + + @mock.patch('os_client_config.get_config') + @mock.patch('shade.OpenStackCloud') + def test_case_name(self, *args): + testcase = vmtp.Vmtp(case_name="foo") + self.assertEqual(testcase.case_name, "foo") + args[0].assert_called_once_with(cloud_config=mock.ANY) + args[1].assert_called_once_with() + + +class VmtpTesting(unittest.TestCase): + + def setUp(self): + with mock.patch('os_client_config.get_config'), \ + mock.patch('shade.OpenStackCloud'): + self.testcase = vmtp.Vmtp() + self.testcase.cloud = mock.Mock() + self.testcase.cloud.create_keypair.return_value = munch.Munch( + private_key="priv", public_key="pub", id="id") + + @mock.patch('six.moves.builtins.open') + def test_generate_keys1(self, *args): + self.testcase.generate_keys() + self.testcase.cloud.create_keypair.assert_called_once_with( + 'vmtp_{}'.format(self.testcase.guid)) + self.testcase.cloud.delete_keypair.assert_called_once_with('id') + calls = [mock.call(self.testcase.privkey_filename, 'w'), + mock.call(self.testcase.pubkey_filename, 'w')] + args[0].assert_has_calls(calls, any_order=True) + + @mock.patch('six.moves.builtins.open') + def test_generate_keys2(self, *args): + # pylint: disable=bad-continuation + with mock.patch.object( + self.testcase.cloud, "create_keypair", + side_effect=shade.OpenStackCloudException(None)) as mock_obj, \ + self.assertRaises(shade.OpenStackCloudException): + self.testcase.generate_keys() + mock_obj.assert_called_once_with('vmtp_{}'.format(self.testcase.guid)) + args[0].assert_not_called() + +if __name__ == "__main__": + logging.disable(logging.CRITICAL) + unittest.main(verbosity=2) diff --git a/tox.ini b/tox.ini index 46782995f..323762f5b 100644 --- a/tox.ini +++ b/tox.ini @@ -53,12 +53,13 @@ basepython = python2.7 whitelist_externals = bash modules = functest.ci + functest.opnfv_tests.openstack.cinder functest.opnfv_tests.openstack.rally functest.opnfv_tests.openstack.refstack functest.opnfv_tests.openstack.snaps functest.opnfv_tests.openstack.tempest + functest.opnfv_tests.openstack.vmtp functest.opnfv_tests.openstack.vping - functest.opnfv_tests.openstack.cinder functest.opnfv_tests.sdn.odl functest.opnfv_tests.vnf.router functest.tests.unit.ci @@ -66,6 +67,7 @@ modules = functest.tests.unit.openstack.rally functest.tests.unit.openstack.snaps functest.tests.unit.openstack.tempest + functest.tests.unit.openstack.vmtp functest.tests.unit.openstack.vping functest.tests.unit.vnf.router functest.tests.unit.utils -- cgit 1.2.3-korg