summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCédric Ollivier <cedric.ollivier@orange.com>2018-06-18 14:18:59 +0200
committerCédric Ollivier <cedric.ollivier@orange.com>2018-06-21 05:40:46 +0200
commit0f6c31a434873068e6c3bfecf31930536bf59d2f (patch)
treeda7c50f3882183734b4fda2c3144745f836b0b2c
parent979161874ba837f55a53aba391966c52433123e6 (diff)
Publish singlevm scenarios
They ease creating all ressources to execute command in a new VM reachable via ssh. This scenarios should be reused by other more advanced ones (shaker, vping, cinder, etc.). Change-Id: If23866827c64a7afbdd8ff596dbc33710ee4ee20 Signed-off-by: Cédric Ollivier <cedric.ollivier@orange.com>
-rw-r--r--docker/healthcheck/testcases.yaml92
-rw-r--r--functest/ci/testcases.yaml92
-rw-r--r--functest/core/singlevm.py283
-rw-r--r--functest/core/tenantnetwork.py1
4 files changed, 408 insertions, 60 deletions
diff --git a/docker/healthcheck/testcases.yaml b/docker/healthcheck/testcases.yaml
index 14d353dc1..9fb64700d 100644
--- a/docker/healthcheck/testcases.yaml
+++ b/docker/healthcheck/testcases.yaml
@@ -28,68 +28,100 @@ tiers:
class: 'ConnectionCheck'
-
- case_name: api_check
+ case_name: tenantnetwork1
project_name: functest
criteria: 100
blocking: true
description: >-
- This test case verifies the retrieval of OpenStack clients:
- Keystone, Glance, Neutron and Nova and may perform some
- simple queries. When the config value of
- snaps.use_keystone is True, functest must have access to
- the cloud's private network.
+ It creates and configures all tenant network ressources
+ required by advanced testcases (subnet, network and
+ router).
dependencies:
installer: ''
- scenario: '^((?!lxd).)*$'
+ scenario: ''
run:
- module: 'functest.opnfv_tests.openstack.snaps.api_check'
- class: 'ApiCheck'
+ module: 'functest.core.tenantnetwork'
+ class: 'TenantNetwork1'
-
- case_name: snaps_health_check
+ case_name: tenantnetwork2
project_name: functest
criteria: 100
blocking: true
description: >-
- This test case creates executes the SimpleHealthCheck
- Python test class which creates an, image, flavor, network,
- and Cirros VM instance and observes the console output to
- validate the single port obtains the correct IP address.
+ It creates new user/project before creating and configuring
+ all tenant network ressources required by a testcase
+ (subnet, network and router).
dependencies:
installer: ''
- scenario: '^((?!lxd).)*$'
+ scenario: ''
run:
- module: 'functest.opnfv_tests.openstack.snaps.health_check'
- class: 'HealthCheck'
+ module: 'functest.core.tenantnetwork'
+ class: 'TenantNetwork2'
-
- case_name: tenantnetwork1
+ case_name: singlevm1
project_name: functest
criteria: 100
- blocking: false
+ blocking: true
description: >-
- It creates and configures all tenant network ressources
- required by advanced testcases (subnet, network and
- router).
+ It inherits from TenantNetwork1 which creates all network
+ resources and completes it by booting a VM attached to that
+ network.
dependencies:
installer: ''
scenario: ''
run:
- module: 'functest.core.tenantnetwork'
- class: 'TenantNetwork1'
+ module: 'functest.core.singlevm'
+ class: 'SingleVm1'
-
- case_name: tenantnetwork2
+ case_name: singlevm2
project_name: functest
criteria: 100
- blocking: false
+ blocking: true
description: >-
It creates new user/project before creating and configuring
- all tenant network ressources required by a testcase
- (subnet, network and router).
+ all tenant network ressources and vms required by advanced
+ testcases.
dependencies:
installer: ''
scenario: ''
run:
- module: 'functest.core.tenantnetwork'
- class: 'TenantNetwork2'
+ module: 'functest.core.singlevm'
+ class: 'SingleVm2'
+
+ -
+ case_name: api_check
+ project_name: functest
+ criteria: 100
+ blocking: true
+ description: >-
+ This test case verifies the retrieval of OpenStack clients:
+ Keystone, Glance, Neutron and Nova and may perform some
+ simple queries. When the config value of
+ snaps.use_keystone is True, functest must have access to
+ the cloud's private network.
+ dependencies:
+ installer: ''
+ scenario: '^((?!lxd).)*$'
+ run:
+ module: 'functest.opnfv_tests.openstack.snaps.api_check'
+ class: 'ApiCheck'
+
+ -
+ case_name: snaps_health_check
+ project_name: functest
+ criteria: 100
+ blocking: true
+ description: >-
+ This test case creates executes the SimpleHealthCheck
+ Python test class which creates an, image, flavor, network,
+ and Cirros VM instance and observes the console output to
+ validate the single port obtains the correct IP address.
+ dependencies:
+ installer: ''
+ scenario: '^((?!lxd).)*$'
+ run:
+ module: 'functest.opnfv_tests.openstack.snaps.health_check'
+ class: 'HealthCheck'
diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml
index 55d9994a6..f20363401 100644
--- a/functest/ci/testcases.yaml
+++ b/functest/ci/testcases.yaml
@@ -28,71 +28,103 @@ tiers:
class: 'ConnectionCheck'
-
- case_name: api_check
+ case_name: tenantnetwork1
project_name: functest
criteria: 100
blocking: true
description: >-
- This test case verifies the retrieval of OpenStack clients:
- Keystone, Glance, Neutron and Nova and may perform some
- simple queries. When the config value of
- snaps.use_keystone is True, functest must have access to
- the cloud's private network.
+ It creates and configures all tenant network ressources
+ required by advanced testcases (subnet, network and
+ router).
dependencies:
installer: ''
- scenario: '^((?!lxd).)*$'
+ scenario: ''
run:
- module: 'functest.opnfv_tests.openstack.snaps.api_check'
- class: 'ApiCheck'
+ module: 'functest.core.tenantnetwork'
+ class: 'TenantNetwork1'
-
- case_name: snaps_health_check
+ case_name: tenantnetwork2
project_name: functest
criteria: 100
blocking: true
description: >-
- This test case creates executes the SimpleHealthCheck
- Python test class which creates an, image, flavor, network,
- and Cirros VM instance and observes the console output to
- validate the single port obtains the correct IP address.
+ It creates new user/project before creating and configuring
+ all tenant network ressources required by a testcase
+ (subnet, network and router).
dependencies:
installer: ''
- scenario: '^((?!lxd).)*$'
+ scenario: ''
run:
- module: 'functest.opnfv_tests.openstack.snaps.health_check'
- class: 'HealthCheck'
+ module: 'functest.core.tenantnetwork'
+ class: 'TenantNetwork2'
-
- case_name: tenantnetwork1
+ case_name: singlevm1
project_name: functest
criteria: 100
- blocking: false
+ blocking: true
description: >-
- It creates and configures all tenant network ressources
- required by advanced testcases (subnet, network and
- router).
+ It inherits from TenantNetwork1 which creates all network
+ resources and completes it by booting a VM attached to that
+ network.
dependencies:
installer: ''
scenario: ''
run:
- module: 'functest.core.tenantnetwork'
- class: 'TenantNetwork1'
+ module: 'functest.core.singlevm'
+ class: 'SingleVm1'
-
- case_name: tenantnetwork2
+ case_name: singlevm2
project_name: functest
criteria: 100
- blocking: false
+ blocking: true
description: >-
It creates new user/project before creating and configuring
- all tenant network ressources required by a testcase
- (subnet, network and router).
+ all tenant network ressources and vms required by advanced
+ testcases.
dependencies:
installer: ''
scenario: ''
run:
- module: 'functest.core.tenantnetwork'
- class: 'TenantNetwork2'
+ module: 'functest.core.singlevm'
+ class: 'SingleVm2'
+
+ -
+ case_name: api_check
+ project_name: functest
+ criteria: 100
+ blocking: true
+ description: >-
+ This test case verifies the retrieval of OpenStack clients:
+ Keystone, Glance, Neutron and Nova and may perform some
+ simple queries. When the config value of
+ snaps.use_keystone is True, functest must have access to
+ the cloud's private network.
+ dependencies:
+ installer: ''
+ scenario: '^((?!lxd).)*$'
+ run:
+ module: 'functest.opnfv_tests.openstack.snaps.api_check'
+ class: 'ApiCheck'
+
+ -
+ case_name: snaps_health_check
+ project_name: functest
+ criteria: 100
+ blocking: true
+ description: >-
+ This test case creates executes the SimpleHealthCheck
+ Python test class which creates an, image, flavor, network,
+ and Cirros VM instance and observes the console output to
+ validate the single port obtains the correct IP address.
+ dependencies:
+ installer: ''
+ scenario: '^((?!lxd).)*$'
+ run:
+ module: 'functest.opnfv_tests.openstack.snaps.health_check'
+ class: 'HealthCheck'
-
name: smoke
diff --git a/functest/core/singlevm.py b/functest/core/singlevm.py
new file mode 100644
index 000000000..c6f4493f5
--- /dev/null
+++ b/functest/core/singlevm.py
@@ -0,0 +1,283 @@
+#!/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
+
+"""Ease deploying a single VM reachable via ssh
+
+It offers a simple way to create all tenant network ressources + a VM for
+advanced testcases (e.g. deploying an orchestrator).
+"""
+
+import logging
+import os
+import tempfile
+import time
+import uuid
+
+import os_client_config
+import paramiko
+import shade
+from xtesting.core import testcase
+
+from functest.core import tenantnetwork
+from functest.utils import config
+
+
+class SingleVm1(tenantnetwork.TenantNetwork1):
+ """Deploy a single VM reachable via ssh (scenario1)
+
+ It inherits from TenantNetwork1 which creates all network resources and
+ completes it by booting a VM attached to that network.
+
+ It ensures that all testcases inheriting from SingleVm1 could work
+ without specific configurations (or at least read the same config data).
+ """
+ # pylint: disable=too-many-instance-attributes
+
+ __logger = logging.getLogger(__name__)
+ filename = '/home/opnfv/functest/images/cirros-0.4.0-x86_64-disk.img'
+ flavor_ram = 1024
+ flavor_vcpus = 1
+ flavor_disk = 1
+ username = 'cirros'
+ ssh_connect_timeout = 60
+
+ def __init__(self, **kwargs):
+ if "case_name" not in kwargs:
+ kwargs["case_name"] = 'singlevm1'
+ super(SingleVm1, self).__init__(**kwargs)
+ self.orig_cloud = self.cloud
+ self.image = None
+ self.sshvm = None
+ self.flavor = None
+ self.sec = None
+ self.fip = None
+ self.keypair = None
+ self.ssh = paramiko.SSHClient()
+ (_, self.key_filename) = tempfile.mkstemp()
+
+ def _publish_image(self):
+ assert self.cloud
+ meta = getattr(
+ config.CONF, '{}_extra_properties'.format(self.case_name), None)
+ self.image = self.cloud.create_image(
+ '{}-img_{}'.format(self.case_name, self.guid),
+ filename=getattr(
+ config.CONF, '{}_image'.format(self.case_name),
+ self.filename),
+ meta=meta)
+ self.__logger.debug("image: %s", self.image)
+
+ def create_sg_rules(self):
+ """Create the security group
+
+ It can be overriden to set other rules according to the services
+ running in the VM
+
+ Raises: Exception on error
+ """
+ assert self.cloud
+ self.sec = self.cloud.create_security_group(
+ '{}-sg_{}'.format(self.case_name, self.guid),
+ 'created by OPNFV Functest ({})'.format(self.case_name))
+ self.cloud.create_security_group_rule(
+ self.sec.id, port_range_min='22', port_range_max='22',
+ protocol='tcp', direction='ingress')
+ self.cloud.create_security_group_rule(
+ self.sec.id, protocol='icmp', direction='ingress')
+
+ def _boot_vm(self):
+ assert self.orig_cloud
+ assert self.cloud
+ self.flavor = self.orig_cloud.create_flavor(
+ '{}-flavor_{}'.format(self.case_name, self.guid),
+ getattr(config.CONF, '{}_flavor_ram'.format(self.case_name),
+ self.flavor_ram),
+ getattr(config.CONF, '{}_flavor_vcpus'.format(self.case_name),
+ self.flavor_vcpus),
+ getattr(config.CONF, '{}_flavor_disk'.format(self.case_name),
+ self.flavor_disk))
+ self.__logger.debug("flavor: %s", self.flavor)
+ self.cloud.set_flavor_specs(
+ self.flavor.id, getattr(config.CONF, 'flavor_extra_specs', {}))
+
+ self.keypair = self.cloud.create_keypair(
+ '{}-kp_{}'.format(self.case_name, self.guid))
+ self.__logger.debug("keypair: %s", self.keypair)
+ self.__logger.debug("private_key: %s", self.keypair.private_key)
+ with open(self.key_filename, 'w') as private_key_file:
+ private_key_file.write(self.keypair.private_key)
+
+ self.sshvm = self.cloud.create_server(
+ '{}-vm_{}'.format(self.case_name, self.guid),
+ image=self.image.id, flavor=self.flavor.id,
+ key_name=self.keypair.id,
+ auto_ip=False, wait=True,
+ network=self.network.id,
+ security_groups=[self.sec.id])
+ self.__logger.debug("vm: %s", self.sshvm)
+ self.fip = self.cloud.create_floating_ip(
+ network=self.ext_net.id, server=self.sshvm)
+ self.__logger.debug("floating_ip: %s", self.fip)
+ self.sshvm = self.cloud.wait_for_server(self.sshvm, auto_ip=False)
+
+ def _connect(self):
+ assert self.cloud
+ p_console = self.cloud.get_server_console(self.sshvm.id)
+ self.__logger.debug("vm console: \n%s", p_console)
+ self.ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
+ for loop in range(6):
+ try:
+ self.ssh.connect(
+ self.sshvm.public_v4,
+ username=getattr(
+ config.CONF,
+ '{}_image_user'.format(self.case_name), self.username),
+ key_filename=self.key_filename,
+ timeout=getattr(
+ config.CONF,
+ '{}_vm_ssh_connect_timeout'.format(self.case_name),
+ self.ssh_connect_timeout))
+ break
+ except Exception: # pylint: disable=broad-except
+ self.__logger.info(
+ "try %s: cannot connect to %s", loop + 1,
+ self.sshvm.public_v4)
+ time.sleep(10)
+ else:
+ self.__logger.error("cannot connect to %s", self.sshvm.public_v4)
+ return False
+ return True
+
+ def execute(self):
+ """Say hello world via ssh
+
+ It can be overriden to execute any command.
+
+ Returns: echo exit codes
+ """
+ (_, stdout, _) = self.ssh.exec_command('echo Hello World')
+ self.__logger.info("output:\n%s", stdout.read())
+ return stdout.channel.recv_exit_status()
+
+ def run(self, **kwargs):
+ """Boot the new VM
+
+ Here are the main actions:
+ - publish the image
+ - add a new ssh key
+ - boot the VM
+ - create the security group
+ - execute the right command over ssh
+
+ Returns:
+ - TestCase.EX_OK
+ - TestCase.EX_RUN_ERROR on error
+ """
+ status = testcase.TestCase.EX_RUN_ERROR
+ try:
+ assert self.cloud
+ super(SingleVm1, self).run(**kwargs)
+ self.result = 0
+ self._publish_image()
+ self.create_sg_rules()
+ self._boot_vm()
+ assert self._connect()
+ if not self.execute():
+ self.result = 100
+ status = testcase.TestCase.EX_OK
+ except Exception: # pylint: disable=broad-except
+ self.__logger.exception('Cannot run %s', self.case_name)
+ finally:
+ self.stop_time = time.time()
+ return status
+
+ def clean(self):
+ try:
+ assert self.orig_cloud
+ assert self.cloud
+ self.cloud.delete_server(self.sshvm, wait=True)
+ self.cloud.delete_security_group(self.sec.id)
+ self.cloud.delete_image(self.image)
+ self.orig_cloud.delete_flavor(self.flavor.id)
+ self.cloud.delete_keypair(self.keypair.id)
+ self.cloud.delete_floating_ip(self.fip.id)
+ self.cloud.delete_image(self.image)
+ except Exception: # pylint: disable=broad-except
+ pass
+
+
+class SingleVm2(SingleVm1):
+ """Deploy a single VM reachable via ssh (scenario2)
+
+ It creates new user/project before creating and configuring all tenant
+ network ressources and vms required by advanced testcases.
+
+ It ensures that all testcases inheriting from SingleVm2 could work
+ without specific configurations (or at least read the same config data).
+ """
+
+ __logger = logging.getLogger(__name__)
+
+ def __init__(self, **kwargs):
+ if "case_name" not in kwargs:
+ kwargs["case_name"] = 'singlevm2'
+ super(SingleVm2, self).__init__(**kwargs)
+ try:
+ assert self.cloud
+ self.domain = self.cloud.get_domain(
+ name_or_id=self.cloud.auth.get(
+ "project_domain_name", "Default"))
+ except Exception: # pylint: disable=broad-except
+ self.domain = None
+ self.__logger.exception("Cannot connect to Cloud")
+ self.project = None
+ self.user = None
+ self.orig_cloud = None
+ self.password = str(uuid.uuid4())
+
+ def run(self, **kwargs):
+ assert self.cloud
+ assert self.domain
+ try:
+ self.project = self.cloud.create_project(
+ name='{}-project_{}'.format(self.case_name, self.guid),
+ description="Created by OPNFV Functest: {}".format(
+ self.case_name),
+ domain_id=self.domain.id)
+ self.__logger.debug("project: %s", self.project)
+ self.user = self.cloud.create_user(
+ name='{}-user_{}'.format(self.case_name, self.guid),
+ password=self.password,
+ default_project=self.project.id,
+ domain_id=self.domain.id)
+ self.__logger.debug("user: %s", self.user)
+ self.orig_cloud = self.cloud
+ os.environ["OS_USERNAME"] = self.user.name
+ os.environ["OS_PROJECT_NAME"] = self.user.default_project_id
+ cloud_config = os_client_config.get_config()
+ self.cloud = shade.OpenStackCloud(cloud_config=cloud_config)
+ os.environ["OS_USERNAME"] = self.orig_cloud.auth["username"]
+ os.environ["OS_PROJECT_NAME"] = self.orig_cloud.auth[
+ "project_name"]
+ except Exception: # pylint: disable=broad-except
+ self.__logger.exception("Cannot create user or project")
+ return testcase.TestCase.EX_RUN_ERROR
+ return super(SingleVm2, self).run(**kwargs)
+
+ def clean(self):
+ try:
+ assert self.cloud
+ assert self.orig_cloud
+ super(SingleVm2, self).clean()
+ assert self.user.id
+ assert self.project.id
+ self.orig_cloud.delete_user(self.user.id)
+ self.orig_cloud.delete_project(self.project.id)
+ except Exception: # pylint: disable=broad-except
+ self.__logger.exception("cannot clean all ressources")
diff --git a/functest/core/tenantnetwork.py b/functest/core/tenantnetwork.py
index e43971fba..4a740d614 100644
--- a/functest/core/tenantnetwork.py
+++ b/functest/core/tenantnetwork.py
@@ -188,6 +188,7 @@ class TenantNetwork2(TenantNetwork1):
def clean(self):
try:
assert self.cloud
+ assert self.orig_cloud
super(TenantNetwork2, self).clean()
assert self.user.id
assert self.project.id