Allow tempest to run in minimal mode (#956)

Add test class that runs tempest in miminal mode. This is useful
for testing that the OpenStack apis are responding but there are
components not configured like an external network. In addtion
some missing doc strings were added and support for neutron
tempest configuration pre ussuri removed as there is a branch
for that.
This commit is contained in:
Liam Young
2022-10-20 11:18:04 +01:00
committed by GitHub
parent 6662503432
commit 827d81fc12
2 changed files with 88 additions and 42 deletions

View File

@@ -122,6 +122,23 @@ class TempestTestWithKeystoneV3(TempestTestBase):
return super().run()
class TempestTestWithKeystoneMinimal(TempestTestBase):
"""Tempest test class to validate an OpenStack setup with Keystone V2."""
def run(self):
"""Run tempest tests as specified in tests/tests.yaml.
Allow test to run even if some components are missing (like
external network setup).
See TempestTestBase.run() for the available test options.
:returns: Status of tempest run
:rtype: bool
"""
tempest_utils.render_tempest_config_keystone_v3(minimal=True)
return super().run()
class TempestTest(TempestTestBase):
"""Tempest test class.

View File

@@ -21,6 +21,8 @@ import shutil
import subprocess
import urllib.parse
from neutronclient.common import exceptions as neutronexceptions
import zaza.model as model
import zaza.utilities.deployment_env as deployment_env
import zaza.openstack.utilities.juju as juju_utils
@@ -51,13 +53,18 @@ def render_tempest_config_keystone_v2():
_setup_tempest('tempest_v2.j2', 'accounts.j2')
def render_tempest_config_keystone_v3():
def render_tempest_config_keystone_v3(minimal=False):
"""Render tempest config for Keystone V3 API.
:param minimal: Run in minimal mode eg ignore missing setup
:type minimal: bool
:returns: None
:rtype: None
"""
_setup_tempest('tempest_v3.j2', 'accounts.j2')
_setup_tempest(
'tempest_v3.j2',
'accounts.j2',
minimal=minimal)
def get_workspace():
@@ -105,20 +112,22 @@ def _init_workspace(workspace_path):
pass
def _setup_tempest(tempest_template, accounts_template):
def _setup_tempest(tempest_template, accounts_template, minimal=False):
"""Initialize tempest and render tempest config.
:param tempest_template: tempest.conf template
:type tempest_template: module
:param accounts_template: accounts.yaml template
:type accounts_template: module
:param minimal: Run in minimal mode eg ignore missing setup
:type minimal: bool
:returns: None
:rtype: None
"""
workspace_name, workspace_path = get_workspace()
destroy_workspace(workspace_name, workspace_path)
_init_workspace(workspace_path)
context = _get_tempest_context(workspace_path)
context = _get_tempest_context(workspace_path, missing_fatal=not minimal)
_render_tempest_config(
os.path.join(workspace_path, 'etc/tempest.conf'),
context,
@@ -129,9 +138,13 @@ def _setup_tempest(tempest_template, accounts_template):
accounts_template)
def _get_tempest_context(workspace_path):
def _get_tempest_context(workspace_path, missing_fatal=True):
"""Generate the tempest config context.
:param workspace_path: path to workspace directory
:type workspace_path: str
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: Context dictionary
:rtype: dict
"""
@@ -153,8 +166,14 @@ def _get_tempest_context(workspace_path):
_add_application_ips(ctxt)
for svc_name, ctxt_func in ctxt_funcs.items():
if svc_name in ctxt['enabled_services']:
ctxt_func(ctxt, keystone_session)
_add_environment_var_config(ctxt, ctxt['enabled_services'])
ctxt_func(
ctxt,
keystone_session,
missing_fatal=missing_fatal)
_add_environment_var_config(
ctxt,
ctxt['enabled_services'],
missing_fatal=missing_fatal)
_add_auth_config(ctxt)
if 'octavia' in ctxt['enabled_services']:
_add_octavia_config(ctxt)
@@ -194,13 +213,15 @@ def _add_application_ips(ctxt):
ctxt['ncc'] = juju_utils.get_application_ip('nova-cloud-controller')
def _add_nova_config(ctxt, keystone_session):
def _add_nova_config(ctxt, keystone_session, missing_fatal=True):
"""Add nova config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param keystone_session: keystoneauth1.session.Session object
:type: keystoneauth1.session.Session
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
"""
@@ -213,54 +234,52 @@ def _add_nova_config(ctxt, keystone_session):
ctxt['flavor_ref_alt'] = flavor.id
def _add_neutron_config(ctxt, keystone_session):
def _add_neutron_config(ctxt, keystone_session, missing_fatal=True):
"""Add neutron config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param keystone_session: keystoneauth1.session.Session object
:type: keystoneauth1.session.Session
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
"""
current_release = openstack_utils.get_os_release()
focal_ussuri = openstack_utils.get_os_release('focal_ussuri')
neutron_client = openstack_utils.get_neutron_session_client(
keystone_session)
net = neutron_client.find_resource("network", "ext_net")
ctxt['ext_net'] = net['id']
router = neutron_client.find_resource("router", "provider-router")
ctxt['provider_router_id'] = router['id']
# For focal+ with OVN, we use the same settings as upstream gate.
# This is because the l3_agent_scheduler extension is only
# applicable for OVN when conventional layer-3 agent enabled:
# https://docs.openstack.org/networking-ovn/2.0.1/features.html
# This enables test_list_show_extensions to run successfully.
if current_release >= focal_ussuri:
extensions = ('address-scope,agent,allowed-address-pairs,'
'auto-allocated-topology,availability_zone,'
'binding,default-subnetpools,external-net,'
'extra_dhcp_opt,multi-provider,net-mtu,'
'network_availability_zone,network-ip-availability,'
'port-security,provider,quotas,rbac-address-scope,'
'rbac-policies,standard-attr-revisions,security-group,'
'standard-attr-description,subnet_allocation,'
'standard-attr-tag,standard-attr-timestamp,trunk,'
'quota_details,router,extraroute,ext-gw-mode,'
'fip-port-details,pagination,sorting,project-id,'
'dns-integration,qos')
ctxt['neutron_api_extensions'] = extensions
else:
ctxt['neutron_api_extensions'] = 'all'
try:
net = neutron_client.find_resource("network", "ext_net")
ctxt['ext_net'] = net['id']
router = neutron_client.find_resource("router", "provider-router")
ctxt['provider_router_id'] = router['id']
except neutronexceptions.NotFound:
if missing_fatal:
raise
extensions = ('address-scope,agent,allowed-address-pairs,'
'auto-allocated-topology,availability_zone,'
'binding,default-subnetpools,external-net,'
'extra_dhcp_opt,multi-provider,net-mtu,'
'network_availability_zone,network-ip-availability,'
'port-security,provider,quotas,rbac-address-scope,'
'rbac-policies,standard-attr-revisions,security-group,'
'standard-attr-description,subnet_allocation,'
'standard-attr-tag,standard-attr-timestamp,trunk,'
'quota_details,router,extraroute,ext-gw-mode,'
'fip-port-details,pagination,sorting,project-id,'
'dns-integration,qos')
ctxt['neutron_api_extensions'] = extensions
def _add_glance_config(ctxt, keystone_session):
def _add_glance_config(ctxt, keystone_session, missing_fatal=True):
"""Add glance config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param keystone_session: keystoneauth1.session.Session object
:type: keystoneauth1.session.Session
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
"""
@@ -276,13 +295,15 @@ def _add_glance_config(ctxt, keystone_session):
ctxt['image_alt_id'] = image_alt[0].id
def _add_cinder_config(ctxt, keystone_session):
def _add_cinder_config(ctxt, keystone_session, missing_fatal=True):
"""Add cinder config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param keystone_session: keystoneauth1.session.Session object
:type: keystoneauth1.session.Session
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
"""
@@ -297,13 +318,15 @@ def _add_cinder_config(ctxt, keystone_session):
break
def _add_keystone_config(ctxt, keystone_session):
def _add_keystone_config(ctxt, keystone_session, missing_fatal=True):
"""Add keystone config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param keystone_session: keystoneauth1.session.Session object
:type: keystoneauth1.session.Session
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
"""
@@ -313,11 +336,13 @@ def _add_keystone_config(ctxt, keystone_session):
ctxt['default_domain_id'] = domain.id
def _add_octavia_config(ctxt):
def _add_octavia_config(ctxt, missing_fatal=True):
"""Add octavia config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
:raises: subprocess.CalledProcessError
@@ -334,11 +359,15 @@ def _add_octavia_config(ctxt):
])
def _add_environment_var_config(ctxt, services):
def _add_environment_var_config(ctxt, services, missing_fatal=True):
"""Add environment variable config to context.
:param ctxt: Context dictionary
:type ctxt: dict
:param services: List of services
:type services: List[str]
:param missing_fatal: Raise an exception if a resource is missing
:type missing_fatal: bool
:returns: None
:rtype: None
"""
@@ -353,7 +382,7 @@ def _add_environment_var_config(ctxt, services):
else:
if var not in IGNORABLE_VARS:
missing_vars.append(var)
if missing_vars:
if missing_vars and missing_fatal:
raise ValueError(
("Environment variables [{}] must all be set to run this"
" test").format(', '.join(missing_vars)))