531 lines
19 KiB
Python
531 lines
19 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2012 OpenStack, LLC
|
|
# All Rights Reserved.
|
|
#
|
|
# 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 logging
|
|
import os
|
|
import sys
|
|
|
|
from tempest.common.utils import data_utils
|
|
from tempest.openstack.common import cfg
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
identity_group = cfg.OptGroup(name='identity',
|
|
title="Keystone Configuration Options")
|
|
|
|
IdentityGroup = [
|
|
cfg.StrOpt('catalog_type',
|
|
default='identity',
|
|
help="Catalog type of the Identity service."),
|
|
cfg.BoolOpt('disable_ssl_certificate_validation',
|
|
default=False,
|
|
help="Set to True if using self-signed SSL certificates."),
|
|
cfg.StrOpt('uri',
|
|
default=None,
|
|
help="Full URI of the OpenStack Identity API (Keystone)"),
|
|
cfg.StrOpt('host',
|
|
default="127.0.0.1",
|
|
help="(DEPRECATED, use uri) Host IP for making Identity "
|
|
"API requests."),
|
|
cfg.IntOpt('port',
|
|
default=8773,
|
|
help="(DEPRECATED, use uri) Port for the Identity service."),
|
|
cfg.StrOpt('api_version',
|
|
default="v1.1",
|
|
help="(DEPRECATED, use uri) Version of the Identity API"),
|
|
cfg.StrOpt('path',
|
|
default='/',
|
|
help="(IGNORED) Path of API request"),
|
|
cfg.BoolOpt('use_ssl',
|
|
default=False,
|
|
help="(DEPRECATED, use uri) Specifies if we are using https."),
|
|
cfg.StrOpt('strategy',
|
|
default='keystone',
|
|
help="Which auth method does the environment use? "
|
|
"(basic|keystone)"),
|
|
cfg.StrOpt('region',
|
|
default=None,
|
|
help="The identity region name to use."),
|
|
]
|
|
|
|
|
|
def register_identity_opts(conf):
|
|
conf.register_group(identity_group)
|
|
for opt in IdentityGroup:
|
|
conf.register_opt(opt, group='identity')
|
|
|
|
# Fall back to piecemeal identity URI for legacy support
|
|
authurl = data_utils.build_url(conf.identity.host,
|
|
str(conf.identity.port),
|
|
conf.identity.api_version,
|
|
path='', # Ignore path...
|
|
use_ssl=conf.identity.use_ssl)
|
|
|
|
if not conf.identity.uri:
|
|
conf.identity.uri = authurl
|
|
|
|
|
|
identity_admin_group = cfg.OptGroup(name='identity-admin',
|
|
title="Identity Admin Options")
|
|
|
|
IdentityAdminGroup = [
|
|
cfg.StrOpt('username',
|
|
default='admin',
|
|
help="Username to use for Identity Admin API requests"),
|
|
cfg.StrOpt('tenant_name',
|
|
default='admin',
|
|
help="Tenant name to use for Identity Admin API requests"),
|
|
cfg.StrOpt('password',
|
|
default='pass',
|
|
help="API key to use for Identity Admin API requests",
|
|
secret=True),
|
|
]
|
|
|
|
|
|
def register_identity_admin_opts(conf):
|
|
conf.register_group(identity_admin_group)
|
|
for opt in IdentityAdminGroup:
|
|
conf.register_opt(opt, group='identity-admin')
|
|
|
|
|
|
compute_group = cfg.OptGroup(name='compute',
|
|
title='Compute Service Options')
|
|
|
|
ComputeGroup = [
|
|
cfg.BoolOpt('allow_tenant_isolation',
|
|
default=False,
|
|
help="Allows test cases to create/destroy tenants and "
|
|
"users. This option enables isolated test cases and "
|
|
"better parallel execution, but also requires that "
|
|
"OpenStack Identity API admin credentials are known."),
|
|
cfg.BoolOpt('allow_tenant_reuse',
|
|
default=True,
|
|
help="If allow_tenant_isolation is True and a tenant that "
|
|
"would be created for a given test already exists (such "
|
|
"as from a previously-failed run), re-use that tenant "
|
|
"instead of failing because of the conflict. Note that "
|
|
"this would result in the tenant being deleted at the "
|
|
"end of a subsequent successful run."),
|
|
cfg.StrOpt('username',
|
|
default='demo',
|
|
help="Username to use for Nova API requests."),
|
|
cfg.StrOpt('tenant_name',
|
|
default='demo',
|
|
help="Tenant name to use for Nova API requests."),
|
|
cfg.StrOpt('password',
|
|
default='pass',
|
|
help="API key to use when authenticating.",
|
|
secret=True),
|
|
cfg.StrOpt('alt_username',
|
|
default=None,
|
|
help="Username of alternate user to use for Nova API "
|
|
"requests."),
|
|
cfg.StrOpt('alt_tenant_name',
|
|
default=None,
|
|
help="Alternate user's Tenant name to use for Nova API "
|
|
"requests."),
|
|
cfg.StrOpt('alt_password',
|
|
default=None,
|
|
help="API key to use when authenticating as alternate user.",
|
|
secret=True),
|
|
cfg.StrOpt('region',
|
|
default=None,
|
|
help="The compute region name to use."),
|
|
cfg.StrOpt('image_ref',
|
|
default="{$IMAGE_ID}",
|
|
help="Valid secondary image reference to be used in tests."),
|
|
cfg.StrOpt('image_ref_alt',
|
|
default="{$IMAGE_ID_ALT}",
|
|
help="Valid secondary image reference to be used in tests."),
|
|
cfg.IntOpt('flavor_ref',
|
|
default=1,
|
|
help="Valid primary flavor to use in tests."),
|
|
cfg.IntOpt('flavor_ref_alt',
|
|
default=2,
|
|
help='Valid secondary flavor to be used in tests.'),
|
|
cfg.BoolOpt('resize_available',
|
|
default=False,
|
|
help="Does the test environment support resizing?"),
|
|
cfg.BoolOpt('live_migration_available',
|
|
default=False,
|
|
help="Does the test environment support live migration "
|
|
"available?"),
|
|
cfg.BoolOpt('use_block_migration_for_live_migration',
|
|
default=False,
|
|
help="Does the test environment use block devices for live "
|
|
"migration"),
|
|
cfg.BoolOpt('change_password_available',
|
|
default=False,
|
|
help="Does the test environment support changing the admin "
|
|
"password?"),
|
|
cfg.BoolOpt('create_image_enabled',
|
|
default=False,
|
|
help="Does the test environment support snapshots?"),
|
|
cfg.IntOpt('build_interval',
|
|
default=10,
|
|
help="Time in seconds between build status checks."),
|
|
cfg.IntOpt('build_timeout',
|
|
default=300,
|
|
help="Timeout in seconds to wait for an instance to build."),
|
|
cfg.BoolOpt('run_ssh',
|
|
default=False,
|
|
help="Does the test environment support snapshots?"),
|
|
cfg.StrOpt('ssh_user',
|
|
default='root',
|
|
help="User name used to authenticate to an instance."),
|
|
cfg.IntOpt('ssh_timeout',
|
|
default=300,
|
|
help="Timeout in seconds to wait for authentcation to "
|
|
"succeed."),
|
|
cfg.StrOpt('network_for_ssh',
|
|
default='public',
|
|
help="Network used for SSH connections."),
|
|
cfg.IntOpt('ip_version_for_ssh',
|
|
default=4,
|
|
help="IP version used for SSH connections."),
|
|
cfg.StrOpt('catalog_type',
|
|
default='compute',
|
|
help="Catalog type of the Compute service."),
|
|
cfg.StrOpt('log_level',
|
|
default="ERROR",
|
|
help="Level for logging compute API calls."),
|
|
cfg.BoolOpt('whitebox_enabled',
|
|
default=False,
|
|
help="Does the test environment support whitebox tests for "
|
|
"Compute?"),
|
|
cfg.StrOpt('db_uri',
|
|
default=None,
|
|
help="Connection string to the database of Compute service"),
|
|
cfg.StrOpt('source_dir',
|
|
default="/opt/stack/nova",
|
|
help="Path of nova source directory"),
|
|
cfg.StrOpt('config_path',
|
|
default='/etc/nova/nova.conf',
|
|
help="Path of nova configuration file"),
|
|
cfg.StrOpt('bin_dir',
|
|
default="/usr/local/bin/",
|
|
help="Directory containing nova binaries such as nova-manage"),
|
|
cfg.StrOpt('path_to_private_key',
|
|
default=None,
|
|
help="Path to a private key file for SSH access to remote "
|
|
"hosts"),
|
|
cfg.BoolOpt('disk_config_enabled_override',
|
|
default=True,
|
|
help="If false, skip config tests regardless of the "
|
|
"extension status"),
|
|
]
|
|
|
|
|
|
def register_compute_opts(conf):
|
|
conf.register_group(compute_group)
|
|
for opt in ComputeGroup:
|
|
conf.register_opt(opt, group='compute')
|
|
|
|
compute_admin_group = cfg.OptGroup(name='compute-admin',
|
|
title="Compute Admin Options")
|
|
|
|
ComputeAdminGroup = [
|
|
cfg.StrOpt('username',
|
|
default='admin',
|
|
help="Administrative Username to use for Nova API requests."),
|
|
cfg.StrOpt('tenant_name',
|
|
default='admin',
|
|
help="Administrative Tenant name to use for Nova API "
|
|
"requests."),
|
|
cfg.StrOpt('password',
|
|
default='pass',
|
|
help="API key to use when authenticating as admin.",
|
|
secret=True),
|
|
]
|
|
|
|
|
|
def register_compute_admin_opts(conf):
|
|
conf.register_group(compute_admin_group)
|
|
for opt in ComputeAdminGroup:
|
|
conf.register_opt(opt, group='compute-admin')
|
|
|
|
|
|
image_group = cfg.OptGroup(name='image',
|
|
title="Image Service Options")
|
|
|
|
ImageGroup = [
|
|
cfg.StrOpt('host',
|
|
default='127.0.0.1',
|
|
help="Host IP for making Images API requests. Defaults to "
|
|
"'127.0.0.1'."),
|
|
cfg.IntOpt('port',
|
|
default=9292,
|
|
help="Listen port of the Images service."),
|
|
cfg.StrOpt('api_version',
|
|
default='1',
|
|
help="Version of the API"),
|
|
cfg.StrOpt('username',
|
|
default='demo',
|
|
help="Username to use for Images API requests. Defaults to "
|
|
"'demo'."),
|
|
cfg.StrOpt('password',
|
|
default='pass',
|
|
help="Password for user",
|
|
secret=True),
|
|
cfg.StrOpt('tenant_name',
|
|
default="demo",
|
|
help="Tenant to use for Images API requests. Defaults to "
|
|
"'demo'."),
|
|
]
|
|
|
|
|
|
def register_image_opts(conf):
|
|
conf.register_group(image_group)
|
|
for opt in ImageGroup:
|
|
conf.register_opt(opt, group='image')
|
|
|
|
|
|
network_group = cfg.OptGroup(name='network',
|
|
title='Network Service Options')
|
|
|
|
NetworkGroup = [
|
|
cfg.StrOpt('catalog_type',
|
|
default='network',
|
|
help='Catalog type of the Quantum service.'),
|
|
cfg.StrOpt('api_version',
|
|
default="v1.1",
|
|
help="Version of Quantum API"),
|
|
cfg.StrOpt('username',
|
|
default="demo",
|
|
help="Username to use for Quantum API requests."),
|
|
cfg.StrOpt('tenant_name',
|
|
default="demo",
|
|
help="Tenant name to use for Quantum API requests."),
|
|
cfg.StrOpt('password',
|
|
default="pass",
|
|
help="API key to use when authenticating as admin.",
|
|
secret=True),
|
|
cfg.StrOpt('tenant_network_cidr',
|
|
default="10.100.0.0/16",
|
|
help="The cidr block to allocate tenant networks from"),
|
|
cfg.IntOpt('tenant_network_mask_bits',
|
|
default=29,
|
|
help="The mask bits for tenant networks"),
|
|
cfg.BoolOpt('tenant_networks_reachable',
|
|
default=False,
|
|
help="Whether tenant network connectivity should be "
|
|
"evaluated directly"),
|
|
cfg.StrOpt('public_network_id',
|
|
default="",
|
|
help="Id of the public network that provides external "
|
|
"connectivity"),
|
|
cfg.StrOpt('public_router_id',
|
|
default="",
|
|
help="Id of the public router that provides external "
|
|
"connectivity"),
|
|
]
|
|
|
|
|
|
def register_network_opts(conf):
|
|
conf.register_group(network_group)
|
|
for opt in NetworkGroup:
|
|
conf.register_opt(opt, group='network')
|
|
|
|
network_admin_group = cfg.OptGroup(name='network-admin',
|
|
title="Network Admin Options")
|
|
|
|
NetworkAdminGroup = [
|
|
cfg.StrOpt('username',
|
|
default='admin',
|
|
help="Administrative Username to use for Quantum API "
|
|
"requests."),
|
|
cfg.StrOpt('tenant_name',
|
|
default='admin',
|
|
help="Administrative Tenant name to use for Quantum API "
|
|
"requests."),
|
|
cfg.StrOpt('password',
|
|
default='pass',
|
|
help="API key to use when authenticating as admin.",
|
|
secret=True),
|
|
]
|
|
|
|
|
|
def register_network_admin_opts(conf):
|
|
conf.register_group(network_admin_group)
|
|
for opt in NetworkAdminGroup:
|
|
conf.register_opt(opt, group='network-admin')
|
|
|
|
|
|
volume_group = cfg.OptGroup(name='volume',
|
|
title='Block Storage Options')
|
|
|
|
VolumeGroup = [
|
|
cfg.IntOpt('build_interval',
|
|
default=10,
|
|
help='Time in seconds between volume availability checks.'),
|
|
cfg.IntOpt('build_timeout',
|
|
default=300,
|
|
help='Timeout in seconds to wait for a volume to become'
|
|
'available.'),
|
|
cfg.StrOpt('catalog_type',
|
|
default='Volume',
|
|
help="Catalog type of the Volume Service"),
|
|
]
|
|
|
|
|
|
def register_volume_opts(conf):
|
|
conf.register_group(volume_group)
|
|
for opt in VolumeGroup:
|
|
conf.register_opt(opt, group='volume')
|
|
|
|
|
|
object_storage_group = cfg.OptGroup(name='object-storage',
|
|
title='Object Storage Service Options')
|
|
|
|
ObjectStoreConfig = [
|
|
cfg.StrOpt('catalog_type',
|
|
default='object-store',
|
|
help="Catalog type of the Object-Storage service."),
|
|
cfg.StrOpt('region',
|
|
default=None,
|
|
help='The object-store region name to use.'),
|
|
]
|
|
|
|
|
|
def register_object_storage_opts(conf):
|
|
conf.register_group(object_storage_group)
|
|
for opt in ObjectStoreConfig:
|
|
conf.register_opt(opt, group='object-storage')
|
|
|
|
boto_group = cfg.OptGroup(name='boto',
|
|
title='EC2/S3 options')
|
|
BotoConfig = [
|
|
cfg.StrOpt('ec2_url',
|
|
default="http://localhost:8773/services/Cloud",
|
|
help="EC2 URL"),
|
|
cfg.StrOpt('s3_url',
|
|
default="http://localhost:8080",
|
|
help="S3 URL"),
|
|
cfg.StrOpt('aws_secret',
|
|
default=None,
|
|
help="AWS Secret Key",
|
|
secret=True),
|
|
cfg.StrOpt('aws_access',
|
|
default=None,
|
|
help="AWS Access Key"),
|
|
cfg.StrOpt('aws_region',
|
|
default=None,
|
|
help="AWS Region"),
|
|
cfg.StrOpt('s3_materials_path',
|
|
default="/opt/stack/devstack/files/images/"
|
|
"s3-materials/cirros-0.3.0",
|
|
help="S3 Materials Path"),
|
|
cfg.StrOpt('ari_manifest',
|
|
default="cirros-0.3.0-x86_64-initrd.manifest.xml",
|
|
help="ARI Ramdisk Image manifest"),
|
|
cfg.StrOpt('ami_manifest',
|
|
default="cirros-0.3.0-x86_64-blank.img.manifest.xml",
|
|
help="AMI Machine Image manifest"),
|
|
cfg.StrOpt('aki_manifest',
|
|
default="cirros-0.3.0-x86_64-vmlinuz.manifest.xml",
|
|
help="AKI Kernel Image manifest"),
|
|
cfg.StrOpt('instance_type',
|
|
default="m1.tiny",
|
|
help="Instance type"),
|
|
cfg.IntOpt('http_socket_timeout',
|
|
default=3,
|
|
help="boto Http socket timeout"),
|
|
cfg.IntOpt('num_retries',
|
|
default=1,
|
|
help="boto num_retries on error"),
|
|
cfg.IntOpt('build_timeout',
|
|
default=60,
|
|
help="Status Change Timeout"),
|
|
cfg.IntOpt('build_interval',
|
|
default=1,
|
|
help="Status Change Test Interval"),
|
|
]
|
|
|
|
|
|
def register_boto_opts(conf):
|
|
conf.register_group(boto_group)
|
|
for opt in BotoConfig:
|
|
conf.register_opt(opt, group='boto')
|
|
|
|
|
|
# TODO(jaypipes): Move this to a common utils (not data_utils...)
|
|
def singleton(cls):
|
|
"""Simple wrapper for classes that should only have a single instance."""
|
|
instances = {}
|
|
|
|
def getinstance():
|
|
if cls not in instances:
|
|
instances[cls] = cls()
|
|
return instances[cls]
|
|
return getinstance
|
|
|
|
|
|
@singleton
|
|
class TempestConfig:
|
|
"""Provides OpenStack configuration information."""
|
|
|
|
DEFAULT_CONFIG_DIR = os.path.join(
|
|
os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
|
|
"etc")
|
|
|
|
DEFAULT_CONFIG_FILE = "tempest.conf"
|
|
|
|
def __init__(self):
|
|
"""Initialize a configuration from a conf directory and conf file."""
|
|
|
|
# Environment variables override defaults...
|
|
conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
|
|
self.DEFAULT_CONFIG_DIR)
|
|
conf_file = os.environ.get('TEMPEST_CONFIG', self.DEFAULT_CONFIG_FILE)
|
|
|
|
path = os.path.join(conf_dir, conf_file)
|
|
|
|
if (not os.path.isfile(path) and
|
|
not 'TEMPEST_CONFIG_DIR' in os.environ and
|
|
not 'TEMPEST_CONFIG' in os.environ):
|
|
path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE
|
|
|
|
LOG.info("Using tempest config file %s" % path)
|
|
|
|
if not os.path.exists(path):
|
|
msg = "Config file %(path)s not found" % locals()
|
|
print >> sys.stderr, RuntimeError(msg)
|
|
sys.exit(os.EX_NOINPUT)
|
|
|
|
cfg.CONF([], project='tempest', default_config_files=[path])
|
|
|
|
register_compute_opts(cfg.CONF)
|
|
register_identity_opts(cfg.CONF)
|
|
register_identity_admin_opts(cfg.CONF)
|
|
register_compute_admin_opts(cfg.CONF)
|
|
register_image_opts(cfg.CONF)
|
|
register_network_opts(cfg.CONF)
|
|
register_network_admin_opts(cfg.CONF)
|
|
register_volume_opts(cfg.CONF)
|
|
register_object_storage_opts(cfg.CONF)
|
|
register_boto_opts(cfg.CONF)
|
|
self.compute = cfg.CONF.compute
|
|
self.compute_admin = cfg.CONF['compute-admin']
|
|
self.identity = cfg.CONF.identity
|
|
self.identity_admin = cfg.CONF['identity-admin']
|
|
self.images = cfg.CONF.image
|
|
self.network = cfg.CONF.network
|
|
self.network_admin = cfg.CONF['network-admin']
|
|
self.volume = cfg.CONF.volume
|
|
self.object_storage = cfg.CONF['object-storage']
|
|
self.boto = cfg.CONF.boto
|