Reworked script generating tempest.conf

* The config.py script generating tempest.conf was significantly reworked.

* The config.ini file was updated.

* A context class to create/delete all resources needed for Tempest was added.
  How does it work? Before running tests:
    1. The context class creates all roles needed for Tempest;
    2. If the image_ref option is not specified in the tempest.conf file,
       the context class will create an image for this option and add ID of
       the created image to tempest.conf;
    3. The same is for 'image_ref_alt', 'flavor_ref' and 'flavor_ref_alt';
    4. Once tests finish, all created resources will be deleted. All IDs of
       created resources will be deleted from tempest.conf.

* The TempestConfigCreationFailure exception was moved to the exceptions.py
  file. In addition, the TempestResourceCreationFailure exception was added.

* The rally-verify.sh script was changed. The index_verify.mako file was changed
  as well in accordance with changes in rally-verify.sh.

* All relevant unit tests were updated in accordance with new changes.

Closes-bug: #1454648

Change-Id: If32e51d6ce1f6bf7421021d151005cc75ed34953
This commit is contained in:
Yaroslav Lobankov 2015-09-23 11:40:01 +03:00
parent 77861e2c2f
commit 1dfb99574a
13 changed files with 575 additions and 464 deletions

View File

@ -615,14 +615,29 @@
# From rally # From rally
# #
# Version of cirros image (string value) # CirrOS image URL (string value)
#cirros_version = 0.3.4 #cirros_img_url = http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img
# Cirros image name (string value)
#cirros_image = cirros-0.3.4-x86_64-disk.img
# Cirros image base URL (string value) [role]
#cirros_base_url = http://download.cirros-cloud.net
#
# From rally
#
# Role required for users to be able to create Swift containers
# (string value)
#swift_operator_role = Member
# User role that has reseller admin (string value)
#swift_reseller_admin_role = ResellerAdmin
# Role required for users to be able to manage Heat stacks (string
# value)
#heat_stack_owner_role = heat_stack_owner
# Role for Heat template-defined users (string value)
#heat_stack_user_role = heat_stack_user
[users_context] [users_context]

View File

@ -43,6 +43,7 @@ def list_opts():
ec2_utils.EC2_BENCHMARK_OPTS)), ec2_utils.EC2_BENCHMARK_OPTS)),
("image", ("image",
itertools.chain(tempest_conf.IMAGE_OPTS)), itertools.chain(tempest_conf.IMAGE_OPTS)),
("role", itertools.chain(tempest_conf.ROLE_OPTS)),
("users_context", itertools.chain(users.USER_CONTEXT_OPTS)), ("users_context", itertools.chain(users.USER_CONTEXT_OPTS)),
("cleanup", itertools.chain(cleanup_base.CLEANUP_OPTS)) ("cleanup", itertools.chain(cleanup_base.CLEANUP_OPTS))
] ]

View File

@ -231,3 +231,11 @@ class InvalidHostException(RallyException):
class MultipleMatchesFound(RallyException): class MultipleMatchesFound(RallyException):
msg_fmt = _("Found multiple %(needle)s: %(haystack)s") msg_fmt = _("Found multiple %(needle)s: %(haystack)s")
class TempestConfigCreationFailure(RallyException):
msg_fmt = _("Unable to create Tempest config file: %(message)s")
class TempestResourceCreationFailure(RallyException):
msg_fmt = _("Unable to create resource needed for Tempest: %(message)s")

View File

@ -23,7 +23,6 @@ from rally.common import utils
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from rally.task import context from rally.task import context
from rally.verification.tempest import config
from rally.verification.tempest import tempest from rally.verification.tempest import tempest
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -65,7 +64,7 @@ class Tempest(context.Context):
msg = _("Failing to install tempest.") msg = _("Failing to install tempest.")
LOG.error(msg) LOG.error(msg)
raise exceptions.BenchmarkSetupFailure(msg) raise exceptions.BenchmarkSetupFailure(msg)
except config.TempestConfigCreationFailure: except exceptions.TempestConfigCreationFailure:
msg = _("Failing to configure tempest.") msg = _("Failing to configure tempest.")
LOG.error(msg) LOG.error(msg)
raise exceptions.BenchmarkSetupFailure(msg) raise exceptions.BenchmarkSetupFailure(msg)

View File

@ -3,50 +3,55 @@ debug = True
log_file = tempest.log log_file = tempest.log
use_stderr = False use_stderr = False
[auth]
allow_tenant_isolation = False
[boto] [boto]
instance_type = m1.nano
http_socket_timeout = 30 http_socket_timeout = 30
build_interval = 1
build_timeout = 196
[compute] [compute]
ssh_connect_method = floating image_ref =
image_ref_alt =
flavor_ref =
flavor_ref_alt =
ssh_user = cirros
image_ssh_user = cirros image_ssh_user = cirros
image_alt_ssh_user = cirros image_alt_ssh_user = cirros
network_for_ssh = private
ssh_user = cirros
build_interval = 1
build_timeout = 196
[compute-feature-enabled] [compute-feature-enabled]
change_password = False
live_migration = False live_migration = False
block_migration_for_live_migration = False resize = True
vnc_console = False
attach_encrypted_volume = False
[dashboard]
[data_processing-feature-enabled]
plugins = vanilla,cdh,mapr,spark,ambari
[identity] [identity]
[image-feature-enabled]
deactivate_image = True
[network] [network]
tenant_networks_reachable = False
[network-feature-enabled] [network-feature-enabled]
api_extensions = all ipv6_subnet_attributes = True
ipv6 = True ipv6 = True
[object-storage]
[oslo_concurrency] [oslo_concurrency]
[orchestration]
max_template_size = 5440000
max_resources_per_stack = 20000
[scenario] [scenario]
large_ops_number = 0 large_ops_number = 2
ssh_user = cirros
[service_available] [service_available]
[validation] [validation]
ssh_timeout = 196 run_validation = False
ip_version_for_ssh = 4
[volume] [volume-feature-enabled]
build_interval = 1 bootable = True
build_timeout = 196

View File

