Fixes LP Bug#899383 - Cleanup config file search

Cleans up a bunch of configuration-related errors
when trying to run tempest out of the box with a
simple call to:

$> nosetests storm

* Raises a sensible error if the config file cannot be found
* Makes it possible to set the config file directory and
  config file name via environment variables
* Removes unnecessary calls to create storm.config.StormConfig()
  and share a configuration object by passing the openstack.Manager's
  config object with the various rest client objects
* Updates the README to show how to make a config file and run
  the tests in tempest

Change-Id: I60e33595b88df596cc9585bcaf18d37ae77d6f2b
This commit is contained in:
Jay Pipes 2011-12-02 15:53:32 -05:00
parent e1b050d01c
commit 7f75763f54
17 changed files with 128 additions and 62 deletions

3
.gitignore vendored
View File

@ -1,7 +1,10 @@
.kong-venv .kong-venv
*.pyc *.pyc
etc/config.ini etc/config.ini
etc/storm.conf
etc/tempest.conf
include/swift_objects/swift_small include/swift_objects/swift_small
include/swift_objects/swift_medium include/swift_objects/swift_medium
include/swift_objects/swift_large include/swift_objects/swift_large
*.log *.log
*.swp

View File

@ -1,25 +1,37 @@
:: ::
OpenStack integration test suite Tempest - The OpenStack Integration Test Suite
================================ ==============================================
This is a set of integration tests to be run against a live cluster. This is a set of integration tests to be run against a live cluster.
Quickstart Quickstart
---------- ----------
You're going to want to make your own config.ini file in the /etc/ directory, To run Tempest, you first need to create a configuration file that
it needs to point at your running cluster. will tell Tempest where to find the various OpenStack services and
other testing behaviour switches.
After that try commands such as:: The easiest way to create a configuration file is to copy the sample
one in the ``etc/`` directory ::
run_tests.sh --nova $> cd $TEMPEST_ROOT_DIR
run_tests.sh --glance $> cp etc/storm.conf.sample etc/storm.conf
run_tests.sh --swift
run_tests.sh --auth
After that, open up the ``etc/storm.conf`` file and edit the
variables to fit your test environment.
Additional Info .. note::
---------------
There are additional README files in the various subdirectories of this project. If you have a running devstack environment, look at the
environment variables in your ``devstack/localrc`` file.
The ADMIN_PASSWORD variable should match the api_key value
in the storm.conf [nova] configuration section. In addition,
you will need to get the UUID identifier of the image that
devstack uploaded and set the image_ref value in the [environment]
section in the storm.conf to that image UUID.
After setting up your configuration file, you can execute the set of
Tempest tests by using ``nosetests`` ::
$> nosetests storm

View File

