From a67b4906eef7e199b2a0949f6723a6d64097f670 Mon Sep 17 00:00:00 2001 From: coreycb Date: Tue, 18 Aug 2020 09:54:09 -0400 Subject: [PATCH 1/5] Use juju model as workspace and store in home (#383) * Use juju model as workspace and store in home The current juju model will now be used as the tempest workspace name. Additionally, all workspaces will be stored in ~/.tempest/. This patch also introduces a new option 'keep-workspace' that can be specified along with other tempest options to keep the workspace after tempest test execution. It defaults to False. Also minor adjustment to smoke option to test boolean value. --- zaza/openstack/charm_tests/tempest/setup.py | 19 +++--- zaza/openstack/charm_tests/tempest/tests.py | 20 ++++-- zaza/openstack/charm_tests/tempest/utils.py | 67 +++++++++++++++++++++ 3 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 zaza/openstack/charm_tests/tempest/utils.py diff --git a/zaza/openstack/charm_tests/tempest/setup.py b/zaza/openstack/charm_tests/tempest/setup.py index af1ee4c..7ce4478 100644 --- a/zaza/openstack/charm_tests/tempest/setup.py +++ b/zaza/openstack/charm_tests/tempest/setup.py @@ -16,11 +16,12 @@ import jinja2 import urllib.parse -import subprocess +import os import zaza.utilities.deployment_env as deployment_env import zaza.openstack.utilities.juju as juju_utils import zaza.openstack.utilities.openstack as openstack_utils +import zaza.openstack.charm_tests.tempest.utils as tempest_utils import zaza.openstack.charm_tests.glance.setup as glance_setup SETUP_ENV_VARS = { @@ -279,21 +280,15 @@ def setup_tempest(tempest_template, accounts_template): :returns: None :rtype: None """ - try: - subprocess.check_call(['tempest', 'workspace', 'remove', '--rmdir', - '--name', 'tempest-workspace']) - except subprocess.CalledProcessError: - pass - try: - subprocess.check_call(['tempest', 'init', 'tempest-workspace']) - except subprocess.CalledProcessError: - pass + workspace_name, workspace_path = tempest_utils.get_workspace() + tempest_utils.destroy_workspace(workspace_name, workspace_path) + tempest_utils.init_workspace(workspace_path) render_tempest_config( - 'tempest-workspace/etc/tempest.conf', + os.path.join(workspace_path, 'etc/tempest.conf'), get_tempest_context(), tempest_template) render_tempest_config( - 'tempest-workspace/etc/accounts.yaml', + os.path.join(workspace_path, 'etc/accounts.yaml'), get_tempest_context(), accounts_template) diff --git a/zaza/openstack/charm_tests/tempest/tests.py b/zaza/openstack/charm_tests/tempest/tests.py index d726930..979caff 100644 --- a/zaza/openstack/charm_tests/tempest/tests.py +++ b/zaza/openstack/charm_tests/tempest/tests.py @@ -20,6 +20,7 @@ import subprocess import zaza import zaza.charm_lifecycle.utils import zaza.charm_lifecycle.test +import zaza.openstack.charm_tests.tempest.utils as tempest_utils import tempfile @@ -33,21 +34,24 @@ class TempestTest(): Test keys are parsed from ['tests_options']['tempest']['model'], where valid test keys are: smoke (bool), whitelist (list of tests), blacklist - (list of tests), and regex (list of regex's). + (list of tests), regex (list of regex's), and keep-workspace (bool). :returns: Status of tempest run :rtype: bool """ + result = True charm_config = zaza.charm_lifecycle.utils.get_charm_config() + workspace_name, workspace_path = tempest_utils.get_workspace() tempest_options = ['tempest', 'run', '--workspace', - 'tempest-workspace', '--config', - 'tempest-workspace/etc/tempest.conf'] + workspace_name, '--config', + os.path.join(workspace_path, 'etc/tempest.conf')] for model_alias in zaza.model.get_juju_model_aliases().keys(): tempest_test_key = model_alias if model_alias == zaza.charm_lifecycle.utils.DEFAULT_MODEL_ALIAS: tempest_test_key = 'default' config = charm_config['tests_options']['tempest'][tempest_test_key] - if config.get('smoke'): + smoke = config.get('smoke') + if smoke and smoke is True: tempest_options.extend(['--smoke']) if config.get('regex'): tempest_options.extend( @@ -74,5 +78,9 @@ class TempestTest(): try: subprocess.check_call(tempest_options) except subprocess.CalledProcessError: - return False - return True + result = False + break + keep_workspace = config.get('keep-workspace') + if not keep_workspace or keep_workspace is not True: + tempest_utils.destroy_workspace(workspace_name, workspace_path) + return result diff --git a/zaza/openstack/charm_tests/tempest/utils.py b/zaza/openstack/charm_tests/tempest/utils.py new file mode 100644 index 0000000..8f3aea7 --- /dev/null +++ b/zaza/openstack/charm_tests/tempest/utils.py @@ -0,0 +1,67 @@ +# Copyright 2020 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utility code for working with tempest workspaces.""" + +import os +from pathlib import Path +import shutil +import subprocess + +import zaza.model as model + + +def get_workspace(): + """Get tempest workspace name and path. + + :returns: A tuple containing tempest workspace name and workspace path + :rtype: Tuple[str, str] + """ + home = str(Path.home()) + workspace_name = model.get_juju_model() + workspace_path = os.path.join(home, '.tempest', workspace_name) + return (workspace_name, workspace_path) + + +def destroy_workspace(workspace_name, workspace_path): + """Delete tempest workspace. + + :param workspace_name: name of workspace + :type workspace_name: str + :param workspace_path: directory path where workspace is stored + :type workspace_path: str + :returns: None + :rtype: None + """ + try: + subprocess.check_call(['tempest', 'workspace', 'remove', '--rmdir', + '--name', workspace_name]) + except subprocess.CalledProcessError: + pass + if os.path.isdir(workspace_path): + shutil.rmtree(workspace_path) + + +def init_workspace(workspace_path): + """Initialize tempest workspace. + + :param workspace_path: directory path where workspace is stored + :type workspace_path: str + :returns: None + :rtype: None + """ + try: + subprocess.check_call(['tempest', 'init', workspace_path]) + except subprocess.CalledProcessError: + pass From c5c964506e18c92cca8bea5b47e9981ae8d17e67 Mon Sep 17 00:00:00 2001 From: Aurelien Lourot Date: Wed, 19 Aug 2020 16:43:04 +0200 Subject: [PATCH 2/5] Increase neutron-arista timeout --- zaza/openstack/charm_tests/neutron_arista/tests.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zaza/openstack/charm_tests/neutron_arista/tests.py b/zaza/openstack/charm_tests/neutron_arista/tests.py index 354dfd1..f9eb2fb 100644 --- a/zaza/openstack/charm_tests/neutron_arista/tests.py +++ b/zaza/openstack/charm_tests/neutron_arista/tests.py @@ -38,9 +38,10 @@ class NeutronCreateAristaNetworkTest(neutron_tests.NeutronCreateNetworkTest): # Sometimes the API call from Neutron to Arista fails and Neutron # retries a couple of seconds later, which is why the newly created # test network may not be immediately visible on Arista's API. + # NOTE(lourot): I experienced a run where it took 53 seconds. for attempt in tenacity.Retrying( wait=tenacity.wait_fixed(10), # seconds - stop=tenacity.stop_after_attempt(3), + stop=tenacity.stop_after_attempt(12), reraise=True): with attempt: actual_network_names = arista_utils.query_fixture_networks( @@ -56,7 +57,7 @@ class NeutronCreateAristaNetworkTest(neutron_tests.NeutronCreateNetworkTest): for attempt in tenacity.Retrying( wait=tenacity.wait_fixed(10), # seconds - stop=tenacity.stop_after_attempt(3), + stop=tenacity.stop_after_attempt(12), reraise=True): with attempt: actual_network_names = arista_utils.query_fixture_networks( From 5455bee2e968124cce5ab726d32fa491011fb28f Mon Sep 17 00:00:00 2001 From: Chris MacNaughton Date: Thu, 20 Aug 2020 08:51:57 +0200 Subject: [PATCH 3/5] Fix protocol rendering for keystone URL Closes #387 --- zaza/openstack/charm_tests/tempest/templates/tempest_v2.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zaza/openstack/charm_tests/tempest/templates/tempest_v2.j2 b/zaza/openstack/charm_tests/tempest/templates/tempest_v2.j2 index f5505ad..83a05ca 100644 --- a/zaza/openstack/charm_tests/tempest/templates/tempest_v2.j2 +++ b/zaza/openstack/charm_tests/tempest/templates/tempest_v2.j2 @@ -34,7 +34,7 @@ attach_encrypted_volume = false {% if 'keystone' in enabled_services %} [identity] -uri = {proto}://{{ keystone }}:5000/v2.0 +uri = {{ proto }}://{{ keystone }}:5000/v2.0 auth_version = v2 admin_role = Admin region = RegionOne From 6a18a37c13bec181375ffa541d1a396652f9431b Mon Sep 17 00:00:00 2001 From: Chris MacNaughton Date: Thu, 20 Aug 2020 17:08:33 +0200 Subject: [PATCH 4/5] Ensure that the workspace deletion doesn't fail with file not found. --- zaza/openstack/charm_tests/tempest/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zaza/openstack/charm_tests/tempest/utils.py b/zaza/openstack/charm_tests/tempest/utils.py index 8f3aea7..52ae126 100644 --- a/zaza/openstack/charm_tests/tempest/utils.py +++ b/zaza/openstack/charm_tests/tempest/utils.py @@ -47,7 +47,7 @@ def destroy_workspace(workspace_name, workspace_path): try: subprocess.check_call(['tempest', 'workspace', 'remove', '--rmdir', '--name', workspace_name]) - except subprocess.CalledProcessError: + except (subprocess.CalledProcessError, FileNotFoundError): pass if os.path.isdir(workspace_path): shutil.rmtree(workspace_path) From d7bc2d32986ebe1718f7e2e3f4d8981a9c71c80c Mon Sep 17 00:00:00 2001 From: Aurelien Lourot Date: Thu, 20 Aug 2020 17:22:31 +0200 Subject: [PATCH 5/5] Revert "Merge pull request #384 from camille-rodriguez/master" This reverts commit 73bab8395bb793578e3992cf4d2a31e89d642791, reversing changes made to c165c42c0030269ea62feda7a6471985e0eb172c. This change introduced a new test under an existing test class, which is a breaking change and prevents us to keep testing older releases. This new test will be soon re-introduced under a new test class. --- zaza/openstack/charm_tests/gnocchi/tests.py | 34 --------------------- 1 file changed, 34 deletions(-) diff --git a/zaza/openstack/charm_tests/gnocchi/tests.py b/zaza/openstack/charm_tests/gnocchi/tests.py index e3b9ae1..680bf3c 100644 --- a/zaza/openstack/charm_tests/gnocchi/tests.py +++ b/zaza/openstack/charm_tests/gnocchi/tests.py @@ -16,15 +16,12 @@ """Encapsulate Gnocchi testing.""" -import base64 import boto3 import logging import pprint from gnocchiclient.v1 import client as gnocchi_client -import zaza.model as model import zaza.openstack.charm_tests.test_utils as test_utils -import zaza.openstack.utilities as utilities import zaza.openstack.utilities.openstack as openstack_utils @@ -92,37 +89,6 @@ class GnocchiS3Test(test_utils.OpenStackBaseTest): # Create AWS compatible application credentials in Keystone cls.ec2_creds = ks_client.ec2.create(user_id, project_id) - def test_upload_external_cert(self): - """Verify that the external CA is uploaded correctly.""" - logging.info('Changing value for trusted-external-ca-cert.') - ca_cert_option = 'trusted-external-ca-cert' - ppk, cert = utilities.cert.generate_cert('gnocchi_test.ci.local') - b64_cert = base64.b64encode(cert).decode() - config = { - ca_cert_option: b64_cert, - } - model.set_application_config( - 'gnocchi', - config - ) - model.block_until_all_units_idle() - - cert_location = '/usr/local/share/ca-certificates' - cert_name = 'gnocchi-external.crt' - cmd = 'ls ' + cert_location + '/' + cert_name - logging.info("Validating that the file {} is created in \ - {}".format(cert_name, cert_location)) - result = model.run_on_unit('gnocchi/0', cmd) - self.assertEqual(result['Code'], '0') - - linked_cert_location = '/etc/ssl/certs' - linked_cert_name = 'gnocchi-external.pem' - cmd = 'ls ' + linked_cert_location + '/' + linked_cert_name - logging.info("Validating that the link {} is created in \ - {}".format(linked_cert_name, linked_cert_location)) - result = model.run_on_unit('gnocchi/0', cmd) - self.assertEqual(result['Code'], '0') - def test_s3_list_gnocchi_buckets(self): """Verify that the gnocchi buckets were created in the S3 backend.""" kwargs = {