@ -13,10 +13,9 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import datetime
import inspect import inspect
import os import os
import time import uuid
from oslo_config import cfg from oslo_config import cfg
import requests import requests
@ -30,236 +29,328 @@ from rally.common import objects
from rally import exceptions from rally import exceptions
from rally import osclients from rally import osclients
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
IMAGE_OPTS = [ IMAGE_OPTS = [
cfg.StrOpt("cirros_version", cfg.StrOpt("cirros_img_url",
default="0.3.4", default="http://download.cirros-cloud.net/"
help="Version of cirros image"), "0.3.4/cirros-0.3.4-x86_64-disk.img",
cfg.StrOpt("cirros_image", help="CirrOS image URL")
default="cirros-0.3.4-x86_64-disk.img",
help="Cirros image name"),
cfg.StrOpt("cirros_base_url",
default="http://download.cirros-cloud.net",
help="Cirros image base URL"),
] ]
ROLE_OPTS = [
cfg.StrOpt("swift_operator_role",
default="Member",
help="Role required for users "
"to be able to create Swift containers"),
cfg.StrOpt("swift_reseller_admin_role",
default="ResellerAdmin",
help="User role that has reseller admin"),
cfg.StrOpt("heat_stack_owner_role",
default="heat_stack_owner",
help="Role required for users "
"to be able to manage Heat stacks"),
cfg.StrOpt("heat_stack_user_role",
default="heat_stack_user",
help="Role for Heat template-defined users")
]
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_opts(IMAGE_OPTS, "image") CONF.register_opts(IMAGE_OPTS, "image")
CONF.register_opts(ROLE_OPTS, "role")
IMAGE_NAME = parse.urlparse(CONF.image.cirros_img_url).path.split("/")[-1]
class TempestConfigCreationFailure(exceptions.RallyException): def _create_or_get_data_dir():
msg_fmt = _("Unable create tempest.conf: '%(message)s'") data_dir = os.path.join(
os.path.expanduser("~"), ".rally", "tempest", "data")
if not os.path.exists(data_dir):
os.makedirs(data_dir)
return data_dir
class TempestConf(object): def _write_config(conf_path, conf_data):
with open(conf_path, "w+") as conf_file:
conf_data.write(conf_file)
class TempestConfig(object):
"""Class to generate Tempest configuration file."""
def __init__(self, deployment): def __init__(self, deployment):
self.deployment = deployment
self.endpoint = db.deployment_get(deployment)["admin"] self.endpoint = db.deployment_get(deployment)["admin"]
self.clients = osclients.Clients(objects.Endpoint(**self.endpoint)) self.clients = osclients.Clients(objects.Endpoint(**self.endpoint))
try: self.keystone = self.clients.verified_keystone()
self.keystoneclient = self.clients.verified_keystone()
except exceptions.InvalidAdminException:
msg = (_("Admin permission is required to generate tempest "
"configuration file. User %s doesn't have admin role.") %
self.endpoint["username"])
raise TempestConfigCreationFailure(msg)
self.available_services = self.clients.services().values() self.available_services = self.clients.services().values()
self.data_dir = _create_or_get_data_dir()
self.conf = configparser.ConfigParser() self.conf = configparser.ConfigParser()
self.conf.read(os.path.join(os.path.dirname(__file__), "config.ini")) self.conf.read(os.path.join(os.path.dirname(__file__), "config.ini"))
self.deployment = deployment
self.data_path = os.path.join(os.path.expanduser("~"), ".rally",
"tempest", "data")
if not os.path.exists(self.data_path):
os.makedirs(self.data_path)
self.img_path = os.path.join(self.data_path,
CONF.image.cirros_image)
if not os.path.isfile(self.img_path):
self._load_img()
def _load_img(self): self._download_cirros_image()
cirros_url = ("%s/%s/%s" %
(CONF.image.cirros_base_url, def _download_cirros_image(self):
CONF.image.cirros_version, img_path = os.path.join(self.data_dir, IMAGE_NAME)
CONF.image.cirros_image)) if os.path.isfile(img_path):
return
try: try:
response = requests.get(cirros_url, stream=True) response = requests.get(CONF.image.cirros_img_url, stream=True)
except requests.ConnectionError as err: except requests.ConnectionError as err:
msg = _("Error on downloading cirros image, possibly" msg = _("Failed to download CirrOS image. "
" no connection to Internet with message %s") % str(err) "Possibly there is no connection to Internet. "
raise TempestConfigCreationFailure(msg) "Error: %s.") % (str(err) or "unknown")
raise exceptions.TempestConfigCreationFailure(msg)
if response.status_code == 200: if response.status_code == 200:
with open(self.img_path + ".tmp", "wb") as img_file: with open(img_path + ".tmp", "wb") as img_file:
for chunk in response.iter_content(chunk_size=1024): for chunk in response.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks if chunk: # filter out keep-alive new chunks
img_file.write(chunk) img_file.write(chunk)
img_file.flush() img_file.flush()
os.rename(self.img_path + ".tmp", self.img_path) os.rename(img_path + ".tmp", img_path)
else: else:
if response.status_code == 404: if response.status_code == 404:
msg = _("Error on downloading cirros image, possibly" msg = _("Failed to download CirrOS image. "
"invalid cirros_version or cirros_image in rally.conf") "Image was not found.")
else: else:
msg = _("Error on downloading cirros image, " msg = _("Failed to download CirrOS image. "
"HTTP error code %s") % response.getcode() "HTTP error code %d.") % response.status_code
raise TempestConfigCreationFailure(msg) raise exceptions.TempestConfigCreationFailure(msg)
def _get_url(self, servicename): def _get_service_url(self, service_type):
services_type2name_map = self.clients.services() for service in self.keystone.auth_ref["serviceCatalog"]:
for service in self.keystoneclient.auth_ref["serviceCatalog"]: if self.clients.services().get(service["type"]) == service_type:
if services_type2name_map.get(service["type"]) == servicename:
return service["endpoints"][0]["publicURL"] return service["endpoints"][0]["publicURL"]
def _set_default(self): def _configure_boto(self, section_name="boto"):
# Nothing to set up in this section for now self.conf.set(section_name, "ec2_url", self._get_service_url("ec2"))
pass self.conf.set(section_name, "s3_url", self._get_service_url("s3"))
self.conf.set(section_name, "s3_materials_path",
def _set_oslo_concurrency(self, section_name="oslo_concurrency"): os.path.join(self.data_dir, "s3materials"))
lock_path = os.path.join(self.data_path,
"lock_files_%s" % self.deployment)
if not os.path.exists(lock_path):
os.makedirs(lock_path)
self.conf.set(section_name, "lock_path", lock_path)
def _set_boto(self, section_name="boto"):
self.conf.set(section_name, "ec2_url", self._get_url("ec2"))
self.conf.set(section_name, "s3_url", self._get_url("s3"))
materials_path = os.path.join(self.data_path, "s3materials")
self.conf.set(section_name, "s3_materials_path", materials_path)
# TODO(olkonami): find out how can we get ami, ari, aki manifest files # TODO(olkonami): find out how can we get ami, ari, aki manifest files
def _set_compute_images(self, section_name="compute"): def _configure_default(self, section_name="DEFAULT"):
glanceclient = self.clients.glance() # Nothing to configure in this section for now
image_list = [img for img in glanceclient.images.list() pass
if img.status.lower() == "active" and
img.name is not None and "cirros" in img.name]
# Upload new images if there are no
# necessary images in the cloud (cirros)
while len(image_list) < 2:
now = (datetime.datetime.fromtimestamp(time.time()).
strftime("%Y_%m_%d_%H_%M_%S"))
try:
image = glanceclient.images.create(name=("cirros_%s" % now),
disk_format="qcow2",
container_format="bare")
image.update(data=open(self.img_path, "rb"))
image_list.append(image)
except Exception as e:
msg = _("There are no desired images (cirros) or only one and "
"new image could not be created.\n"
"Reason: %s") % getattr(e, "message", "unknown")
raise TempestConfigCreationFailure(msg)
self.conf.set(section_name, "image_ref", image_list[0].id)
self.conf.set(section_name, "image_ref_alt", image_list[1].id)
def _set_compute_flavors(self, section_name="compute"): def _configure_dashboard(self, section_name="dashboard"):
novaclient = self.clients.nova() url = "http://%s/" % parse.urlparse(self.endpoint["auth_url"]).hostname
flavor_list = sorted(novaclient.flavors.list(), self.conf.set(section_name, "dashboard_url", url)
key=lambda flv: flv.ram)
# Create new flavors if they are missing
while len(flavor_list) < 2:
now = (datetime.datetime.fromtimestamp(time.time()).
strftime("%Y_%m_%d_%H_%M_%S"))
try:
flv = novaclient.flavors.create("m1.tiny_%s" % now, 512, 1, 1)
flavor_list.append(flv)
except Exception as e:
msg = _("There are no desired flavors or only one and "
"new flavor could not be created.\n"
"Reason: %s") % getattr(e, "message", "unknown")
raise TempestConfigCreationFailure(msg)
self.conf.set(section_name, "flavor_ref", flavor_list[0].id)
self.conf.set(section_name, "flavor_ref_alt", flavor_list[1].id)
def _set_compute_ssh_connect_method(self, section_name="compute"): def _configure_identity(self, section_name="identity"):
if "neutron" in self.available_services:
self.conf.set(section_name, "ssh_connect_method", "floating")
else:
self.conf.set(section_name, "ssh_connect_method", "fixed")
def _set_identity(self, section_name="identity"):
self.conf.set(section_name, "username", self.endpoint["username"]) self.conf.set(section_name, "username", self.endpoint["username"])
self.conf.set(section_name, "password", self.endpoint["password"]) self.conf.set(section_name, "password", self.endpoint["password"])
self.conf.set(section_name, "tenant_name", self.conf.set(section_name, "tenant_name",
self.endpoint["tenant_name"]) self.endpoint["tenant_name"])
self.conf.set(section_name, "alt_username", self.endpoint["username"])
self.conf.set(section_name, "alt_password", self.endpoint["password"])
self.conf.set(section_name, "alt_tenant_name",
self.endpoint["tenant_name"])
self.conf.set(section_name, "admin_username", self.conf.set(section_name, "admin_username",
self.endpoint["username"]) self.endpoint["username"])
self.conf.set(section_name, "admin_password", self.conf.set(section_name, "admin_password",
self.endpoint["password"]) self.endpoint["password"])
self.conf.set(section_name, "admin_tenant_name", self.conf.set(section_name, "admin_tenant_name",
self.endpoint["tenant_name"]) self.endpoint["tenant_name"])
self.conf.set(section_name, "uri", self.endpoint["auth_url"]) self.conf.set(section_name, "uri", self.endpoint["auth_url"])
v2_url_trailer = parse.urlparse(self.endpoint["auth_url"]).path
self.conf.set(section_name, "uri_v3", self.conf.set(section_name, "uri_v3",
self.endpoint["auth_url"].replace("/v2.0", "/v3")) self.endpoint["auth_url"].replace(v2_url_trailer, "/v3"))
self.conf.set(section_name, "admin_domain_name", self.conf.set(section_name, "admin_domain_name",
self.endpoint["admin_domain_name"]) self.endpoint["admin_domain_name"])
def _set_network(self, section_name="network"): # The compute section is configured in context class for Tempest resources.
if "neutron" in self.available_services: # Options which are configured there: 'image_ref', 'image_ref_alt',
neutron = self.clients.neutron() # 'flavor_ref', 'flavor_ref_alt'.
public_net = [net for net in neutron.list_networks()["networks"] if
net["status"] == "ACTIVE" and
net["router:external"] is True]
if public_net:
net_id = public_net[0]["id"]
self.conf.set(section_name, "public_network_id", net_id)
public_router = neutron.list_routers(
network_id=net_id)["routers"][0]
self.conf.set(section_name, "public_router_id",
public_router["id"])
subnets = neutron.list_subnets(network_id=net_id)["subnets"]
if subnets:
subnet = subnets[0]
else:
# TODO(akurilin): create public subnet
LOG.warn("No public subnet is found.")
else:
subnets = neutron.list_subnets()["subnets"]
if subnets:
subnet = subnets[0]
else:
# TODO(akurilin): create subnet
LOG.warn("No subnet is found.")
self.conf.set(section_name, "tenant_network_cidr", subnet["cidr"])
else:
network = self.clients.nova().networks.list()[0]
self.conf.set(section_name, "tenant_network_cidr", network.cidr)
def _set_service_available(self, section_name="service_available"): def _configure_network(self, section_name="network"):
services = ["neutron", "heat", "ceilometer", "swift", if "neutron" in self.available_services:
"cinder", "nova", "glance"] neutronclient = self.clients.neutron()
public_nets = [net for net
in neutronclient.list_networks()["networks"]
if net["status"] == "ACTIVE" and
net["router:external"] is True]
if public_nets:
net_id = public_nets[0]["id"]
self.conf.set(section_name, "public_network_id", net_id)
else:
novaclient = self.clients.nova()
net_name = next(net.human_id for net in novaclient.networks.list()
if net.human_id is not None)
self.conf.set("compute", "fixed_network_name", net_name)
self.conf.set("compute", "network_for_ssh", net_name)
def _configure_network_feature_enabled(
self, section_name="network-feature-enabled"):
if "neutron" in self.available_services:
neutronclient = self.clients.neutron()
ext_list = [ext["alias"] for ext in
neutronclient.list_ext("/extensions")["extensions"]]
ext_list_str = ",".join(ext_list)
self.conf.set(section_name, "api_extensions", ext_list_str)
def _configure_oslo_concurrency(self, section_name="oslo_concurrency"):
lock_path = os.path.join(self.data_dir,
"lock_files_%s" % self.deployment)
if not os.path.exists(lock_path):
os.makedirs(lock_path)
self.conf.set(section_name, "lock_path", lock_path)
def _configure_object_storage(self, section_name="object-storage"):
self.conf.set(section_name, "operator_role",
CONF.role.swift_operator_role)
self.conf.set(section_name, "reseller_admin_role",
CONF.role.swift_reseller_admin_role)
def _configure_scenario(self, section_name="scenario"):
self.conf.set(section_name, "img_dir", self.data_dir)
self.conf.set(section_name, "img_file", IMAGE_NAME)
def _configure_service_available(self, section_name="service_available"):
services = ["ceilometer", "cinder", "glance",
"heat", "neutron", "nova", "sahara", "swift"]
for service in services: for service in services:
# Convert boolean to string because ConfigParser fails
# on attempt to get option with boolean value
self.conf.set(section_name, service, self.conf.set(section_name, service,
str(service in self.available_services)) str(service in self.available_services))
horizon_url = ("http://" + horizon_url = ("http://" +
parse.urlparse(self.endpoint["auth_url"]).hostname) parse.urlparse(self.endpoint["auth_url"]).hostname)
try: try:
horizon_req = requests.get(horizon_url) horizon_req = requests.get(horizon_url)
except requests.RequestException as e: except requests.RequestException:
LOG.debug("Failed to connect to Horizon: %s" % e) LOG.debug("Horizon is unavailable!")
horizon_availability = False horizon_availability = False
else: else:
horizon_availability = (horizon_req.status_code == 200) horizon_availability = (horizon_req.status_code == 200)
# convert boolean to string because ConfigParser fails # Convert boolean to string because ConfigParser fails
# on attempt to get option with boolean value # on attempt to get option with boolean value
self.conf.set(section_name, "horizon", str(horizon_availability)) self.conf.set(section_name, "horizon", str(horizon_availability))
def write_config(self, file_name): def _configure_validation(self, section_name="validation"):
with open(file_name, "w+") as f: if "neutron" in self.available_services:
self.conf.write(f) self.conf.set(section_name, "connect_method", "floating")
else:
self.conf.set(section_name, "connect_method", "fixed")
def generate(self, file_name=None): def generate(self, conf_path=None):
for name, func in inspect.getmembers(self, predicate=inspect.ismethod): for name, method in inspect.getmembers(self, inspect.ismethod):
if name.startswith("_set_"): if name.startswith("_configure_"):
func() method()
if file_name:
self.write_config(file_name)
return self.conf if conf_path:
_write_config(conf_path, self.conf)
class TempestResourcesContext(object):
"""Context class to create/delete resources needed for Tempest."""
def __init__(self, deployment, conf_path):
endpoint = db.deployment_get(deployment)["admin"]
self.clients = osclients.Clients(objects.Endpoint(**endpoint))
self.keystone = self.clients.verified_keystone()
self.conf_path = conf_path
self.conf = configparser.ConfigParser()
self.conf.read(conf_path)
def __enter__(self):
self._created_roles = []
self._created_images = []
self._created_flavors = []
self._create_tempest_roles()
self._configure_option("image_ref", self._create_image)
self._configure_option("image_ref_alt", self._create_image)
self._configure_option("flavor_ref", self._create_flavor, 64)
self._configure_option("flavor_ref_alt", self._create_flavor, 128)
_write_config(self.conf_path, self.conf)
def __exit__(self, exc_type, exc_value, exc_traceback):
self._cleanup_roles()
self._cleanup_resource("image", self._created_images)
self._cleanup_resource("flavor", self._created_flavors)
def _create_tempest_roles(self):
roles = [CONF.role.swift_operator_role,
CONF.role.swift_reseller_admin_role,
CONF.role.heat_stack_owner_role,
CONF.role.heat_stack_user_role]
existing_roles = set(role.name for role in self.keystone.roles.list())
for role in roles:
if role not in existing_roles:
LOG.debug("Creating role '%s'" % role)
self._created_roles.append(self.keystone.roles.create(role))
def _configure_option(self, option, create_method, *args, **kwargs):
option_value = self.conf.get("compute", option)
if not option_value:
LOG.debug("Option '%s' is not configured" % option)
resource = create_method(*args, **kwargs)
self.conf.set("compute", option, resource.id)
LOG.debug("Option '{opt}' is configured. {opt} = {resource_id}"
.format(opt=option, resource_id=resource.id))
else:
LOG.debug("Option '{opt}' was configured manually "
"in Tempest config file. {opt} = {opt_val}"
.format(opt=option, opt_val=option_value))
def _create_image(self):
glanceclient = self.clients.glance()
image_name = "rally-verify-cirros-img-%s" % uuid.uuid4()
LOG.debug("Creating image '%s'" % image_name)
try:
image = glanceclient.images.create(
name=image_name,
disk_format="qcow2",
container_format="bare",
is_public=True)
self._created_images.append(image)
image.update(data=open(
os.path.join(_create_or_get_data_dir(), IMAGE_NAME), "rb"))
except Exception as exc:
msg = _("Image could not be created. "
"Reason: %s") % (str(exc) or "unknown")
raise exceptions.TempestResourceCreationFailure(msg)
return image
def _create_flavor(self, flv_ram):
novaclient = self.clients.nova()
flavor_name = "m1.rally-verify-flv-%s" % uuid.uuid4()
LOG.debug("Creating flavor '%s'" % flavor_name)
try:
flavor = novaclient.flavors.create(
flavor_name, ram=flv_ram, vcpus=1, disk=0)
except Exception as exc:
msg = _("Flavor could not be created. "
"Reason: %s") % (str(exc) or "unknown")
raise exceptions.TempestResourceCreationFailure(msg)
self._created_flavors.append(flavor)
return flavor
def _cleanup_roles(self):
for role in self._created_roles:
LOG.debug("Deleting role '%s'" % role.name)
role.delete()
def _cleanup_resource(self, resource_type, created_resources):
for res in created_resources:
LOG.debug("Deleting %s '%s'" % (resource_type, res.name))
if res.id == self.conf.get("compute", "%s_ref" % resource_type):
self.conf.set("compute", "%s_ref" % resource_type, "")
else:
self.conf.set("compute", "%s_ref_alt" % resource_type, "")
res.delete()
_write_config(self.conf_path, self.conf)

