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:
Matthew Treinish 2016-06-22 21:13:42 -04:00 committed by Andrea Frittoli
parent 23d0575338
commit f2c45014bb
4 changed files with 25 additions and 214 deletions

View File

@ -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.

View File

@ -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),
]

View File

@ -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:

View File

@ -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)