Merge pull request #302 from coreycb/add-tempest-support-corey
Add tempest support
This commit is contained in:
@@ -28,11 +28,11 @@ def basic_setup():
|
||||
tests.
|
||||
"""
|
||||
current_release = openstack_utils.get_os_release()
|
||||
xenial_pike = openstack_utils.get_os_release('xenial_pike')
|
||||
xenial_ocata = openstack_utils.get_os_release('xenial_ocata')
|
||||
|
||||
if current_release < xenial_pike:
|
||||
if current_release < xenial_ocata:
|
||||
logging.info(
|
||||
'Skipping ceilometer-upgrade as it is not supported before Pike')
|
||||
'Skipping ceilometer-upgrade as it is not supported before ocata')
|
||||
return
|
||||
|
||||
logging.debug('Checking ceilometer-upgrade')
|
||||
|
||||
@@ -18,6 +18,7 @@ import logging
|
||||
import zaza.openstack.utilities.openstack as openstack_utils
|
||||
|
||||
CIRROS_IMAGE_NAME = "cirros"
|
||||
CIRROS_ALT_IMAGE_NAME = "cirros_alt"
|
||||
LTS_RELEASE = "bionic"
|
||||
LTS_IMAGE_NAME = "bionic"
|
||||
|
||||
@@ -77,6 +78,18 @@ def add_cirros_image(glance_client=None, image_name=None):
|
||||
image_name=image_name)
|
||||
|
||||
|
||||
def add_cirros_alt_image(glance_client=None, image_name=None):
|
||||
"""Add alt cirros image to the current deployment.
|
||||
|
||||
:param glance: Authenticated glanceclient
|
||||
:type glance: glanceclient.Client
|
||||
:param image_name: Label for the image in glance
|
||||
:type image_name: str
|
||||
"""
|
||||
image_name = image_name or CIRROS_ALT_IMAGE_NAME
|
||||
add_cirros_image(glance_client, image_name)
|
||||
|
||||
|
||||
def add_lts_image(glance_client=None, image_name=None, release=None):
|
||||
"""Add an Ubuntu LTS image to the current deployment.
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ DEMO_ADMIN_USER_PASSWORD = 'password'
|
||||
DEMO_USER = 'demo'
|
||||
DEMO_PASSWORD = 'password'
|
||||
|
||||
TEMPEST_ROLES = ['member', 'ResellerAdmin']
|
||||
|
||||
|
||||
class BaseKeystoneTest(test_utils.OpenStackBaseTest):
|
||||
"""Base for Keystone charm tests."""
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
"""Code for setting up keystone."""
|
||||
|
||||
import keystoneauth1
|
||||
|
||||
import zaza.openstack.utilities.openstack as openstack_utils
|
||||
from zaza.openstack.charm_tests.keystone import (
|
||||
BaseKeystoneTest,
|
||||
@@ -24,6 +26,7 @@ from zaza.openstack.charm_tests.keystone import (
|
||||
DEMO_ADMIN_USER_PASSWORD,
|
||||
DEMO_USER,
|
||||
DEMO_PASSWORD,
|
||||
TEMPEST_ROLES,
|
||||
)
|
||||
|
||||
|
||||
@@ -115,3 +118,30 @@ def add_demo_user():
|
||||
else:
|
||||
# create only V3 user
|
||||
_v3()
|
||||
|
||||
|
||||
def _add_additional_roles(roles):
|
||||
"""Add additional roles to this deployment.
|
||||
|
||||
:param ctxt: roles
|
||||
:type ctxt: list
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
keystone_client = openstack_utils.get_keystone_session_client(
|
||||
keystone_session)
|
||||
for role_name in roles:
|
||||
try:
|
||||
keystone_client.roles.create(role_name)
|
||||
except keystoneauth1.exceptions.http.Conflict:
|
||||
pass
|
||||
|
||||
|
||||
def add_tempest_roles():
|
||||
"""Add tempest roles to this deployment.
|
||||
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
_add_additional_roles(TEMPEST_ROLES)
|
||||
|
||||
@@ -35,5 +35,15 @@ FLAVORS = {
|
||||
'ram': 8192,
|
||||
'disk': 40,
|
||||
'vcpus': 4},
|
||||
'm1.tempest': {
|
||||
'flavorid': 6,
|
||||
'ram': 256,
|
||||
'disk': 1,
|
||||
'vcpus': 1},
|
||||
'm2.tempest': {
|
||||
'flavorid': 7,
|
||||
'ram': 512,
|
||||
'disk': 1,
|
||||
'vcpus': 1},
|
||||
}
|
||||
KEYPAIR_NAME = 'zaza'
|
||||
|
||||
15
zaza/openstack/charm_tests/tempest/__init__.py
Normal file
15
zaza/openstack/charm_tests/tempest/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
"""Collection of code for setting up and running tempest."""
|
||||
291
zaza/openstack/charm_tests/tempest/setup.py
Normal file
291
zaza/openstack/charm_tests/tempest/setup.py
Normal file
@@ -0,0 +1,291 @@
|
||||
# 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.
|
||||
|
||||
"""Code for configuring and initializing tempest."""
|
||||
|
||||
import urllib.parse
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
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.glance.setup as glance_setup
|
||||
import zaza.openstack.charm_tests.tempest.templates.tempest_v2 as tempest_v2
|
||||
import zaza.openstack.charm_tests.tempest.templates.tempest_v3 as tempest_v3
|
||||
import zaza.openstack.charm_tests.tempest.templates.accounts as accounts
|
||||
|
||||
SETUP_ENV_VARS = [
|
||||
'TEST_GATEWAY',
|
||||
'TEST_CIDR_EXT',
|
||||
'TEST_FIP_RANGE',
|
||||
'TEST_NAMESERVER',
|
||||
'TEST_CIDR_PRIV',
|
||||
'TEST_SWIFT_IP',
|
||||
]
|
||||
TEMPEST_FLAVOR_NAME = 'm1.tempest'
|
||||
TEMPEST_ALT_FLAVOR_NAME = 'm2.tempest'
|
||||
|
||||
|
||||
def add_application_ips(ctxt):
|
||||
"""Add application access IPs to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
ctxt['keystone'] = juju_utils.get_application_ip('keystone')
|
||||
ctxt['dashboard'] = juju_utils.get_application_ip('openstack-dashboard')
|
||||
ctxt['ncc'] = juju_utils.get_application_ip('nova-cloud-controller')
|
||||
|
||||
|
||||
def add_nova_config(ctxt, keystone_session):
|
||||
"""Add nova config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:param keystone_session: keystoneauth1.session.Session object
|
||||
:type: keystoneauth1.session.Session
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
nova_client = openstack_utils.get_nova_session_client(
|
||||
keystone_session)
|
||||
for flavor in nova_client.flavors.list():
|
||||
if flavor.name == TEMPEST_FLAVOR_NAME:
|
||||
ctxt['flavor_ref'] = flavor.id
|
||||
if flavor.name == TEMPEST_ALT_FLAVOR_NAME:
|
||||
ctxt['flavor_ref_alt'] = flavor.id
|
||||
|
||||
|
||||
def add_neutron_config(ctxt, keystone_session):
|
||||
"""Add neutron config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:param keystone_session: keystoneauth1.session.Session object
|
||||
:type: keystoneauth1.session.Session
|
||||
: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'
|
||||
|
||||
|
||||
def add_glance_config(ctxt, keystone_session):
|
||||
"""Add glance config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:param keystone_session: keystoneauth1.session.Session object
|
||||
:type: keystoneauth1.session.Session
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
glance_client = openstack_utils.get_glance_session_client(
|
||||
keystone_session)
|
||||
image = openstack_utils.get_images_by_name(
|
||||
glance_client, glance_setup.CIRROS_IMAGE_NAME)
|
||||
image_alt = openstack_utils.get_images_by_name(
|
||||
glance_client, glance_setup.CIRROS_ALT_IMAGE_NAME)
|
||||
if image:
|
||||
ctxt['image_id'] = image[0].id
|
||||
if image_alt:
|
||||
ctxt['image_alt_id'] = image_alt[0].id
|
||||
|
||||
|
||||
def add_cinder_config(ctxt, keystone_session):
|
||||
"""Add cinder config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:param keystone_session: keystoneauth1.session.Session object
|
||||
:type: keystoneauth1.session.Session
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
volume_types = ['volumev2', 'volumev3']
|
||||
keystone_client = openstack_utils.get_keystone_session_client(
|
||||
keystone_session)
|
||||
for volume_type in volume_types:
|
||||
service = keystone_client.services.list(type=volume_type)
|
||||
if service:
|
||||
ctxt['catalog_type'] = volume_type
|
||||
break
|
||||
|
||||
|
||||
def add_keystone_config(ctxt, keystone_session):
|
||||
"""Add keystone config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:param keystone_session: keystoneauth1.session.Session object
|
||||
:type: keystoneauth1.session.Session
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
keystone_client = openstack_utils.get_keystone_session_client(
|
||||
keystone_session)
|
||||
domain = keystone_client.domains.find(name="admin_domain")
|
||||
ctxt['default_domain_id'] = domain.id
|
||||
|
||||
|
||||
def add_environment_var_config(ctxt):
|
||||
"""Add environment variable config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
deploy_env = deployment_env.get_deployment_context()
|
||||
for var in SETUP_ENV_VARS:
|
||||
value = deploy_env.get(var)
|
||||
if value:
|
||||
ctxt[var.lower()] = value
|
||||
else:
|
||||
raise ValueError(
|
||||
("Environment variables {} must all be set to run this"
|
||||
" test").format(', '.join(SETUP_ENV_VARS)))
|
||||
|
||||
|
||||
def add_auth_config(ctxt):
|
||||
"""Add authorization config to context.
|
||||
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
overcloud_auth = openstack_utils.get_overcloud_auth()
|
||||
ctxt['proto'] = urllib.parse.urlparse(overcloud_auth['OS_AUTH_URL']).scheme
|
||||
ctxt['admin_username'] = overcloud_auth['OS_USERNAME']
|
||||
ctxt['admin_password'] = overcloud_auth['OS_PASSWORD']
|
||||
if overcloud_auth['API_VERSION'] == 3:
|
||||
ctxt['admin_project_name'] = overcloud_auth['OS_PROJECT_NAME']
|
||||
ctxt['admin_domain_name'] = overcloud_auth['OS_DOMAIN_NAME']
|
||||
ctxt['default_credentials_domain_name'] = (
|
||||
overcloud_auth['OS_PROJECT_DOMAIN_NAME'])
|
||||
|
||||
|
||||
def get_tempest_context():
|
||||
"""Generate the tempest config context.
|
||||
|
||||
:returns: Context dictionary
|
||||
:rtype: dict
|
||||
"""
|
||||
keystone_session = openstack_utils.get_overcloud_keystone_session()
|
||||
ctxt = {}
|
||||
add_application_ips(ctxt)
|
||||
add_nova_config(ctxt, keystone_session)
|
||||
add_neutron_config(ctxt, keystone_session)
|
||||
add_glance_config(ctxt, keystone_session)
|
||||
add_cinder_config(ctxt, keystone_session)
|
||||
add_keystone_config(ctxt, keystone_session)
|
||||
add_environment_var_config(ctxt)
|
||||
add_auth_config(ctxt)
|
||||
return ctxt
|
||||
|
||||
|
||||
def render_tempest_config(target_file, ctxt, template):
|
||||
"""Render tempest config for specified config file and template.
|
||||
|
||||
:param target_file: Name of file to render config to
|
||||
:type target_file: str
|
||||
:param ctxt: Context dictionary
|
||||
:type ctxt: dict
|
||||
:param template: Template module
|
||||
:type template: module
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
# TODO: switch to jinja2 and generate config based on available services
|
||||
with open(target_file, 'w') as f:
|
||||
f.write(template.file_contents.format(**ctxt))
|
||||
|
||||
|
||||
def setup_tempest(tempest_template, accounts_template):
|
||||
"""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
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
if os.path.isdir('tempest-workspace'):
|
||||
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
|
||||
render_tempest_config(
|
||||
'tempest-workspace/etc/tempest.conf',
|
||||
get_tempest_context(),
|
||||
tempest_template)
|
||||
render_tempest_config(
|
||||
'tempest-workspace/etc/accounts.yaml',
|
||||
get_tempest_context(),
|
||||
accounts_template)
|
||||
|
||||
|
||||
def render_tempest_config_keystone_v2():
|
||||
"""Render tempest config for Keystone V2 API.
|
||||
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
setup_tempest(tempest_v2, accounts)
|
||||
|
||||
|
||||
def render_tempest_config_keystone_v3():
|
||||
"""Render tempest config for Keystone V3 API.
|
||||
|
||||
:returns: None
|
||||
:rtype: None
|
||||
"""
|
||||
setup_tempest(tempest_v3, accounts)
|
||||
15
zaza/openstack/charm_tests/tempest/templates/__init__.py
Normal file
15
zaza/openstack/charm_tests/tempest/templates/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
"""Collection of templates for tempest."""
|
||||
9
zaza/openstack/charm_tests/tempest/templates/accounts.py
Normal file
9
zaza/openstack/charm_tests/tempest/templates/accounts.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# flake8: noqa
|
||||
file_contents = """
|
||||
- username: 'demo'
|
||||
tenant_name: 'demo'
|
||||
password: 'pass'
|
||||
- username: 'alt_demo'
|
||||
tenant_name: 'alt_demo'
|
||||
password: 'secret'
|
||||
"""
|
||||
96
zaza/openstack/charm_tests/tempest/templates/tempest_v2.py
Normal file
96
zaza/openstack/charm_tests/tempest/templates/tempest_v2.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# flake8: noqa
|
||||
file_contents = """
|
||||
[DEFAULT]
|
||||
debug = false
|
||||
use_stderr = false
|
||||
log_file = tempest.log
|
||||
|
||||
[auth]
|
||||
test_accounts_file = accounts.yaml
|
||||
default_credentials_domain_name = Default
|
||||
admin_username = {admin_username}
|
||||
admin_project_name = admin
|
||||
admin_password = {admin_password}
|
||||
admin_domain_name = Default
|
||||
|
||||
[compute]
|
||||
image_ref = {image_id}
|
||||
image_ref_alt = {image_alt_id}
|
||||
flavor_ref = {flavor_ref}
|
||||
flavor_ref_alt = {flavor_ref_alt}
|
||||
region = RegionOne
|
||||
min_compute_nodes = 3
|
||||
|
||||
# TODO: review this as its release specific
|
||||
# min_microversion = 2.2
|
||||
# max_microversion = latest
|
||||
|
||||
[compute-feature-enabled]
|
||||
console_output = true
|
||||
resize = true
|
||||
live_migration = true
|
||||
block_migration_for_live_migration = true
|
||||
attach_encrypted_volume = false
|
||||
|
||||
[identity]
|
||||
uri = {proto}://{keystone}:5000/v2.0
|
||||
auth_version = v2
|
||||
admin_role = Admin
|
||||
region = RegionOne
|
||||
disable_ssl_certificate_validation = true
|
||||
|
||||
[identity-feature-enabled]
|
||||
api_v2 = true
|
||||
api_v3 = false
|
||||
|
||||
[image]
|
||||
http_image = http://{test_swift_ip}:80/swift/v1/images/cirros-0.3.4-x86_64-uec.tar.gz
|
||||
|
||||
[network]
|
||||
project_network_cidr = {test_cidr_priv}
|
||||
public_network_id = {ext_net}
|
||||
dns_servers = {test_nameserver}
|
||||
project_networks_reachable = false
|
||||
|
||||
[network-feature-enabled]
|
||||
ipv6 = false
|
||||
|
||||
[orchestration]
|
||||
stack_owner_role = Admin
|
||||
instance_type = m1.small
|
||||
keypair_name = testkey
|
||||
|
||||
[oslo_concurrency]
|
||||
lock_path = /tmp
|
||||
|
||||
[scenario]
|
||||
img_dir = /home/ubuntu/images
|
||||
img_file = cirros-0.3.4-x86_64-disk.img
|
||||
img_container_format = bare
|
||||
img_disk_format = qcow2
|
||||
|
||||
[validation]
|
||||
run_validation = true
|
||||
image_ssh_user = cirros
|
||||
|
||||
[service_available]
|
||||
ceilometer = true
|
||||
cinder = true
|
||||
glance = true
|
||||
heat = true
|
||||
horizon = true
|
||||
ironic = false
|
||||
neutron = true
|
||||
nova = true
|
||||
sahara = false
|
||||
swift = true
|
||||
trove = false
|
||||
zaqar = false
|
||||
|
||||
[volume]
|
||||
backend_names = cinder-ceph
|
||||
storage_protocol = ceph
|
||||
catalog_type = {catalog_type}
|
||||
|
||||
[volume-feature-enabled]
|
||||
backup = false"""
|
||||
100
zaza/openstack/charm_tests/tempest/templates/tempest_v3.py
Normal file
100
zaza/openstack/charm_tests/tempest/templates/tempest_v3.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# flake8: noqa
|
||||
file_contents = """
|
||||
[DEFAULT]
|
||||
debug = false
|
||||
use_stderr = false
|
||||
log_file = tempest.log
|
||||
|
||||
[auth]
|
||||
test_accounts_file = accounts.yaml
|
||||
default_credentials_domain_name = {default_credentials_domain_name}
|
||||
admin_username = {admin_username}
|
||||
admin_project_name = {admin_project_name}
|
||||
admin_password = {admin_password}
|
||||
admin_domain_name = {admin_domain_name}
|
||||
|
||||
[compute]
|
||||
image_ref = {image_id}
|
||||
image_ref_alt = {image_alt_id}
|
||||
flavor_ref = {flavor_ref}
|
||||
flavor_ref_alt = {flavor_ref_alt}
|
||||
min_compute_nodes = 3
|
||||
|
||||
# TODO: review this as its release specific
|
||||
# min_microversion = 2.2
|
||||
# max_microversion = latest
|
||||
|
||||
[compute-feature-enabled]
|
||||
console_output = true
|
||||
resize = true
|
||||
live_migration = true
|
||||
block_migration_for_live_migration = true
|
||||
attach_encrypted_volume = false
|
||||
|
||||
[identity]
|
||||
uri = {proto}://{keystone}:5000/v2.0
|
||||
uri_v3 = {proto}://{keystone}:5000/v3
|
||||
auth_version = v3
|
||||
admin_role = Admin
|
||||
region = RegionOne
|
||||
default_domain_id = {default_domain_id}
|
||||
admin_domain_scope = true
|
||||
disable_ssl_certificate_validation = true
|
||||
|
||||
[identity-feature-enabled]
|
||||
api_v2 = false
|
||||
api_v3 = true
|
||||
|
||||
[image]
|
||||
http_image = http://{test_swift_ip}:80/swift/v1/images/cirros-0.3.4-x86_64-uec.tar.gz
|
||||
|
||||
[network]
|
||||
project_network_cidr = {test_cidr_priv}
|
||||
public_network_id = {ext_net}
|
||||
dns_servers = {test_nameserver}
|
||||
project_networks_reachable = false
|
||||
floating_network_name = {ext_net}
|
||||
|
||||
[network-feature-enabled]
|
||||
ipv6 = false
|
||||
api_extensions = {neutron_api_extensions}
|
||||
|
||||
[orchestration]
|
||||
stack_owner_role = Admin
|
||||
instance_type = m1.small
|
||||
keypair_name = testkey
|
||||
|
||||
[oslo_concurrency]
|
||||
lock_path = /tmp
|
||||
|
||||
[scenario]
|
||||
img_dir = /home/ubuntu/images
|
||||
img_file = cirros-0.3.4-x86_64-disk.img
|
||||
img_container_format = bare
|
||||
img_disk_format = qcow2
|
||||
|
||||
[validation]
|
||||
run_validation = true
|
||||
image_ssh_user = cirros
|
||||
|
||||
[service_available]
|
||||
ceilometer = true
|
||||
cinder = true
|
||||
glance = true
|
||||
heat = true
|
||||
horizon = true
|
||||
ironic = false
|
||||
neutron = true
|
||||
nova = true
|
||||
sahara = false
|
||||
swift = true
|
||||
trove = false
|
||||
zaqar = false
|
||||
|
||||
[volume]
|
||||
backend_names = cinder-ceph
|
||||
storage_protocol = ceph
|
||||
catalog_type = {catalog_type}
|
||||
|
||||
[volume-feature-enabled]
|
||||
backup = false"""
|
||||
78
zaza/openstack/charm_tests/tempest/tests.py
Normal file
78
zaza/openstack/charm_tests/tempest/tests.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# 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.
|
||||
|
||||
"""Code for running tempest tests."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import zaza
|
||||
import zaza.charm_lifecycle.utils
|
||||
import zaza.charm_lifecycle.test
|
||||
import tempfile
|
||||
|
||||
|
||||
class TempestTest():
|
||||
"""Tempest test class."""
|
||||
|
||||
test_runner = zaza.charm_lifecycle.test.DIRECT
|
||||
|
||||
def run(self):
|
||||
"""Run tempest tests as specified in tests/tests.yaml.
|
||||
|
||||
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).
|
||||
|
||||
:returns: Status of tempest run
|
||||
:rtype: bool
|
||||
"""
|
||||
charm_config = zaza.charm_lifecycle.utils.get_charm_config()
|
||||
tempest_options = ['tempest', 'run', '--workspace',
|
||||
'tempest-workspace', '--config',
|
||||
'tempest-workspace/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'):
|
||||
tempest_options.extend(['--smoke'])
|
||||
if config.get('regex'):
|
||||
tempest_options.extend(
|
||||
['--regex',
|
||||
' '.join([reg for reg in config.get('regex')])])
|
||||
if config.get('black-regex'):
|
||||
tempest_options.extend(
|
||||
['--black-regex',
|
||||
' '.join([reg for reg in config.get('black-regex')])])
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
if config.get('whitelist'):
|
||||
white_file = os.path.join(tmpdirname, 'white.cfg')
|
||||
with open(white_file, 'w') as f:
|
||||
f.write('\n'.join(config.get('whitelist')))
|
||||
f.write('\n')
|
||||
tempest_options.extend(['--whitelist-file', white_file])
|
||||
if config.get('blacklist'):
|
||||
black_file = os.path.join(tmpdirname, 'black.cfg')
|
||||
with open(black_file, 'w') as f:
|
||||
f.write('\n'.join(config.get('blacklist')))
|
||||
f.write('\n')
|
||||
tempest_options.extend(['--blacklist-file', black_file])
|
||||
print(tempest_options)
|
||||
try:
|
||||
subprocess.check_call(tempest_options)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
return True
|
||||
@@ -49,6 +49,27 @@ def get_application_status(application=None, unit=None, model_name=None):
|
||||
return status
|
||||
|
||||
|
||||
def get_application_ip(application):
|
||||
"""Get the application's IP address.
|
||||
|
||||
:param application: Application name
|
||||
:type application: str
|
||||
:returns: Application's IP address
|
||||
:rtype: str
|
||||
"""
|
||||
try:
|
||||
app_config = model.get_application_config(application)
|
||||
except KeyError:
|
||||
return ''
|
||||
vip = app_config.get("vip").get("value")
|
||||
if vip:
|
||||
ip = vip
|
||||
else:
|
||||
unit = model.get_units(application)[0]
|
||||
ip = unit.public_address
|
||||
return ip
|
||||
|
||||
|
||||
def get_cloud_configs(cloud=None):
|
||||
"""Get cloud configuration from local clouds.yaml.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user