Merge "tests: Centralize configuration of default flavor, image"

This commit is contained in:
Zuul 2022-03-09 13:44:44 +00:00 committed by Gerrit Code Review
commit cbb6aee038
10 changed files with 163 additions and 164 deletions

@ -68,8 +68,9 @@ configured for the one cloud. These accounts are:
configurable via the ``OPENSTACKSDK_DEMO_CLOUD_ALT`` environment variable
In addition, you must indicate the names of the flavor and image that should be
used for tests. These can be configured via ``functional.flavor_name`` and
``functional.image_name`` settings in the ``clouds.yaml`` file.
used for tests. These can be configured via ``OPENSTACKSDK_FLAVOR`` and
``OPENSTACKSDK_IMAGE`` environment variables or ``functional.flavor_name`` and
``functional.image_name`` settings in the ``clouds.yaml`` file, respectively.
Finally, you can configure the timeout for tests using the
``OPENSTACKSDK_FUNC_TEST_TIMEOUT`` environment variable (defaults to 300

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import operator
import os
from keystoneauth1 import discover
@ -28,9 +29,8 @@ TEST_CLOUD_NAME = os.getenv('OS_CLOUD', 'devstack-admin')
TEST_CLOUD_REGION = openstack.config.get_cloud_region(cloud=TEST_CLOUD_NAME)
def _get_resource_value(resource_key, default):
return TEST_CONFIG.get_extra_config(
'functional').get(resource_key, default)
def _get_resource_value(resource_key):
return TEST_CONFIG.get_extra_config('functional').get(resource_key)
def _disable_keep_alive(conn):
@ -38,10 +38,6 @@ def _disable_keep_alive(conn):
sess.keep_alive = False
IMAGE_NAME = _get_resource_value('image_name', 'cirros-0.4.0-x86_64-disk')
FLAVOR_NAME = _get_resource_value('flavor_name', 'm1.small')
class BaseFunctionalTest(base.TestCase):
_wait_for_timeout_key = ''
@ -52,10 +48,12 @@ class BaseFunctionalTest(base.TestCase):
_disable_keep_alive(self.conn)
self._demo_name = os.environ.get('OPENSTACKSDK_DEMO_CLOUD', 'devstack')
self._demo_name_alt = os.environ.get('OPENSTACKSDK_DEMO_CLOUD_ALT',
'devstack-alt')
self._demo_name_alt = os.environ.get(
'OPENSTACKSDK_DEMO_CLOUD_ALT', 'devstack-alt',
)
self._op_name = os.environ.get(
'OPENSTACKSDK_OPERATOR_CLOUD', 'devstack-admin')
'OPENSTACKSDK_OPERATOR_CLOUD', 'devstack-admin',
)
self.config = openstack.config.OpenStackConfig()
self._set_user_cloud()
@ -64,6 +62,9 @@ class BaseFunctionalTest(base.TestCase):
self.identity_version = \
self.operator_cloud.config.get_api_version('identity')
self.flavor = self._pick_flavor()
self.image = self._pick_image()
# Defines default timeout for wait_for methods used
# in the functional tests
self._wait_for_timeout = int(
@ -71,8 +72,7 @@ class BaseFunctionalTest(base.TestCase):
'OPENSTACKSDK_FUNC_TEST_TIMEOUT', 300)))
def _set_user_cloud(self, **kwargs):
user_config = self.config.get_one(
cloud=self._demo_name, **kwargs)
user_config = self.config.get_one(cloud=self._demo_name, **kwargs)
self.user_cloud = connection.Connection(config=user_config)
_disable_keep_alive(self.user_cloud)
@ -84,37 +84,95 @@ class BaseFunctionalTest(base.TestCase):
_disable_keep_alive(self.user_cloud_alt)
def _set_operator_cloud(self, **kwargs):
operator_config = self.config.get_one(
cloud=self._op_name, **kwargs)
operator_config = self.config.get_one(cloud=self._op_name, **kwargs)
self.operator_cloud = connection.Connection(config=operator_config)
_disable_keep_alive(self.operator_cloud)
def pick_image(self):
def _pick_flavor(self):
"""Pick a sensible flavor to run tests with.
This returns None if the compute service is not present (e.g.
ironic-only deployments).
"""
if not self.user_cloud.has_service('compute'):
return None
flavors = self.user_cloud.list_flavors(get_extra=False)
self.add_info_on_exception('flavors', flavors)
flavor_name = os.environ.get('OPENSTACKSDK_FLAVOR')
if not flavor_name:
flavor_name = _get_resource_value('flavor_name')
if flavor_name:
for flavor in flavors:
if flavor.name == flavor_name:
return flavor
raise self.failureException(
"Cloud does not have flavor '%s'", flavor_name,
)
# Enable running functional tests against RAX, which requires
# performance flavors be used for boot from volume
for flavor in sorted(flavors, key=operator.attrgetter('ram')):
if 'performance' in flavor.name:
return flavor
# Otherwise, pick the smallest flavor with a ephemeral disk configured
for flavor in sorted(flavors, key=operator.attrgetter('ram')):
if flavor.disk:
return flavor
raise self.failureException('No sensible flavor found')
def _pick_image(self):
"""Pick a sensible image to run tests with.
This returns None if the image service is not present.
"""
if not self.user_cloud.has_service('image'):
return None
images = self.user_cloud.list_images()
self.add_info_on_exception('images', images)
image_name = os.environ.get('OPENSTACKSDK_IMAGE')
if not image_name:
image_name = _get_resource_value('image_name')
if image_name:
for image in images:
if image.name == image_name:
return image
self.assertFalse(
"Cloud does not have {image}".format(image=image_name))
raise self.failureException(
"Cloud does not have image '%s'", image_name,
)
for image in images:
if image.name.startswith('cirros') and image.name.endswith('-uec'):
return image
for image in images:
if (image.name.startswith('cirros')
and image.disk_format == 'qcow2'):
if (
image.name.startswith('cirros')
and image.disk_format == 'qcow2'
):
return image
for image in images:
if image.name.lower().startswith('ubuntu'):
return image
for image in images:
if image.name.lower().startswith('centos'):
return image
self.assertFalse('no sensible image available')
raise self.failureException('No sensible image found')
def addEmptyCleanup(self, func, *args, **kwargs):
def cleanup():
@ -125,12 +183,12 @@ class BaseFunctionalTest(base.TestCase):
def require_service(self, service_type, min_microversion=None, **kwargs):
"""Method to check whether a service exists
Usage:
class TestMeter(base.BaseFunctionalTest):
...
def setUp(self):
super(TestMeter, self).setUp()
self.require_service('metering')
Usage::
class TestMeter(base.BaseFunctionalTest):
def setUp(self):
super(TestMeter, self).setUp()
self.require_service('metering')
:returns: True if the service exists, otherwise False.
"""
@ -144,16 +202,19 @@ class BaseFunctionalTest(base.TestCase):
data = self.conn.session.get_endpoint_data(
service_type=service_type, **kwargs)
if not (data.min_microversion
and data.max_microversion
and discover.version_between(
data.min_microversion,
data.max_microversion,
min_microversion)):
self.skipTest('Service {service_type} does not provide '
'microversion {ver}'.format(
service_type=service_type,
ver=min_microversion))
if not (
data.min_microversion
and data.max_microversion
and discover.version_between(
data.min_microversion,
data.max_microversion,
min_microversion,
)
):
self.skipTest(
f'Service {service_type} does not provide microversion '
f'{min_microversion}'
)
class KeystoneBaseFunctionalTest(BaseFunctionalTest):