View File

@ -229,7 +229,7 @@ class Tempest(object):
msg = _("Creation of configuration file for tempest.") msg = _("Creation of configuration file for tempest.")
LOG.info(_("Starting: ") + msg) LOG.info(_("Starting: ") + msg)
config.TempestConf(self.deployment).generate(self.config_file) config.TempestConfig(self.deployment).generate(self.config_file)
LOG.info(_("Completed: ") + msg) LOG.info(_("Completed: ") + msg)
else: else:
LOG.info("Tempest is already configured.") LOG.info("Tempest is already configured.")
@ -345,6 +345,10 @@ class Tempest(object):
"log_file": log_file or self.log_file_raw "log_file": log_file or self.log_file_raw
}) })
LOG.debug("Test(s) started by the command: %s" % test_cmd) LOG.debug("Test(s) started by the command: %s" % test_cmd)
# Create all resources needed for Tempest before running tests.
# Once tests finish, all created resources will be deleted.
with config.TempestResourcesContext(self.deployment, self.config_file):
# Run tests
subprocess.check_call(test_cmd, cwd=self.path(), subprocess.check_call(test_cmd, cwd=self.path(),
env=self.env, shell=True) env=self.env, shell=True)

View File

@ -62,27 +62,26 @@
</li> </li>
<li> <li>
<span class="${vr_1_html}">[${vr_1_html}]</span> <span class="${vr_1_html}">[${vr_1_html}]</span>
<a href="rally-verify/1_verify_results.html.gz">Display raw results in HTML</a> <a href="rally-verify/1_verify_results_compute_set.html.gz">Display raw results in HTML</a>
<code>$ rally verify results --html</code> <code>$ rally verify results --html</code>
</li> </li>
<li> <li>
<span class="${vr_1_json}">[${vr_1_json}]</span> <span class="${vr_1_json}">[${vr_1_json}]</span>
<a href="rally-verify/1_verify_results.json.gz">Display raw results in JSON</a> <a href="rally-verify/1_verify_results_compute_set.json.gz">Display raw results in JSON</a>
<code>$ rally verify results --json</code> <code>$ rally verify results --json</code>
</li> </li>
<li> <li>
<span class="${vs_1}">[${vs_1}]</span> <span class="${vs_1}">[${vs_1}]</span>
<a href="rally-verify/1_verify_show.txt.gz">Display results table of the verification</a> <a href="rally-verify/1_verify_show_compute_set.txt.gz">Display results table of the verification</a>
<code>$ rally verify show</code> <code>$ rally verify show</code>
</li> </li>
<li> <li>
<span class="${vsd_1}">[${vsd_1}]</span> <span class="${vsd_1}">[${vsd_1}]</span>
<a href="rally-verify/1_verify_show_detailed.txt.gz">Display results table of the verification with detailed errors</a><br /> <a href="rally-verify/1_verify_show_compute_set_detailed.txt.gz">Display results table of the verification with detailed errors</a><br />
<code style="display: inline">$ rally verify show --detailed</code> or <code style="display: inline">$ rally verify detailed</code> <code style="display: inline">$ rally verify show --detailed</code> or <code style="display: inline">$ rally verify detailed</code>
</li> </li>
</ol> </ol>
Second verification run Second verification run
<ol> <ol>
<li> <li>
@ -92,22 +91,22 @@
</li> </li>
<li> <li>
<span class="${vr_2_html}">[${vr_2_html}]</span> <span class="${vr_2_html}">[${vr_2_html}]</span>
<a href="rally-verify/2_verify_results.html.gz">Display results in HTML</a> <a href="rally-verify/2_verify_results_compute_set.html.gz">Display results in HTML</a>
<code>$ rally verify results --html</code> <code>$ rally verify results --html</code>
</li> </li>
<li> <li>
<span class="${vr_2_json}">[${vr_2_json}]</span> <span class="${vr_2_json}">[${vr_2_json}]</span>
<a href="rally-verify/2_verify_results.json.gz">Display results in JSON</a> <a href="rally-verify/2_verify_results_compute_set.json.gz">Display results in JSON</a>
<code>$ rally verify results --json</code> <code>$ rally verify results --json</code>
</li> </li>
<li> <li>
<span class="${vs_2}">[${vs_2}]</span> <span class="${vs_2}">[${vs_2}]</span>
<a href="rally-verify/2_verify_show.txt.gz">Display table results of the verification</a> <a href="rally-verify/2_verify_show_compute_set.txt.gz">Display table results of the verification</a>
<code>$ rally verify show</code> <code>$ rally verify show</code>
</li> </li>
<li> <li>
<span class="${vsd_2}">[${vsd_2}]</span> <span class="${vsd_2}">[${vsd_2}]</span>
<a href="rally-verify/2_verify_show_detailed.txt.gz">Display table results of the verification with detailed errors</a><br /> <a href="rally-verify/2_verify_show_compute_set_detailed.txt.gz">Display table results of the verification with detailed errors</a><br />
<code style="display: inline">$ rally verify show --detailed</code> or <code style="display: inline">$ rally verify detailed</code> <code style="display: inline">$ rally verify show --detailed</code> or <code style="display: inline">$ rally verify detailed</code>
</li> </li>
</ol> </ol>

