Add Vmtp as a new testcase 01/58401/7
authorCédric Ollivier <cedric.ollivier@orange.com>
Tue, 5 Jun 2018 19:04:54 +0000 (21:04 +0200)
committerCédric Ollivier <ollivier.cedric@gmail.com>
Mon, 9 Jul 2018 12:07:36 +0000 (14:07 +0200)
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 <cedric.ollivier@orange.com>
docker/smoke/Dockerfile
docker/smoke/testcases.yaml
functest/ci/config_aarch64_patch.yaml
functest/ci/config_patch.yaml
functest/ci/testcases.yaml
functest/opnfv_tests/openstack/vmtp/__init__.py [new file with mode: 0644]
functest/opnfv_tests/openstack/vmtp/vmtp.py [new file with mode: 0644]
functest/tests/unit/openstack/vmtp/__init__.py [new file with mode: 0644]
functest/tests/unit/openstack/vmtp/test_vmtp.py [new file with mode: 0644]
tox.ini

index 87b28f0..4d239e5 100644 (file)
@@ -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 && \
index 5a93a1d..0d16879 100644 (file)
@@ -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
index b288641..00020af 100644 (file)
@@ -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:
index c2c6cb4..c2bfe33 100644 (file)
@@ -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'}
index 44685a1..48e6474 100644 (file)
@@ -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 (file)
index 0000000..e69de29
diff --git a/functest/opnfv_tests/openstack/vmtp/vmtp.py b/functest/opnfv_tests/openstack/vmtp/vmtp.py
new file mode 100644 (file)
index 0000000..52d1d6d
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/functest/tests/unit/openstack/vmtp/test_vmtp.py b/functest/tests/unit/openstack/vmtp/test_vmtp.py
new file mode 100644 (file)
index 0000000..7f8cf40
--- /dev/null
@@ -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 4678299..323762f 100644 (file)
--- 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