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
*.pyc
etc/config.ini
etc/storm.conf
etc/tempest.conf
include/swift_objects/swift_small
include/swift_objects/swift_medium
include/swift_objects/swift_large
*.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.
Quickstart
----------
You're going to want to make your own config.ini file in the /etc/ directory,
it needs to point at your running cluster.
To run Tempest, you first need to create a configuration file that
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
run_tests.sh --glance
run_tests.sh --swift
run_tests.sh --auth
$> cd $TEMPEST_ROOT_DIR
$> cp etc/storm.conf.sample etc/storm.conf
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 httplib2
from storm import exceptions
import storm.config
class RestClient(object):
def __init__(self, user, key, auth_url, tenant_name=None):
self.config = storm.config.StormConfig()
def __init__(self, config, user, key, auth_url, tenant_name=None):
self.config = config
if self.config.env.authentication == 'keystone_v2':
self.token, self.base_url = self.keystone_v2_auth(user,
key,
@ -55,6 +56,7 @@ class RestClient(object):
resp, body = self.http_obj.request(auth_url, 'POST',
headers=headers, body=body)
if resp.status == 200:
try:
auth_data = json.loads(body)['access']
token = auth_data['token']['id']
@ -67,9 +69,11 @@ class RestClient(object):
service_url = temp[0] + '//' + temp[2] + '/' + temp[3] + '/'
management_url = service_url + tenant_name
return token, management_url
except KeyError:
print "Failed to authenticate user"
except Exception, e:
print "Failed to authenticate user: %s" % e
raise
elif resp.status == 401:
raise exceptions.AuthenticationFailure(user=user, password=api_key)
def post(self, url, body, headers):
return self.request('POST', url, headers, body)

View File

@ -1,4 +1,8 @@
import ConfigParser
import logging
import os
LOG = logging.getLogger(__name__)
class NovaConfig(object):
@ -119,15 +123,24 @@ class EnvironmentConfig(object):
class StormConfig(object):
"""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):
"""Initialize a configuration from a path."""
self._conf = self.load_config(self._path)
:param conf_dir: Directory to look for config files
:param conf_file: Name of config file to use
"""
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.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."""
config = ConfigParser.SafeConfigParser()
config.read(path)

View File

@ -16,3 +16,10 @@ class BadRequest(Exception):
def __str__(self):
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.flavors_client import FlavorsClient
from storm.services.nova.json.servers_client import ServersClient
@ -7,38 +9,57 @@ import storm.config
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):
"""
Top level manager for all Openstack APIs
"""
self.config = storm.config.StormConfig()
# Environment variables override defaults...
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.config.nova.port,
self.config.nova.apiVer,
self.config.nova.path)
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.auth_url,
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.auth_url,
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.auth_url,
self.config.nova.tenant_name)
else:
#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.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.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.auth_url)

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ class ImagesMetadataTest(unittest.TestCase):
cls.os = openstack.Manager()
cls.servers_client = cls.os.servers_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.flavor_ref = cls.config.env.flavor_ref
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 storm.config
# Some module-level skip conditions
create_image_enabled = False
class ImagesTest(unittest.TestCase):
create_image_enabled = storm.config.StormConfig().env.create_image_enabled
@classmethod
def setUpClass(cls):
cls.os = openstack.Manager()
cls.client = cls.os.images_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.flavor_ref = cls.config.env.flavor_ref
create_image_enabled = cls.config.env.create_image_enabled
def _parse_image_id(self, image_ref):
temp = image_ref.rsplit('/')

View File

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

View File

@ -11,7 +11,7 @@ class ServerDetailsTest(unittest.TestCase):
def setUpClass(cls):
cls.os = openstack.Manager()
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.flavor_ref = cls.config.env.flavor_ref
cls.image_ref_alt = cls.config.env.image_ref_alt

View File

@ -11,7 +11,7 @@ class ServerMetadataTest(unittest.TestCase):
def setUpClass(cls):
cls.os = openstack.Manager()
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.flavor_ref = cls.config.env.flavor_ref

View File

@ -13,7 +13,7 @@ class ServersTest(unittest.TestCase):
def setUpClass(cls):
cls.os = openstack.Manager()
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.flavor_ref = cls.config.env.flavor_ref
cls.ssh_timeout = cls.config.nova.ssh_timeout

View File

@ -14,7 +14,7 @@ class ServersNegativeTest(unittest.TestCase):
def setUpClass(cls):
cls.os = openstack.Manager()
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.flavor_ref = cls.config.env.flavor_ref
cls.ssh_timeout = cls.config.nova.ssh_timeout