@ -1,14 +1,15 @@
from storm import exceptions
import httplib2
import json import json
import httplib2
from storm import exceptions
import storm.config import storm.config
class RestClient(object): class RestClient(object):
def __init__(self, user, key, auth_url, tenant_name=None): def __init__(self, config, user, key, auth_url, tenant_name=None):
self.config = storm.config.StormConfig() self.config = config
if self.config.env.authentication == 'keystone_v2': if self.config.env.authentication == 'keystone_v2':
self.token, self.base_url = self.keystone_v2_auth(user, self.token, self.base_url = self.keystone_v2_auth(user,
key, key,
@ -55,21 +56,24 @@ class RestClient(object):
resp, body = self.http_obj.request(auth_url, 'POST', resp, body = self.http_obj.request(auth_url, 'POST',
headers=headers, body=body) headers=headers, body=body)
try: if resp.status == 200:
auth_data = json.loads(body)['access'] try:
token = auth_data['token']['id'] auth_data = json.loads(body)['access']
endpoints = auth_data['serviceCatalog'][0]['endpoints'] token = auth_data['token']['id']
mgmt_url = endpoints[0]['publicURL'] endpoints = auth_data['serviceCatalog'][0]['endpoints']
mgmt_url = endpoints[0]['publicURL']
#TODO (dwalleck): This is a horrible stopgap. #TODO (dwalleck): This is a horrible stopgap.
#Need to join strings more cleanly #Need to join strings more cleanly
temp = mgmt_url.rsplit('/') temp = mgmt_url.rsplit('/')
service_url = temp[0] + '//' + temp[2] + '/' + temp[3] + '/' service_url = temp[0] + '//' + temp[2] + '/' + temp[3] + '/'
management_url = service_url + tenant_name management_url = service_url + tenant_name
return token, management_url return token, management_url
except KeyError: except Exception, e:
print "Failed to authenticate user" print "Failed to authenticate user: %s" % e
raise raise
elif resp.status == 401:
raise exceptions.AuthenticationFailure(user=user, password=api_key)
def post(self, url, body, headers): def post(self, url, body, headers):
return self.request('POST', url, headers, body) return self.request('POST', url, headers, body)

View File

@ -1,4 +1,8 @@
import ConfigParser import ConfigParser
import logging
import os
LOG = logging.getLogger(__name__)
class NovaConfig(object): class NovaConfig(object):
@ -119,15 +123,24 @@ class EnvironmentConfig(object):
class StormConfig(object): class StormConfig(object):
"""Provides OpenStack configuration information.""" """Provides OpenStack configuration information."""
_path = "etc/storm.conf" def __init__(self, conf_dir, conf_file):
"""
Initialize a configuration from a conf directory and conf file.
def __init__(self, path=None): :param conf_dir: Directory to look for config files
"""Initialize a configuration from a path.""" :param conf_file: Name of config file to use
self._conf = self.load_config(self._path) """
path = os.path.join(conf_dir, conf_file)
if not os.path.exists(path):
msg = "Config file %(path)s not found" % locals()
raise RuntimeError(msg)
self._conf = self.load_config(path)
self.nova = NovaConfig(self._conf) self.nova = NovaConfig(self._conf)
self.env = EnvironmentConfig(self._conf) self.env = EnvironmentConfig(self._conf)
def load_config(self, path=None): def load_config(self, path):
"""Read configuration from given path and return a config object.""" """Read configuration from given path and return a config object."""
config = ConfigParser.SafeConfigParser() config = ConfigParser.SafeConfigParser()
config.read(path) config.read(path)

View File

@ -16,3 +16,10 @@ class BadRequest(Exception):
def __str__(self): def __str__(self):
return repr(self.message) return repr(self.message)
class AuthenticationFailure(Exception):
msg = ("Authentication with user %(user)s and password "
"%(password)s failed.")
def __init__(self, **kwargs):
self.message = self.msg % kwargs

View File

@ -1,3 +1,5 @@
import os
from storm.services.nova.json.images_client import ImagesClient from storm.services.nova.json.images_client import ImagesClient
from storm.services.nova.json.flavors_client import FlavorsClient from storm.services.nova.json.flavors_client import FlavorsClient
from storm.services.nova.json.servers_client import ServersClient from storm.services.nova.json.servers_client import ServersClient
@ -7,38 +9,57 @@ import storm.config
class Manager(object): class Manager(object):
DEFAULT_CONFIG_DIR = os.path.join(
os.path.abspath(
os.path.dirname(
os.path.dirname(__file__))),
"etc")
DEFAULT_CONFIG_FILE = "storm.conf"
def __init__(self): def __init__(self):
""" """
Top level manager for all Openstack APIs Top level manager for all Openstack APIs
""" """
# Environment variables override defaults...
self.config = storm.config.StormConfig() config_dir = os.environ.get('TEMPEST_CONFIG_DIR',
self.DEFAULT_CONFIG_DIR)
config_file = os.environ.get('TEMPEST_CONFIG',
self.DEFAULT_CONFIG_FILE)
self.config = storm.config.StormConfig(config_dir, config_file)
self.auth_url = data_utils.build_url(self.config.nova.host, self.auth_url = data_utils.build_url(self.config.nova.host,
self.config.nova.port, self.config.nova.port,
self.config.nova.apiVer, self.config.nova.apiVer,
self.config.nova.path) self.config.nova.path)
if self.config.env.authentication == 'keystone_v2': if self.config.env.authentication == 'keystone_v2':
self.servers_client = ServersClient(self.config.nova.username, self.servers_client = ServersClient(self.config,
self.config.nova.username,
self.config.nova.api_key, self.config.nova.api_key,
self.auth_url, self.auth_url,
self.config.nova.tenant_name) self.config.nova.tenant_name)
self.flavors_client = FlavorsClient(self.config.nova.username, self.flavors_client = FlavorsClient(self.config,
self.config.nova.username,
self.config.nova.api_key, self.config.nova.api_key,
self.auth_url, self.auth_url,
self.config.nova.tenant_name) self.config.nova.tenant_name)
self.images_client = ImagesClient(self.config.nova.username, self.images_client = ImagesClient(self.config,
self.config.nova.username,
self.config.nova.api_key, self.config.nova.api_key,
self.auth_url, self.auth_url,
self.config.nova.tenant_name) self.config.nova.tenant_name)
else: else:
#Assuming basic/native authentication #Assuming basic/native authentication
self.servers_client = ServersClient(self.config.nova.username, self.servers_client = ServersClient(self.config,
self.config.nova.username,
self.config.nova.api_key, self.config.nova.api_key,
self.auth_url) self.auth_url)
self.flavors_client = FlavorsClient(self.config.nova.username, self.flavors_client = FlavorsClient(self.config,
self.config.nova.username,
self.config.nova.api_key, self.config.nova.api_key,
self.auth_url) self.auth_url)
self.images_client = ImagesClient(self.config.nova.username, self.images_client = ImagesClient(self.config,
self.config.nova.username,
self.config.nova.auth_url,
self.config.nova.api_key, self.config.nova.api_key,
self.auth_url) self.auth_url)

View File

@ -5,8 +5,9 @@ import time
class FlavorsClient(object): class FlavorsClient(object):
def __init__(self, username, key, auth_url, tenant_name=None): def __init__(self, config, username, key, auth_url, tenant_name=None):
self.client = rest_client.RestClient(username, key, self.config = config
self.client = rest_client.RestClient(config, username, key,
auth_url, tenant_name) auth_url, tenant_name)
def list_flavors(self, params=None): def list_flavors(self, params=None):

View File

@ -6,10 +6,10 @@ import time
class ImagesClient(object): class ImagesClient(object):
def __init__(self, username, key, auth_url, tenant_name=None): def __init__(self, config, username, key, auth_url, tenant_name=None):
self.client = rest_client.RestClient(username, key, self.config = config
self.client = rest_client.RestClient(config, username, key,
auth_url, tenant_name) auth_url, tenant_name)
self.config = storm.config.StormConfig()
self.build_interval = self.config.nova.build_interval self.build_interval = self.config.nova.build_interval
self.build_timeout = self.config.nova.build_timeout self.build_timeout = self.config.nova.build_timeout
self.headers = {'Content-Type': 'application/json', self.headers = {'Content-Type': 'application/json',

View File

@ -7,10 +7,10 @@ import time
class ServersClient(object): class ServersClient(object):
def __init__(self, username, key, auth_url, tenant_name=None): def __init__(self, config, username, key, auth_url, tenant_name=None):
self.client = rest_client.RestClient(username, key, self.config = config
self.client = rest_client.RestClient(config, username, key,
auth_url, tenant_name) auth_url, tenant_name)
self.config = storm.config.StormConfig()
self.build_interval = self.config.nova.build_interval self.build_interval = self.config.nova.build_interval
self.build_timeout = self.config.nova.build_timeout self.build_timeout = self.config.nova.build_timeout
self.headers = {'Content-Type': 'application/json', self.headers = {'Content-Type': 'application/json',

View File

@ -10,7 +10,7 @@ class FlavorsTest(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.flavors_client cls.client = cls.os.flavors_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.flavor_id = cls.config.env.flavor_ref cls.flavor_id = cls.config.env.flavor_ref
@attr(type='smoke') @attr(type='smoke')

View File

@ -12,7 +12,7 @@ class ImagesMetadataTest(unittest.TestCase):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.servers_client = cls.os.servers_client cls.servers_client = cls.os.servers_client
cls.client = cls.os.images_client cls.client = cls.os.images_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref
cls.ssh_timeout = cls.config.nova.ssh_timeout cls.ssh_timeout = cls.config.nova.ssh_timeout

View File

@ -4,18 +4,21 @@ from storm.common.utils.data_utils import rand_name
import unittest2 as unittest import unittest2 as unittest
import storm.config import storm.config
# Some module-level skip conditions
create_image_enabled = False
class ImagesTest(unittest.TestCase): class ImagesTest(unittest.TestCase):
create_image_enabled = storm.config.StormConfig().env.create_image_enabled
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.images_client cls.client = cls.os.images_client
cls.servers_client = cls.os.servers_client cls.servers_client = cls.os.servers_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref
create_image_enabled = cls.config.env.create_image_enabled
def _parse_image_id(self, image_ref): def _parse_image_id(self, image_ref):
temp = image_ref.rsplit('/') temp = image_ref.rsplit('/')

View File

@ -4,19 +4,21 @@ import unittest2 as unittest
import storm.config import storm.config
from storm.common.utils.data_utils import rand_name from storm.common.utils.data_utils import rand_name
# Some module-level skip conditions
resize_available = False
class ServerActionsTest(unittest.TestCase): class ServerActionsTest(unittest.TestCase):
resize_available = storm.config.StormConfig().env.resize_available
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.servers_client cls.client = cls.os.servers_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.image_ref_alt = cls.config.env.image_ref_alt cls.image_ref_alt = cls.config.env.image_ref_alt
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref
cls.flavor_ref_alt = cls.config.env.flavor_ref_alt cls.flavor_ref_alt = cls.config.env.flavor_ref_alt
resize_available = cls.config.env.resize_available
def setUp(self): def setUp(self):
self.name = rand_name('server') self.name = rand_name('server')

View File

@ -11,7 +11,7 @@ class ServerDetailsTest(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.servers_client cls.client = cls.os.servers_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref
cls.image_ref_alt = cls.config.env.image_ref_alt cls.image_ref_alt = cls.config.env.image_ref_alt

View File

@ -11,7 +11,7 @@ class ServerMetadataTest(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.servers_client cls.client = cls.os.servers_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref

View File

@ -13,7 +13,7 @@ class ServersTest(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.servers_client cls.client = cls.os.servers_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref
cls.ssh_timeout = cls.config.nova.ssh_timeout cls.ssh_timeout = cls.config.nova.ssh_timeout

View File

@ -14,7 +14,7 @@ class ServersNegativeTest(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
cls.os = openstack.Manager() cls.os = openstack.Manager()
cls.client = cls.os.servers_client cls.client = cls.os.servers_client
cls.config = storm.config.StormConfig() cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref cls.flavor_ref = cls.config.env.flavor_ref
cls.ssh_timeout = cls.config.nova.ssh_timeout cls.ssh_timeout = cls.config.nova.ssh_timeout