Remove testscenarios usage from test_server_basic_ops
This commit removes the scenario test wrapper around test_server_basic_ops. This has always caused problems in tempest as it actually tries to do real operations during discovery which is a terrible idea. This weighed against a very limited benefit and limited use by most people it's time to just call the experiment and remove it. This is not saying there is no usefulness in testing a full matrix of images and flavors on a real deployment, but instead that the place for this kind of testing is not in tempest discovery. If people who found this valuable in the past want to retain the functionality should help work on an alternative method of doing it that isn't so invasive. Change-Id: Ie7814bd50f1c57c5f8da8355f665f09c9ac8e2d9
This commit is contained in:
parent
23d0575338
commit
f2c45014bb
@ -0,0 +1,11 @@
|
||||
---
|
||||
upgrade:
|
||||
- The input scenarios functionality no longer exists in tempest. This caused
|
||||
a large number of issues for limited benefit and was only used by a single
|
||||
test, test_server_basic_ops. If you were using this functionality you'll
|
||||
now have to do it manually with a script and/or tempest workspaces
|
||||
deprecations:
|
||||
- All the options in the input-scenario group are now deprecated. These were
|
||||
only used in tree by the now removed input scenarios functionality in
|
||||
test_server_basic_ops. They were only deprecated because there could be
|
||||
external consumers via plugins. They will be removed during the Ocata cycle.
|
@ -1035,23 +1035,28 @@ specify .* as the regex.
|
||||
|
||||
input_scenario_group = cfg.OptGroup(name="input-scenario",
|
||||
title="Filters and values for"
|
||||
" input scenarios")
|
||||
" input scenarios[DEPRECATED]")
|
||||
|
||||
|
||||
InputScenarioGroup = [
|
||||
cfg.StrOpt('image_regex',
|
||||
default='^cirros-0.3.1-x86_64-uec$',
|
||||
help="Matching images become parameters for scenario tests"),
|
||||
help="Matching images become parameters for scenario tests",
|
||||
deprecated_for_removal=True),
|
||||
cfg.StrOpt('flavor_regex',
|
||||
default='^m1.nano$',
|
||||
help="Matching flavors become parameters for scenario tests"),
|
||||
help="Matching flavors become parameters for scenario tests",
|
||||
deprecated_for_removal=True),
|
||||
cfg.StrOpt('non_ssh_image_regex',
|
||||
default='^.*[Ww]in.*$',
|
||||
help="SSH verification in tests is skipped"
|
||||
"for matching images"),
|
||||
"for matching images",
|
||||
deprecated_for_removal=True),
|
||||
cfg.StrOpt('ssh_user_regex',
|
||||
default="[[\"^.*[Cc]irros.*$\", \"cirros\"]]",
|
||||
help="List of user mapped to regex "
|
||||
"to matching image names."),
|
||||
"to matching image names.",
|
||||
deprecated_for_removal=True),
|
||||
]
|
||||
|
||||
|
||||
|
@ -20,15 +20,12 @@ from oslo_log import log as logging
|
||||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.scenario import manager
|
||||
from tempest.scenario import utils as test_utils
|
||||
from tempest import test
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
load_tests = test_utils.load_tests_input_scenario_utils
|
||||
|
||||
|
||||
class TestServerBasicOps(manager.ScenarioTest):
|
||||
|
||||
@ -47,27 +44,10 @@ class TestServerBasicOps(manager.ScenarioTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestServerBasicOps, self).setUp()
|
||||
# Setup image and flavor the test instance
|
||||
# Support both configured and injected values
|
||||
if not hasattr(self, 'image_ref'):
|
||||
self.image_ref = CONF.compute.image_ref
|
||||
if not hasattr(self, 'flavor_ref'):
|
||||
self.flavor_ref = CONF.compute.flavor_ref
|
||||
self.image_utils = test_utils.ImageUtils(self.manager)
|
||||
if not self.image_utils.is_flavor_enough(self.flavor_ref,
|
||||
self.image_ref):
|
||||
raise self.skipException(
|
||||
'{image} does not fit in {flavor}'.format(
|
||||
image=self.image_ref, flavor=self.flavor_ref
|
||||
)
|
||||
)
|
||||
self.run_ssh = CONF.validation.run_validation and \
|
||||
self.image_utils.is_sshable_image(self.image_ref)
|
||||
self.ssh_user = self.image_utils.ssh_user(self.image_ref)
|
||||
LOG.debug('Starting test for i:{image}, f:{flavor}. '
|
||||
'Run ssh: {ssh}, user: {ssh_user}'.format(
|
||||
image=self.image_ref, flavor=self.flavor_ref,
|
||||
ssh=self.run_ssh, ssh_user=self.ssh_user))
|
||||
self.image_ref = CONF.compute.image_ref
|
||||
self.flavor_ref = CONF.compute.flavor_ref
|
||||
self.run_ssh = CONF.validation.run_validation
|
||||
self.ssh_user = CONF.validation.image_ssh_user
|
||||
|
||||
def verify_ssh(self, keypair):
|
||||
if self.run_ssh:
|
||||
|
@ -1,185 +0,0 @@
|
||||
# Copyright 2013 Hewlett-Packard, 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.
|
||||
|
||||
|
||||
import re
|
||||
import string
|
||||
import unicodedata
|
||||
|
||||
from oslo_serialization import jsonutils as json
|
||||
import testscenarios
|
||||
import testtools
|
||||
|
||||
from tempest import clients
|
||||
from tempest.common import credentials_factory as credentials
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import misc
|
||||
from tempest.lib import exceptions as exc_lib
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class ImageUtils(object):
|
||||
|
||||
default_ssh_user = 'root'
|
||||
|
||||
def __init__(self, os):
|
||||
# Load configuration items
|
||||
self.ssh_users = json.loads(CONF.input_scenario.ssh_user_regex)
|
||||
self.non_ssh_image_pattern = \
|
||||
CONF.input_scenario.non_ssh_image_regex
|
||||
# Setup clients
|
||||
self.compute_images_client = os.compute_images_client
|
||||
self.flavors_client = os.flavors_client
|
||||
|
||||
def ssh_user(self, image_id):
|
||||
_image = self.compute_images_client.show_image(image_id)['image']
|
||||
for regex, user in self.ssh_users:
|
||||
# First match wins
|
||||
if re.match(regex, _image['name']) is not None:
|
||||
return user
|
||||
else:
|
||||
return self.default_ssh_user
|
||||
|
||||
def _is_sshable_image(self, image):
|
||||
return not re.search(pattern=self.non_ssh_image_pattern,
|
||||
string=str(image['name']))
|
||||
|
||||
def is_sshable_image(self, image_id):
|
||||
_image = self.compute_images_client.show_image(image_id)['image']
|
||||
return self._is_sshable_image(_image)
|
||||
|
||||
def _is_flavor_enough(self, flavor, image):
|
||||
return image['minDisk'] <= flavor['disk']
|
||||
|
||||
def is_flavor_enough(self, flavor_id, image_id):
|
||||
_image = self.compute_images_client.show_image(image_id)['image']
|
||||
_flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
|
||||
return self._is_flavor_enough(_flavor, _image)
|
||||
|
||||
|
||||
@misc.singleton
|
||||
class InputScenarioUtils(object):
|
||||
|
||||
"""Example usage:
|
||||
|
||||
import testscenarios
|
||||
(...)
|
||||
load_tests = testscenarios.load_tests_apply_scenarios
|
||||
|
||||
|
||||
class TestInputScenario(manager.ScenarioTest):
|
||||
|
||||
scenario_utils = utils.InputScenarioUtils()
|
||||
scenario_flavor = scenario_utils.scenario_flavors
|
||||
scenario_image = scenario_utils.scenario_images
|
||||
scenarios = testscenarios.multiply_scenarios(scenario_image,
|
||||
scenario_flavor)
|
||||
|
||||
def test_create_server_metadata(self):
|
||||
name = rand_name('instance')
|
||||
self.servers_client.create_server(name=name,
|
||||
flavorRef=self.flavor_ref,
|
||||
imageRef=self.image_ref)
|
||||
"""
|
||||
validchars = "-_.{ascii}{digit}".format(ascii=string.ascii_letters,
|
||||
digit=string.digits)
|
||||
|
||||
def __init__(self):
|
||||
network_resources = {
|
||||
'network': False,
|
||||
'router': False,
|
||||
'subnet': False,
|
||||
'dhcp': False,
|
||||
}
|
||||
self.cred_provider = credentials.get_credentials_provider(
|
||||
name='InputScenarioUtils',
|
||||
identity_version=CONF.identity.auth_version,
|
||||
network_resources=network_resources)
|
||||
os = clients.Manager(
|
||||
self.cred_provider.get_primary_creds().credentials)
|
||||
self.compute_images_client = os.compute_images_client
|
||||
self.flavors_client = os.flavors_client
|
||||
self.image_pattern = CONF.input_scenario.image_regex
|
||||
self.flavor_pattern = CONF.input_scenario.flavor_regex
|
||||
|
||||
def _normalize_name(self, name):
|
||||
nname = unicodedata.normalize('NFKD', name).encode('ASCII', 'ignore')
|
||||
nname = ''.join(c for c in nname if c in self.validchars)
|
||||
return nname
|
||||
|
||||
def clear_creds(self):
|
||||
self.cred_provider.clear_creds()
|
||||
|
||||
@property
|
||||
def scenario_images(self):
|
||||
""":return: a scenario with name and uuid of images"""
|
||||
if not CONF.service_available.glance:
|
||||
return []
|
||||
if not hasattr(self, '_scenario_images'):
|
||||
try:
|
||||
images = self.compute_images_client.list_images()['images']
|
||||
self._scenario_images = [
|
||||
(self._normalize_name(i['name']), dict(image_ref=i['id']))
|
||||
for i in images if re.search(self.image_pattern,
|
||||
str(i['name']))
|
||||
]
|
||||
except Exception:
|
||||
self._scenario_images = []
|
||||
return self._scenario_images
|
||||
|
||||
@property
|
||||
def scenario_flavors(self):
|
||||
""":return: a scenario with name and uuid of flavors"""
|
||||
if not hasattr(self, '_scenario_flavors'):
|
||||
try:
|
||||
flavors = self.flavors_client.list_flavors()['flavors']
|
||||
self._scenario_flavors = [
|
||||
(self._normalize_name(f['name']), dict(flavor_ref=f['id']))
|
||||
for f in flavors if re.search(self.flavor_pattern,
|
||||
str(f['name']))
|
||||
]
|
||||
except Exception:
|
||||
self._scenario_flavors = []
|
||||
return self._scenario_flavors
|
||||
|
||||
|
||||
def load_tests_input_scenario_utils(*args):
|
||||
"""Wrapper for testscenarios to set the scenarios
|
||||
|
||||
The purpose is to avoid running a getattr on the CONF object at import.
|
||||
"""
|
||||
|
||||
if getattr(args[0], 'suiteClass', None) is not None:
|
||||
loader, standard_tests, pattern = args
|
||||
else:
|
||||
standard_tests, module, loader = args
|
||||
output = None
|
||||
scenario_utils = None
|
||||
try:
|
||||
scenario_utils = InputScenarioUtils()
|
||||
scenario_flavor = scenario_utils.scenario_flavors
|
||||
scenario_image = scenario_utils.scenario_images
|
||||
except (exc_lib.InvalidCredentials, TypeError):
|
||||
output = standard_tests
|
||||
finally:
|
||||
if scenario_utils:
|
||||
scenario_utils.clear_creds()
|
||||
if output is not None:
|
||||
return output
|
||||
for test in testtools.iterate_tests(standard_tests):
|
||||
setattr(test, 'scenarios', testscenarios.multiply_scenarios(
|
||||
scenario_image,
|
||||
scenario_flavor))
|
||||
return testscenarios.load_tests_apply_scenarios(*args)
|
Loading…
Reference in New Issue
Block a user