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( 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/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 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..52ae126 --- /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, FileNotFoundError): + 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