@ -115,8 +115,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -145,8 +145,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -189,8 +189,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -232,8 +232,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -318,8 +318,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -392,8 +392,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -474,8 +474,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -567,8 +567,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -656,8 +656,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -713,8 +713,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -775,8 +775,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -863,8 +863,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -914,8 +914,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -1018,8 +1018,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -1056,8 +1056,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -1094,8 +1094,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -1130,8 +1130,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -1297,8 +1297,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"
@ -1356,8 +1356,8 @@ class TestClustering(base.BaseFunctionalTest):
profile_name = "test_profile"
spec = {
"properties": {
"flavor": "m1.tiny",
"image": base.IMAGE_NAME,
"flavor": self.flavor.name,
"image": self.image.name,
"networks": [
{
"network": "private"

@ -23,7 +23,6 @@ from fixtures import TimeoutException
from openstack.cloud import exc
from openstack.tests.functional import base
from openstack.tests.functional.cloud.util import pick_flavor
from openstack import utils
@ -34,11 +33,6 @@ class TestCompute(base.BaseFunctionalTest):
self.TIMEOUT_SCALING_FACTOR = 1.5
super(TestCompute, self).setUp()
self.flavor = pick_flavor(
self.user_cloud.list_flavors(get_extra=False))
if self.flavor is None:
self.assertFalse('no sensible flavor available')
self.image = self.pick_image()
self.server_name = self.getUniqueString()
def _cleanup_servers_and_volumes(self, server_name):

@ -28,7 +28,6 @@ from openstack.cloud.exc import OpenStackCloudException
from openstack.cloud import meta
from openstack import proxy
from openstack.tests.functional import base
from openstack.tests.functional.cloud.util import pick_flavor
from openstack import utils
@ -36,12 +35,7 @@ class TestFloatingIP(base.BaseFunctionalTest):
timeout = 60
def setUp(self):
super(TestFloatingIP, self).setUp()
self.flavor = pick_flavor(
self.user_cloud.list_flavors(get_extra=False))
if self.flavor is None:
self.assertFalse('no sensible flavor available')
self.image = self.pick_image()
super().setUp()
# Generate a random name for these tests
self.new_item_name = self.getUniqueString()

@ -25,9 +25,6 @@ from openstack.tests.functional import base
class TestImage(base.BaseFunctionalTest):
def setUp(self):
super(TestImage, self).setUp()
self.image = self.pick_image()
def test_create_image(self):
test_image = tempfile.NamedTemporaryFile(delete=False)

@ -21,21 +21,15 @@ Functional tests for `shade` inventory methods.
from openstack.cloud import inventory
from openstack.tests.functional import base
from openstack.tests.functional.cloud.util import pick_flavor
class TestInventory(base.BaseFunctionalTest):
def setUp(self):
super(TestInventory, self).setUp()
super().setUp()
# This needs to use an admin account, otherwise a public IP
# is not allocated from devstack.
self.inventory = inventory.OpenStackInventory(cloud='devstack-admin')
self.server_name = self.getUniqueString('inventory')
self.flavor = pick_flavor(
self.user_cloud.list_flavors(get_extra=False))
if self.flavor is None:
self.assertTrue(False, 'no sensible flavor available')
self.image = self.pick_image()
self.addCleanup(self._cleanup_server)
server = self.operator_cloud.create_server(
name=self.server_name, image=self.image, flavor=self.flavor,

@ -1,43 +0,0 @@
# 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.
"""
util
--------------------------------
Util methods for functional tests
"""
import operator
import os
def pick_flavor(flavors):
"""Given a flavor list pick the smallest one."""
# Enable running functional tests against rax - which requires
# performance flavors be used for boot from volume
flavor_name = os.environ.get('OPENSTACKSDK_FLAVOR')
if flavor_name:
for flavor in flavors:
if flavor.name == flavor_name:
return flavor
return None
for flavor in sorted(
flavors,
key=operator.attrgetter('ram')):
if 'performance' in flavor.name:
return flavor
for flavor in sorted(
flavors,
key=operator.attrgetter('ram')):
if flavor.disk:
return flavor

@ -40,8 +40,8 @@ class TestCluster(base.BaseFunctionalTest):
'version': 1.0,
'properties': {
'name': self.getUniqueString(),
'flavor': base.FLAVOR_NAME,
'image': base.IMAGE_NAME,
'flavor': self.flavor.name,
'image': self.image.name,
'networks': [{'network': self.network.id}]
}}}

@ -11,7 +11,6 @@
# under the License.
from openstack.compute.v2 import server
from openstack.tests.functional import base
from openstack.tests.functional.compute import base as ft_base
from openstack.tests.functional.network.v2 import test_network
@ -23,21 +22,24 @@ class TestServerAdmin(ft_base.BaseComputeTest):
self._set_operator_cloud(interface='admin')
self.NAME = 'needstobeshortandlowercase'
self.USERDATA = 'SSdtIGFjdHVhbGx5IGEgZ29hdC4='
flavor = self.conn.compute.find_flavor(base.FLAVOR_NAME,
ignore_missing=False)
image = self.conn.compute.find_image(base.IMAGE_NAME,
ignore_missing=False)
volume = self.conn.create_volume(1)
sot = self.conn.compute.create_server(
name=self.NAME, flavor_id=flavor.id, image_id=image.id,
networks='none', user_data=self.USERDATA,
block_device_mapping=[{
'uuid': volume.id,
'source_type': 'volume',
'boot_index': 0,
'destination_type': 'volume',
'delete_on_termination': True,
'volume_size': 1}])
name=self.NAME,
flavor_id=self.flavor.id,
image_id=self.image.id,
networks='none',
user_data=self.USERDATA,
block_device_mapping=[
{
'uuid': volume.id,
'source_type': 'volume',
'boot_index': 0,
'destination_type': 'volume',
'delete_on_termination': True,
'volume_size': 1,
},
],
)
self.conn.compute.wait_for_server(sot, wait=self._wait_for_timeout)
assert isinstance(sot, server.Server)
self.assertEqual(self.NAME, sot.name)
@ -72,10 +74,6 @@ class TestServer(ft_base.BaseComputeTest):
self.subnet = None
self.cidr = '10.99.99.0/16'
flavor = self.conn.compute.find_flavor(base.FLAVOR_NAME,
ignore_missing=False)
image = self.conn.compute.find_image(base.IMAGE_NAME,
ignore_missing=False)
self.network, self.subnet = test_network.create_network(
self.conn,
self.NAME,
@ -83,8 +81,11 @@ class TestServer(ft_base.BaseComputeTest):
self.assertIsNotNone(self.network)
sot = self.conn.compute.create_server(
name=self.NAME, flavor_id=flavor.id, image_id=image.id,
networks=[{"uuid": self.network.id}])
name=self.NAME,
flavor_id=self.flavor.id,
image_id=self.image.id,
networks=[{"uuid": self.network.id}],
)
self.conn.compute.wait_for_server(sot, wait=self._wait_for_timeout)
assert isinstance(sot, server.Server)
self.assertEqual(self.NAME, sot.name)