View File

@ -48,8 +48,8 @@ gzip -9 ${RESULTS_DIR}/tempest_installation.txt
gzip -9 ${RESULTS_DIR}/tempest_config_generation.txt gzip -9 ${RESULTS_DIR}/tempest_config_generation.txt
function do_verification { function do_verification {
OUTPUT_FILE=${RESULTS_DIR}/${1}_verification_${SET_NAME}_set.txt OUTPUT_FILE=${RESULTS_DIR}/${1}_verification_${2}_set.txt
rally --rally-debug verify start --regex tempest.api.compute.servers.test_servers > ${OUTPUT_FILE} 2>&1 rally --rally-debug verify start --set ${2} > ${OUTPUT_FILE} 2>&1
RESULTS+="v${1}=$(do_status $?) " RESULTS+="v${1}=$(do_status $?) "
gzip -9 ${OUTPUT_FILE} gzip -9 ${OUTPUT_FILE}
source ~/.rally/globals && VERIFICATIONS[${1}]=${RALLY_VERIFICATION} source ~/.rally/globals && VERIFICATIONS[${1}]=${RALLY_VERIFICATION}
@ -57,24 +57,24 @@ function do_verification {
# Check different "rally verify" commands, which displays verification results # Check different "rally verify" commands, which displays verification results
for OUTPUT_FORMAT in "html" "json" for OUTPUT_FORMAT in "html" "json"
do do
OUTPUT_FILE=${RESULTS_DIR}/${1}_verify_results.${OUTPUT_FORMAT} OUTPUT_FILE=${RESULTS_DIR}/${1}_verify_results_${2}_set.${OUTPUT_FORMAT}
rally verify results --uuid ${RALLY_VERIFICATION} --${OUTPUT_FORMAT} --output-file ${OUTPUT_FILE} rally verify results --uuid ${RALLY_VERIFICATION} --${OUTPUT_FORMAT} --output-file ${OUTPUT_FILE}
RESULTS+="vr_${1}_${OUTPUT_FORMAT}=$(do_status $?) " RESULTS+="vr_${1}_${OUTPUT_FORMAT}=$(do_status $?) "
gzip -9 ${OUTPUT_FILE} gzip -9 ${OUTPUT_FILE}
done done
rally verify show --uuid ${RALLY_VERIFICATION} > ${RESULTS_DIR}/${1}_verify_show.txt rally verify show --uuid ${RALLY_VERIFICATION} > ${RESULTS_DIR}/${1}_verify_show_${2}_set.txt
RESULTS+="vs_${1}=$(do_status $?) " RESULTS+="vs_${1}=$(do_status $?) "
gzip -9 ${RESULTS_DIR}/${1}_verify_show.txt gzip -9 ${RESULTS_DIR}/${1}_verify_show_${2}_set.txt
rally verify show --uuid ${RALLY_VERIFICATION} --detailed > ${RESULTS_DIR}/${1}_verify_show_detailed.txt rally verify show --uuid ${RALLY_VERIFICATION} --detailed > ${RESULTS_DIR}/${1}_verify_show_${2}_set_detailed.txt
RESULTS+="vsd_${1}=$(do_status $?) " RESULTS+="vsd_${1}=$(do_status $?) "
gzip -9 ${RESULTS_DIR}/${1}_verify_show_detailed.txt gzip -9 ${RESULTS_DIR}/${1}_verify_show_${2}_set_detailed.txt
} }
function main { function main {
do_verification 1 do_verification 1 compute
do_verification 2 do_verification 2 compute
rally verify list > ${RESULTS_DIR}/verify_list.txt rally verify list > ${RESULTS_DIR}/verify_list.txt
RESULTS+="l=$(do_status $?) " RESULTS+="l=$(do_status $?) "

View File

@ -17,7 +17,6 @@ import mock
from rally import exceptions from rally import exceptions
from rally.plugins.openstack.context.not_for_production import tempest from rally.plugins.openstack.context.not_for_production import tempest
from rally.verification.tempest import config
from rally.verification.tempest import tempest as tempest_verifier from rally.verification.tempest import tempest as tempest_verifier
from tests.unit import test from tests.unit import test
@ -75,7 +74,7 @@ class TempestContextTestCase(test.TestCase):
self, mock_tempest_generate_config_file, mock_tempest_is_installed, self, mock_tempest_generate_config_file, mock_tempest_is_installed,
mock_tempest_is_configured, mock_mkdir): mock_tempest_is_configured, mock_mkdir):
mock_tempest_generate_config_file.side_effect = ( mock_tempest_generate_config_file.side_effect = (
config.TempestConfigCreationFailure() exceptions.TempestConfigCreationFailure()
) )
benchmark = tempest.Tempest(self.context) benchmark = tempest.Tempest(self.context)

View File

@ -19,7 +19,8 @@ from rally.plugins.openstack.scenarios.tempest import tempest
from rally.verification.tempest import tempest as verifier from rally.verification.tempest import tempest as verifier
from tests.unit import test from tests.unit import test
VERIFIER = "rally.verification.tempest.tempest" TEMPEST_DIR = "rally.verification.tempest"
VERIFIER = TEMPEST_DIR + ".tempest"
TS = "rally.plugins.openstack.scenarios.tempest" TS = "rally.plugins.openstack.scenarios.tempest"
@ -51,7 +52,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_single_test(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_single_test(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_test = "tempest.api.fake.test" fake_test = "tempest.api.fake.test"
@ -64,7 +67,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_single_test_negative(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_single_test_negative(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_test = "tempest.api.network" fake_test = "tempest.api.network"
@ -77,7 +82,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_single_test_without_prefix(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_single_test_without_prefix(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.single_test("network") self.scenario.single_test("network")
@ -89,7 +96,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_all(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_all(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.all() self.scenario.all()
@ -101,7 +110,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_set_smoke(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_smoke(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.set("smoke") self.scenario.set("smoke")
@ -113,7 +124,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_set_full(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_full(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.set("full") self.scenario.set("full")
@ -124,7 +137,9 @@ class TempestScenarioTestCase(test.TestCase):
env=self.verifier.env, shell=True) env=self.verifier.env, shell=True)
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
def test_set_from_list(self, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_from_list(self, mock_tempest_resources_context,
mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_scenarios = ["network", "volume", "baremetal", fake_scenarios = ["network", "volume", "baremetal",
@ -143,7 +158,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_set_selective(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_selective(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.set("network") self.scenario.set("network")
@ -155,7 +172,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_list_of_tests(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_list_of_tests(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_tests = ["tempest.fake.test1", "tempest.fake.test2"] fake_tests = ["tempest.fake.test1", "tempest.fake.test2"]
@ -168,7 +187,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@mock.patch(VERIFIER + ".subprocess") @mock.patch(VERIFIER + ".subprocess")
def test_specific_regex(self, mock_subprocess, mock_tempfile): @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_specific_regex(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile):
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
regex = "tempest.fake.test1" regex = "tempest.fake.test1"

View File

@ -19,6 +19,7 @@ import mock
from oslo_config import cfg from oslo_config import cfg
import requests import requests
from rally import exceptions
from rally.verification.tempest import config from rally.verification.tempest import config
from tests.unit import fakes from tests.unit import fakes
from tests.unit import test from tests.unit import test
@ -37,23 +38,31 @@ class ConfigTestCase(test.TestCase):
def setUp(self, mock_isfile, mock_clients_verified_keystone, def setUp(self, mock_isfile, mock_clients_verified_keystone,
mock_clients_services, mock_deployment_get): mock_clients_services, mock_deployment_get):
super(ConfigTestCase, self).setUp() super(ConfigTestCase, self).setUp()
self.endpoint = {"username": "test",
self.endpoint = {
"username": "test",
"tenant_name": "test", "tenant_name": "test",
"password": "test", "password": "test",
"auth_url": "http://test/v2.0", "auth_url": "http://test/v2.0/",
"permission": "admin", "permission": "admin",
"admin_domain_name": "Default"} "admin_domain_name": "Default"
}
mock_deployment_get.return_value = {"admin": self.endpoint} mock_deployment_get.return_value = {"admin": self.endpoint}
self.deployment = "fake_deployment" self.deployment = "fake_deployment"
self.conf_generator = config.TempestConf(self.deployment) self.conf_generator = config.TempestConfig(self.deployment)
self.conf_generator.clients.services = mock_clients_services self.conf_generator.clients.services = mock_clients_services
self.context = config.TempestResourcesContext(self.deployment,
"/path/to/fake/conf")
self.context.conf.add_section("compute")
keystone_patcher = mock.patch("rally.osclients.create_keystone_client") keystone_patcher = mock.patch("rally.osclients.create_keystone_client")
keystone_patcher.start() keystone_patcher.start()
self.addCleanup(keystone_patcher.stop) self.addCleanup(keystone_patcher.stop)
def _remove_default_section(self, items): @staticmethod
# getting items from configparser by specified section name def _remove_default_section(items):
# Getting items from config parser by specified section name
# returns also values from DEFAULT section # returns also values from DEFAULT section
defaults = (("log_file", "tempest.log"), ("debug", "True"), defaults = (("log_file", "tempest.log"), ("debug", "True"),
("use_stderr", "False")) ("use_stderr", "False"))
@ -63,269 +72,223 @@ class ConfigTestCase(test.TestCase):
@mock.patch("rally.verification.tempest.config.os.rename") @mock.patch("rally.verification.tempest.config.os.rename")
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open(), @mock.patch("six.moves.builtins.open", side_effect=mock.mock_open(),
create=True) create=True)
def test__load_img_success(self, mock_open, mock_rename, mock_requests): def test__download_cirros_image_success(self, mock_open, mock_rename,
mock_requests):
mock_result = mock.MagicMock() mock_result = mock.MagicMock()
mock_result.status_code = 200 mock_result.status_code = 200
mock_requests.get.return_value = mock_result mock_requests.get.return_value = mock_result
self.conf_generator._load_img() self.conf_generator._download_cirros_image()
cirros_url = ("http://download.cirros-cloud.net/%s/%s" % mock_requests.get.assert_called_once_with(CONF.image.cirros_img_url,
(CONF.image.cirros_version, stream=True)
CONF.image.cirros_image))
mock_requests.get.assert_called_once_with(cirros_url, stream=True)
@mock.patch("rally.verification.tempest.config.requests") @mock.patch("rally.verification.tempest.config.requests")
def test__load_img_notfound(self, mock_requests): def test__download_cirros_image_notfound(self, mock_requests):
mock_result = mock.MagicMock() mock_result = mock.MagicMock()
mock_result.status_code = 404 mock_result.status_code = 404
mock_requests.get.return_value = mock_result mock_requests.get.return_value = mock_result
self.assertRaises(config.TempestConfigCreationFailure, self.assertRaises(exceptions.TempestConfigCreationFailure,
self.conf_generator._load_img) self.conf_generator._download_cirros_image)
def test__get_url(self): def test__get_service_url(self):
service = "test_service" service = "test_service"
service_type = "test_service_type" service_type = "test_service_type"
url = "test_url" url = "test_url"
# mocked at setUp # Mocked at setUp
self.conf_generator.keystoneclient.auth_ref = { self.conf_generator.keystone.auth_ref = {
"serviceCatalog": [{ "serviceCatalog": [
{
"name": service, "name": service,
"type": service_type, "type": service_type,
"endpoints": [{"publicURL": url}] "endpoints": [{"publicURL": url}]
}]} }
self.assertEqual(self.conf_generator._get_url(service), url) ]
}
self.assertEqual(self.conf_generator._get_service_url(service), url)
@mock.patch("rally.verification.tempest.config.TempestConf" @mock.patch("rally.verification.tempest."
"._get_url") "config.TempestConfig._get_service_url")
def test__set_boto(self, mock_tempest_conf__get_url): def test__configure_boto(self, mock_tempest_config__get_service_url):
url = "test_url" url = "test_url"
mock_tempest_conf__get_url.return_value = url mock_tempest_config__get_service_url.return_value = url
self.conf_generator._set_boto() s3_materials_path = os.path.join(
self.conf_generator.data_dir, "s3materials")
self.conf_generator._configure_boto()
expected = (("ec2_url", url), expected = (("ec2_url", url),
("s3_url", url), ("s3_url", url),
("build_interval", "1"),
("build_timeout", "196"),
("http_socket_timeout", "30"), ("http_socket_timeout", "30"),
("instance_type", "m1.nano"), ("s3_materials_path", s3_materials_path))
("s3_materials_path",
os.path.join(self.conf_generator.data_path,
"s3materials")))
results = self._remove_default_section( results = self._remove_default_section(
self.conf_generator.conf.items("boto")) self.conf_generator.conf.items("boto"))
self.assertEqual(sorted(expected), sorted(results)) self.assertEqual(sorted(expected), sorted(results))
def test__set_compute_flavors(self): def test__configure_default(self):
mock_novaclient = mock.MagicMock() self.conf_generator._configure_default()
mock_novaclient.flavors.list.return_value = [
fakes.FakeFlavor(id="id1"), fakes.FakeFlavor(id="id2")]
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.conf_generator._set_compute_flavors()
expected = ("id1", "id2")
results = (self.conf_generator.conf.get("compute", "flavor_ref"),
self.conf_generator.conf.get("compute",
"flavor_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
def test__set_compute_flavors_create(self):
mock_novaclient = mock.MagicMock()
mock_novaclient.flavors.list.return_value = []
mock_novaclient.flavors.create.side_effect = [
fakes.FakeFlavor(id="id1"), fakes.FakeFlavor(id="id2")]
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.conf_generator._set_compute_flavors()
self.assertEqual(mock_novaclient.flavors.create.call_count, 2)
expected = ("id1", "id2")
results = (self.conf_generator.conf.get("compute", "flavor_ref"),
self.conf_generator.conf.get("compute",
"flavor_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
def test__set_compute_flavors_create_fails(self):
mock_novaclient = mock.MagicMock()
mock_novaclient.flavors.list.return_value = []
mock_novaclient.flavors.create.side_effect = Exception()
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.assertRaises(config.TempestConfigCreationFailure,
self.conf_generator._set_compute_flavors)
def test__set_compute_images(self):
mock_glanceclient = mock.MagicMock()
mock_glanceclient.images.list.return_value = [
fakes.FakeImage(id="id1", name="cirros1"),
fakes.FakeImage(id="id2", name="cirros2")]
mock_glance = mock.MagicMock()
mock_glance.Client.return_value = mock_glanceclient
with mock.patch.dict("sys.modules", {"glanceclient": mock_glance}):
self.conf_generator._set_compute_images()
expected = ("id1", "id2")
results = (self.conf_generator.conf.get("compute", "image_ref"),
self.conf_generator.conf.get("compute",
"image_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
@mock.patch("six.moves.builtins.open")
def test__set_compute_images_create(self, mock_open):
mock_glanceclient = mock.MagicMock()
mock_glanceclient.images.list.return_value = []
mock_glanceclient.images.create.side_effect = [
fakes.FakeImage(id="id1"), fakes.FakeImage(id="id2")]
mock_glance = mock.MagicMock()
mock_glance.Client.return_value = mock_glanceclient
with mock.patch.dict("sys.modules", {"glanceclient": mock_glance}):
self.conf_generator._set_compute_images()
self.assertEqual(mock_glanceclient.images.create.call_count, 2)
expected = ("id1", "id2")
results = (self.conf_generator.conf.get("compute", "image_ref"),
self.conf_generator.conf.get("compute",
"image_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
def test__set_compute_images_create_fails(self):
mock_glanceclient = mock.MagicMock()
mock_glanceclient.images.list.return_value = []
mock_glanceclient.images.create.side_effect = Exception()
mock_glance = mock.MagicMock()
mock_glance.Client.return_value = mock_glanceclient
with mock.patch.dict("sys.modules", {"glanceclient": mock_glance}):
self.assertRaises(config.TempestConfigCreationFailure,
self.conf_generator._set_compute_images)
def test__set_compute_ssh_connect_method_if_neutron(self):
self.conf_generator._set_compute_ssh_connect_method()
self.assertEqual("fixed",
self.conf_generator.conf.get("compute",
"ssh_connect_method"))
# if neutron is available
self.conf_generator.available_services = ["neutron"]
self.conf_generator._set_compute_ssh_connect_method()
self.assertEqual("floating",
self.conf_generator.conf.get("compute",
"ssh_connect_method"))
def test__set_default(self):
self.conf_generator._set_default()
expected = (("debug", "True"), ("log_file", "tempest.log"), expected = (("debug", "True"), ("log_file", "tempest.log"),
("use_stderr", "False")) ("use_stderr", "False"))
results = self.conf_generator.conf.items("DEFAULT") results = self.conf_generator.conf.items("DEFAULT")
self.assertEqual(sorted(expected), sorted(results)) self.assertEqual(sorted(expected), sorted(results))
def test__configure_identity(self):
self.conf_generator._configure_identity()
expected = (
("username", self.endpoint["username"]),
("password", self.endpoint["password"]),
("tenant_name", self.endpoint["tenant_name"]),
("admin_username", self.endpoint["username"]),
("admin_password", self.endpoint["password"]),
("admin_tenant_name", self.endpoint["username"]),
("admin_domain_name", self.endpoint["admin_domain_name"]),
("uri", self.endpoint["auth_url"]),
("uri_v3", self.endpoint["auth_url"].replace("/v2.0/", "/v3")))
results = self._remove_default_section(
self.conf_generator.conf.items("identity"))
self.assertEqual(sorted(expected), sorted(results))
def test__configure_option_flavor(self):
mock_novaclient = mock.MagicMock()
mock_novaclient.flavors.create.side_effect = [
fakes.FakeFlavor(id="id1"), fakes.FakeFlavor(id="id2")]
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
self.context.conf.set("compute", "flavor_ref", "")
self.context.conf.set("compute", "flavor_ref_alt", "")
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.context._configure_option("flavor_ref",
mock_novaclient.flavors.create, 64)
self.context._configure_option("flavor_ref_alt",
mock_novaclient.flavors.create, 128)
self.assertEqual(mock_novaclient.flavors.create.call_count, 2)
expected = ("id1", "id2")
results = (self.context.conf.get("compute", "flavor_ref"),
self.context.conf.get("compute", "flavor_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
@mock.patch("six.moves.builtins.open")
def test__configure_option_image(self, mock_open):
mock_glanceclient = mock.MagicMock()
mock_glanceclient.images.create.side_effect = [
fakes.FakeImage(id="id1"), fakes.FakeImage(id="id2")]
mock_glance = mock.MagicMock()
mock_glance.Client.return_value = mock_glanceclient
self.context.conf.set("compute", "image_ref", "")
self.context.conf.set("compute", "image_ref_alt", "")
with mock.patch.dict("sys.modules", {"glanceclient": mock_glance}):
self.context._configure_option("image_ref",
mock_glanceclient.images.create)
self.context._configure_option("image_ref_alt",
mock_glanceclient.images.create)
self.assertEqual(mock_glanceclient.images.create.call_count, 2)
expected = ("id1", "id2")
results = (self.context.conf.get("compute", "image_ref"),
self.context.conf.get("compute", "image_ref_alt"))
self.assertEqual(sorted(expected), sorted(results))
def test__configure_network_if_neutron(self):
fake_neutronclient = mock.MagicMock()
fake_neutronclient.list_networks.return_value = {
"networks": [
{
"status": "ACTIVE",
"id": "test_id",
"router:external": True
}
]
}
mock_neutron = mock.MagicMock()
mock_neutron.client.Client.return_value = fake_neutronclient
with mock.patch.dict("sys.modules", {"neutronclient.neutron":
mock_neutron}):
self.conf_generator.available_services = ["neutron"]
self.conf_generator._configure_network()
expected = (("public_network_id", "test_id"),)
results = self._remove_default_section(
self.conf_generator.conf.items("network"))
self.assertEqual(sorted(expected), sorted(results))
def test__configure_network_if_nova(self):
self.conf_generator.available_services = ["nova"]
mock_novaclient = mock.MagicMock()
mock_network = mock.MagicMock()
mock_network.human_id = "fake-network"
mock_novaclient.networks.list.return_value = [mock_network]
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.conf_generator._configure_network()
self.assertEqual("fake-network",
self.conf_generator.conf.get(
"compute", "fixed_network_name"))
self.assertEqual("fake-network",
self.conf_generator.conf.get(
"compute", "network_for_ssh"))
@mock.patch("rally.verification.tempest.config.os.path.exists", @mock.patch("rally.verification.tempest.config.os.path.exists",
return_value=False) return_value=False)
@mock.patch("rally.verification.tempest.config.os.makedirs") @mock.patch("rally.verification.tempest.config.os.makedirs")
def test__set_oslo_concurrency(self, mock_makedirs, mock_exists): def test__configure_oslo_concurrency(self, mock_makedirs, mock_exists):
self.conf_generator._set_oslo_concurrency() self.conf_generator._configure_oslo_concurrency()
lock_path = os.path.join(self.conf_generator.data_path, "lock_files_%s" lock_path = os.path.join(
% self.deployment) self.conf_generator.data_dir, "lock_files_%s" % self.deployment)
mock_makedirs.assert_called_once_with(lock_path) mock_makedirs.assert_called_once_with(lock_path)
expected = (("lock_path", lock_path),) expected = (("lock_path", lock_path),)
results = self._remove_default_section( results = self._remove_default_section(
self.conf_generator.conf.items("oslo_concurrency")) self.conf_generator.conf.items("oslo_concurrency"))
self.assertEqual(sorted(expected), sorted(results)) self.assertEqual(sorted(expected), sorted(results))
def test__set_identity(self):
self.conf_generator._set_identity()
expected = (("username", self.endpoint["username"]),
("password", self.endpoint["password"]),
("tenant_name", self.endpoint["tenant_name"]),
("alt_username", self.endpoint["username"]),
("alt_password", self.endpoint["password"]),
("alt_tenant_name", self.endpoint["tenant_name"]),
("admin_username", self.endpoint["username"]),
("admin_password", self.endpoint["password"]),
("admin_tenant_name", self.endpoint["username"]),
("admin_domain_name", self.endpoint["admin_domain_name"]),
("uri", self.endpoint["auth_url"]),
("uri_v3", self.endpoint["auth_url"].replace("/v2.0",
"/v3")))
results = self._remove_default_section(
self.conf_generator.conf.items("identity"))
self.assertEqual(sorted(expected), sorted(results))
def test__set_network_if_neutron(self):
fake_neutronclient = mock.MagicMock()
fake_neutronclient.list_networks.return_value = {"networks": [
{"status": "ACTIVE",
"id": "test_id",
"router:external":
True}]}
fake_neutronclient.list_routers.return_value = {"routers": [
{"id": "test_router"}]}
fake_neutronclient.list_subnets.return_value = {"subnets": [
{"cidr":
"10.0.0.0/24"}]}
mock_neutron = mock.MagicMock()
mock_neutron.client.Client.return_value = fake_neutronclient
with mock.patch.dict("sys.modules", {"neutronclient.neutron":
mock_neutron}):
self.conf_generator.available_services = ["neutron"]
self.conf_generator._set_network()
expected = (("tenant_network_cidr", "10.0.0.0/24"),
("tenant_networks_reachable", "False"),
("public_network_id", "test_id"),
("public_router_id", "test_router"))
results = self._remove_default_section(
self.conf_generator.conf.items("network"))
self.assertEqual(sorted(expected), sorted(results))
def test__set_network_if_nova(self):
network = "10.0.0.0/24"
mock_novaclient = mock.MagicMock()
mock_network = mock.MagicMock()
mock_network.cidr = network
mock_novaclient.networks.list.return_value = [mock_network]
mock_nova = mock.MagicMock()
mock_nova.client.Client.return_value = mock_novaclient
with mock.patch.dict("sys.modules", {"novaclient": mock_nova}):
self.conf_generator._set_network()
self.assertEqual(network,
self.conf_generator.conf.get(
"network", "tenant_network_cidr"))
@mock.patch("rally.verification.tempest.config.requests") @mock.patch("rally.verification.tempest.config.requests")
def test__set_service_available(self, mock_requests): def test__configure_service_available(self, mock_requests):
mock_result = mock.MagicMock() mock_result = mock.MagicMock()
mock_result.status_code = 404 mock_result.status_code = 404
mock_requests.get.return_value = mock_result mock_requests.get.return_value = mock_result
available_services = ("nova", "cinder", "glance") available_services = ("nova", "cinder", "glance", "sahara")
self.conf_generator.available_services = available_services self.conf_generator.available_services = available_services
self.conf_generator._set_service_available() self.conf_generator._configure_service_available()
expected = (("neutron", "False"), ("heat", "False"), expected = (("neutron", "False"), ("heat", "False"),
("ceilometer", "False"), ("swift", "False"), ("ceilometer", "False"), ("swift", "False"),
("cinder", "True"), ("nova", "True"), ("cinder", "True"), ("nova", "True"),
("glance", "True"), ("horizon", "False")) ("glance", "True"), ("horizon", "False"),
("sahara", "True"))
options = self._remove_default_section( options = self._remove_default_section(
self.conf_generator.conf.items("service_available")) self.conf_generator.conf.items("service_available"))
self.assertEqual(sorted(expected), sorted(options)) self.assertEqual(sorted(expected), sorted(options))
@mock.patch("rally.verification.tempest.config.requests") @mock.patch("rally.verification.tempest.config.requests")
def test__set_service_available_horizon(self, mock_requests): def test__configure_service_available_horizon(self, mock_requests):
mock_result = mock.MagicMock() mock_result = mock.MagicMock()
mock_result.status_code = 200 mock_result.status_code = 200
mock_requests.get.return_value = mock_result mock_requests.get.return_value = mock_result
self.conf_generator._set_service_available() self.conf_generator._configure_service_available()
self.assertEqual(self.conf_generator.conf.get( self.assertEqual(
self.conf_generator.conf.get(
"service_available", "horizon"), "True") "service_available", "horizon"), "True")
@mock.patch("rally.verification.tempest.config.requests.get") @mock.patch("rally.verification.tempest.config.requests.get")
def test__set_service_not_available_horizon(self, mock_get): def test__configure_service_not_available_horizon(self, mock_get):
mock_get.side_effect = requests.Timeout() mock_get.side_effect = requests.Timeout()
self.conf_generator._set_service_available() self.conf_generator._configure_service_available()
self.assertEqual(self.conf_generator.conf.get( self.assertEqual(
self.conf_generator.conf.get(
"service_available", "horizon"), "False") "service_available", "horizon"), "False")
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open(), def test__configure_validation_if_neutron(self):
create=True) # if neutron is available
def test_write_config(self, mock_open): self.conf_generator.available_services = ["neutron"]
self.conf_generator.conf = mock.Mock() self.conf_generator._configure_validation()
file_name = "/path/to/fake/conf" self.assertEqual("floating",
self.conf_generator.conf.get("validation",
"connect_method"))
self.conf_generator.write_config(file_name) def test__configure_validation_if_novanetwork(self):
self.conf_generator._configure_validation()
self.assertEqual("fixed",
self.conf_generator.conf.get("validation",
"connect_method"))
mock_open.assert_called_once_with(file_name, "w+") @mock.patch("six.moves.builtins.open",
self.conf_generator.conf.write.assert_called_once_with( side_effect=mock.mock_open(), create=True)
mock_open.side_effect()) def test__write_config(self, mock_open):
conf_path = "/path/to/fake/conf"
conf_data = mock.Mock()
config._write_config(conf_path, conf_data)
mock_open.assert_called_once_with(conf_path, "w+")
conf_data.write.assert_called_once_with(mock_open.side_effect())

View File

@ -339,12 +339,14 @@ class TempestVerifyTestCase(BaseTestCase):
return_value=(None, None)) return_value=(None, None))
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.env") @mock.patch(TEMPEST_PATH + ".tempest.Tempest.env")
@mock.patch(TEMPEST_PATH + ".tempest.subprocess") @mock.patch(TEMPEST_PATH + ".tempest.subprocess")
@mock.patch(TEMPEST_PATH + ".config.TempestConf") @mock.patch(TEMPEST_PATH + ".config.TempestResourcesContext")
@mock.patch(TEMPEST_PATH + ".config.TempestConfig")
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.is_configured", @mock.patch(TEMPEST_PATH + ".tempest.Tempest.is_configured",
return_value=False) return_value=False)
def test_verify_not_configured( def test_verify_not_configured(
self, mock_tempest_is_configured, mock_tempest_conf, self, mock_tempest_is_configured, mock_tempest_config,
mock_subprocess, mock_tempest_env, mock_tempest_parse_results): mock_tempest_resources_context, mock_subprocess, mock_tempest_env,
mock_tempest_parse_results):
set_name = "compute" set_name = "compute"
fake_call = self._get_fake_call(set_name) fake_call = self._get_fake_call(set_name)
@ -352,8 +354,8 @@ class TempestVerifyTestCase(BaseTestCase):
self.verifier.verify(set_name, None) self.verifier.verify(set_name, None)
self.assertEqual(2, mock_tempest_is_configured.call_count) self.assertEqual(2, mock_tempest_is_configured.call_count)
mock_tempest_conf.assert_called_once_with(self.verifier.deployment) mock_tempest_config.assert_called_once_with(self.verifier.deployment)
mock_tempest_conf.return_value.generate.assert_called_once_with( mock_tempest_config.return_value.generate.assert_called_once_with(
self.verifier.config_file self.verifier.config_file
) )
self.verifier.verification.start_verifying.assert_called_once_with( self.verifier.verification.start_verifying.assert_called_once_with(
@ -368,20 +370,22 @@ class TempestVerifyTestCase(BaseTestCase):
return_value=(None, None)) return_value=(None, None))
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.env") @mock.patch(TEMPEST_PATH + ".tempest.Tempest.env")
@mock.patch(TEMPEST_PATH + ".tempest.subprocess") @mock.patch(TEMPEST_PATH + ".tempest.subprocess")
@mock.patch(TEMPEST_PATH + ".config.TempestConf") @mock.patch(TEMPEST_PATH + ".config.TempestResourcesContext")
@mock.patch(TEMPEST_PATH + ".config.TempestConfig")
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.is_configured", @mock.patch(TEMPEST_PATH + ".tempest.Tempest.is_configured",
return_value=True) return_value=True)
def test_verify_when_tempest_configured( def test_verify_when_tempest_configured(
self, mock_tempest_is_configured, mock_tempest_conf, self, mock_tempest_is_configured, mock_tempest_config,
mock_subprocess, mock_tempest_env, mock_tempest_parse_results): mock_tempest_resources_context, mock_subprocess, mock_tempest_env,
mock_tempest_parse_results):
set_name = "identity" set_name = "identity"
fake_call = self._get_fake_call(set_name) fake_call = self._get_fake_call(set_name)
self.verifier.verify(set_name, None) self.verifier.verify(set_name, None)
mock_tempest_is_configured.assert_called_once_with() mock_tempest_is_configured.assert_called_once_with()
self.assertFalse(mock_tempest_conf.called) self.assertFalse(mock_tempest_config.called)
self.assertFalse(mock_tempest_conf().generate.called) self.assertFalse(mock_tempest_config().generate.called)
self.verifier.verification.start_verifying.assert_called_once_with( self.verifier.verification.start_verifying.assert_called_once_with(
set_name) set_name)
@ -394,12 +398,14 @@ class TempestVerifyTestCase(BaseTestCase):
return_value=(None, None)) return_value=(None, None))
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.env") @mock.patch(TEMPEST_PATH + ".tempest.Tempest.env")
@mock.patch(TEMPEST_PATH + ".tempest.subprocess") @mock.patch(TEMPEST_PATH + ".tempest.subprocess")
@mock.patch(TEMPEST_PATH + ".config.TempestConf") @mock.patch(TEMPEST_PATH + ".config.TempestResourcesContext")
@mock.patch(TEMPEST_PATH + ".config.TempestConfig")
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.is_configured", @mock.patch(TEMPEST_PATH + ".tempest.Tempest.is_configured",
return_value=True) return_value=True)
def test_verify_failed_and_tempest_is_configured( def test_verify_failed_and_tempest_is_configured(
self, mock_tempest_is_configured, mock_tempest_conf, self, mock_tempest_is_configured, mock_tempest_config,
mock_subprocess, mock_tempest_env, mock_tempest_parse_results): mock_tempest_resources_context, mock_subprocess, mock_tempest_env,
mock_tempest_parse_results):
set_name = "identity" set_name = "identity"
fake_call = self._get_fake_call(set_name) fake_call = self._get_fake_call(set_name)
mock_subprocess.side_effect = subprocess.CalledProcessError mock_subprocess.side_effect = subprocess.CalledProcessError
@ -407,8 +413,8 @@ class TempestVerifyTestCase(BaseTestCase):
self.verifier.verify(set_name, None) self.verifier.verify(set_name, None)
mock_tempest_is_configured.assert_called_once_with() mock_tempest_is_configured.assert_called_once_with()
self.assertFalse(mock_tempest_conf.called) self.assertFalse(mock_tempest_config.called)
self.assertFalse(mock_tempest_conf().generate.called) self.assertFalse(mock_tempest_config().generate.called)
self.verifier.verification.start_verifying.assert_called_once_with( self.verifier.verification.start_verifying.assert_called_once_with(
set_name) set_name)