blob: f675ea6f0afdbbbee59750de8f65f4488d5ee2db [file] [log] [blame]
Jay Pipes3f981df2012-03-27 18:59:44 -04001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack, LLC
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
Daryl Walleck1465d612011-11-02 02:22:15 -050018import ConfigParser
Jay Pipes7f757632011-12-02 15:53:32 -050019import logging
20import os
Jay Pipes3f981df2012-03-27 18:59:44 -040021
kavan-patil4ea2efb2011-12-09 08:58:50 +000022from tempest.common.utils import data_utils
Jay Pipes7f757632011-12-02 15:53:32 -050023
24LOG = logging.getLogger(__name__)
Daryl Walleck1465d612011-11-02 02:22:15 -050025
26
Jay Pipes3f981df2012-03-27 18:59:44 -040027class BaseConfig(object):
28
29 SECTION_NAME = None
Daryl Walleck1465d612011-11-02 02:22:15 -050030
31 def __init__(self, conf):
Daryl Walleck1465d612011-11-02 02:22:15 -050032 self.conf = conf
33
donald-ngo7fb1efa2011-12-13 17:17:36 -080034 def get(self, item_name, default_value=None):
Daryl Walleck1465d612011-11-02 02:22:15 -050035 try:
Jay Pipes3f981df2012-03-27 18:59:44 -040036 return self.conf.get(self.SECTION_NAME, item_name)
Daryl Walleck1465d612011-11-02 02:22:15 -050037 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
38 return default_value
39
Jay Pipes3f981df2012-03-27 18:59:44 -040040
41class IdentityConfig(BaseConfig):
42
43 """Provides configuration information for authenticating with Keystone."""
44
45 SECTION_NAME = "identity"
46
Daryl Walleck1465d612011-11-02 02:22:15 -050047 @property
Rohit Karajgie1b050d2011-12-02 16:13:18 -080048 def host(self):
Daryl Walleck587385b2012-03-03 13:00:26 -060049 """Host IP for making Identity API requests."""
donald-ngo7fb1efa2011-12-13 17:17:36 -080050 return self.get("host", "127.0.0.1")
Rohit Karajgie1b050d2011-12-02 16:13:18 -080051
52 @property
53 def port(self):
Daryl Walleck587385b2012-03-03 13:00:26 -060054 """Port for the Identity service."""
Rohit Karajgie1b050d2011-12-02 16:13:18 -080055 return self.get("port", "8773")
56
57 @property
Daryl Walleck587385b2012-03-03 13:00:26 -060058 def api_version(self):
59 """Version of the Identity API"""
60 return self.get("api_version", "v1.1")
Rohit Karajgie1b050d2011-12-02 16:13:18 -080061
62 @property
63 def path(self):
64 """Path of API request"""
65 return self.get("path", "/")
66
kavan-patil4ea2efb2011-12-09 08:58:50 +000067 @property
68 def auth_url(self):
Daryl Walleck587385b2012-03-03 13:00:26 -060069 """The Identity URL (derived)"""
kavan-patil4ea2efb2011-12-09 08:58:50 +000070 auth_url = data_utils.build_url(self.host,
71 self.port,
Daryl Walleck587385b2012-03-03 13:00:26 -060072 self.api_version,
donald-ngo7fb1efa2011-12-13 17:17:36 -080073 self.path,
74 use_ssl=self.use_ssl)
kavan-patil4ea2efb2011-12-09 08:58:50 +000075 return auth_url
76
Daryl Walleck1465d612011-11-02 02:22:15 -050077 @property
donald-ngo7fb1efa2011-12-13 17:17:36 -080078 def use_ssl(self):
79 """Specifies if we are using https."""
Dan Prince95195922012-03-12 15:14:51 -040080 return self.get("use_ssl", 'false').lower() != 'false'
donald-ngo7fb1efa2011-12-13 17:17:36 -080081
82 @property
Daryl Walleck587385b2012-03-03 13:00:26 -060083 def strategy(self):
84 """Which auth method does the environment use? (basic|keystone)"""
85 return self.get("strategy", 'keystone')
86
87
Jay Pipes3f981df2012-03-27 18:59:44 -040088class ComputeConfig(BaseConfig):
Daryl Walleck587385b2012-03-03 13:00:26 -060089
Jay Pipes3f981df2012-03-27 18:59:44 -040090 SECTION_NAME = "compute"
91
92 @property
93 def username(self):
94 """Username to use for Nova API requests."""
95 return self.get("username", "demo")
96
97 @property
98 def tenant_name(self):
99 """Tenant name to use for Nova API requests."""
100 return self.get("tenant_name", "demo")
101
102 @property
103 def password(self):
104 """API key to use when authenticating."""
105 return self.get("password", "pass")
106
107 @property
108 def alt_username(self):
109 """Username of alternate user to use for Nova API requests."""
110 return self.get("alt_username", "demo")
111
112 @property
113 def alt_tenant_name(self):
114 """Alternate user's Tenant name to use for Nova API requests."""
115 return self.get("alt_tenant_name", "demo")
116
117 @property
118 def alt_password(self):
119 """API key to use when authenticating as alternate user."""
120 return self.get("alt_password", "pass")
Daryl Walleck587385b2012-03-03 13:00:26 -0600121
122 @property
123 def image_ref(self):
124 """Valid primary image to use in tests."""
Jay Pipes3f981df2012-03-27 18:59:44 -0400125 return self.get("image_ref", "{$IMAGE_ID}")
Daryl Walleck587385b2012-03-03 13:00:26 -0600126
127 @property
128 def image_ref_alt(self):
129 """Valid secondary image reference to be used in tests."""
Jay Pipes3f981df2012-03-27 18:59:44 -0400130 return self.get("image_ref_alt", "{$IMAGE_ID_ALT}")
Daryl Walleck587385b2012-03-03 13:00:26 -0600131
132 @property
133 def flavor_ref(self):
134 """Valid primary flavor to use in tests."""
135 return self.get("flavor_ref", 1)
136
137 @property
138 def flavor_ref_alt(self):
139 """Valid secondary flavor to be used in tests."""
140 return self.get("flavor_ref_alt", 2)
141
142 @property
143 def resize_available(self):
144 """Does the test environment support resizing?"""
Dan Prince95195922012-03-12 15:14:51 -0400145 return self.get("resize_available", 'false').lower() != 'false'
Daryl Walleck587385b2012-03-03 13:00:26 -0600146
147 @property
148 def create_image_enabled(self):
149 """Does the test environment support snapshots?"""
Dan Prince95195922012-03-12 15:14:51 -0400150 return self.get("create_image_enabled", 'false').lower() != 'false'
Daryl Walleck587385b2012-03-03 13:00:26 -0600151
152 @property
Daryl Walleck1465d612011-11-02 02:22:15 -0500153 def build_interval(self):
154 """Time in seconds between build status checks."""
155 return float(self.get("build_interval", 10))
156
157 @property
Daryl Walleck1465d612011-11-02 02:22:15 -0500158 def build_timeout(self):
159 """Timeout in seconds to wait for an entity to build."""
160 return float(self.get("build_timeout", 300))
161
Daryl Walleck4aa82a92012-02-14 15:45:46 -0600162 @property
Daryl Walleckb90a1a62012-02-27 11:23:10 -0600163 def catalog_type(self):
Daryl Walleck587385b2012-03-03 13:00:26 -0600164 """Catalog type of the Compute service."""
Daryl Walleckb90a1a62012-02-27 11:23:10 -0600165 return self.get("catalog_type", 'compute')
Daryl Walleck4aa82a92012-02-14 15:45:46 -0600166
Daryl Walleck1465d612011-11-02 02:22:15 -0500167
Jay Pipes3f981df2012-03-27 18:59:44 -0400168class ImagesConfig(BaseConfig):
169
Jay Pipes50677282012-01-06 15:39:20 -0500170 """
171 Provides configuration information for connecting to an
172 OpenStack Images service.
173 """
174
Jay Pipes3f981df2012-03-27 18:59:44 -0400175 SECTION_NAME = "image"
Jay Pipes50677282012-01-06 15:39:20 -0500176
177 @property
178 def host(self):
179 """Host IP for making Images API requests. Defaults to '127.0.0.1'."""
180 return self.get("host", "127.0.0.1")
181
182 @property
183 def port(self):
184 """Listen port of the Images service."""
185 return int(self.get("port", "9292"))
186
187 @property
188 def api_version(self):
189 """Version of the API"""
190 return self.get("api_version", "1")
191
192 @property
193 def username(self):
Jay Pipes3f981df2012-03-27 18:59:44 -0400194 """Username to use for Images API requests. Defaults to 'demo'."""
195 return self.get("user", "demo")
Jay Pipes50677282012-01-06 15:39:20 -0500196
197 @property
198 def password(self):
199 """Password for user"""
Jay Pipes3f981df2012-03-27 18:59:44 -0400200 return self.get("password", "pass")
Jay Pipes50677282012-01-06 15:39:20 -0500201
202 @property
Jay Pipes3f981df2012-03-27 18:59:44 -0400203 def tenant_name(self):
204 """Tenant to use for Images API requests. Defaults to 'demo'."""
205 return self.get("tenant_name", "demo")
Jay Pipes50677282012-01-06 15:39:20 -0500206
207
Jay Pipes3f981df2012-03-27 18:59:44 -0400208# TODO(jaypipes): Move this to a common utils (not data_utils...)
209def singleton(cls):
210 """Simple wrapper for classes that should only have a single instance"""
211 instances = {}
212
213 def getinstance():
214 if cls not in instances:
215 instances[cls] = cls()
216 return instances[cls]
217 return getinstance
218
219
220@singleton
221class TempestConfig:
Daryl Walleck1465d612011-11-02 02:22:15 -0500222 """Provides OpenStack configuration information."""
223
Brian Waldon738cd632011-12-12 18:45:09 -0500224 DEFAULT_CONFIG_DIR = os.path.join(
225 os.path.abspath(
226 os.path.dirname(
227 os.path.dirname(__file__))),
228 "etc")
Daryl Walleck1465d612011-11-02 02:22:15 -0500229
Brian Waldon738cd632011-12-12 18:45:09 -0500230 DEFAULT_CONFIG_FILE = "tempest.conf"
231
232 def __init__(self):
233 """Initialize a configuration from a conf directory and conf file."""
234
235 # Environment variables override defaults...
236 conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
237 self.DEFAULT_CONFIG_DIR)
238 conf_file = os.environ.get('TEMPEST_CONFIG',
239 self.DEFAULT_CONFIG_FILE)
240
Jay Pipes7f757632011-12-02 15:53:32 -0500241 path = os.path.join(conf_dir, conf_file)
242
Jay Pipes3f981df2012-03-27 18:59:44 -0400243 LOG.info("Using tempest config file %s" % path)
244
Jay Pipes7f757632011-12-02 15:53:32 -0500245 if not os.path.exists(path):
246 msg = "Config file %(path)s not found" % locals()
247 raise RuntimeError(msg)
248
249 self._conf = self.load_config(path)
Daryl Walleck587385b2012-03-03 13:00:26 -0600250 self.compute = ComputeConfig(self._conf)
251 self.identity = IdentityConfig(self._conf)
Jay Pipes50677282012-01-06 15:39:20 -0500252 self.images = ImagesConfig(self._conf)
Daryl Walleck1465d612011-11-02 02:22:15 -0500253
Jay Pipes7f757632011-12-02 15:53:32 -0500254 def load_config(self, path):
Daryl Walleck1465d612011-11-02 02:22:15 -0500255 """Read configuration from given path and return a config object."""
256 config = ConfigParser.SafeConfigParser()
257 config.read(path)
258 return config