TEMPEST_PLUGINS contains the list of the tempest plugins installed
alongside tempest by lib/tempest.
If TEMPEST_PLUGINS is not explicitly set, the new tempest_plugins
variable is used to fill it by combining its items with
the base devstack path.
Change-Id: I9f1fa2755e16871ff9d6ba33fdeaf3023eedf8d4
| ... | ... |
@@ -102,7 +102,6 @@ job.parent. |
| 102 | 102 |
tox_envlist: 'all' |
| 103 | 103 |
devstack_localrc: |
| 104 | 104 |
KURYR_K8S_API_PORT: 8080 |
| 105 |
- TEMPEST_PLUGINS: '/opt/stack/kuryr-tempest-plugin' |
|
| 106 | 105 |
devstack_services: |
| 107 | 106 |
kubernetes-api: true |
| 108 | 107 |
kubernetes-controller-manager: true |
| ... | ... |
@@ -114,6 +113,8 @@ job.parent. |
| 114 | 114 |
kuryr-kubernetes: https://git.openstack.org/openstack/kuryr |
| 115 | 115 |
devstack-plugin-container: https://git.openstack.org/openstack/devstack-plugin-container |
| 116 | 116 |
neutron-lbaas: https://git.openstack.org/openstack/neutron-lbaas |
| 117 |
+ tempest_plugins: |
|
| 118 |
+ - kuryr-tempest-plugin |
|
| 117 | 119 |
(...) |
| 118 | 120 |
|
| 119 | 121 |
Job variables |
| ... | ... |
@@ -88,3 +88,12 @@ Write the local.conf file for use by devstack |
| 88 | 88 |
If a plugin declares a dependency on another plugin (via |
| 89 | 89 |
``plugin_requires`` in the plugin's settings file), this role will |
| 90 | 90 |
automatically emit ``enable_plugin`` lines in the correct order. |
| 91 |
+ |
|
| 92 |
+.. zuul:rolevar:: tempest_plugins |
|
| 93 |
+ :type: list |
|
| 94 |
+ |
|
| 95 |
+ A list of tempest plugins which are installed alongside tempest. |
|
| 96 |
+ |
|
| 97 |
+ The list of values will be combined with the base devstack directory |
|
| 98 |
+ and used to populate the ``TEMPEST_PLUGINS`` variable. If the variable |
|
| 99 |
+ already exists, its value is *not* changed. |
| ... | ... |
@@ -207,13 +207,15 @@ class PluginGraph(DependencyGraph): |
| 207 | 207 |
class LocalConf(object): |
| 208 | 208 |
|
| 209 | 209 |
def __init__(self, localrc, localconf, base_services, services, plugins, |
| 210 |
- base_dir, projects, project): |
|
| 210 |
+ base_dir, projects, project, tempest_plugins): |
|
| 211 | 211 |
self.localrc = [] |
| 212 |
+ self.warnings = [] |
|
| 212 | 213 |
self.meta_sections = {}
|
| 213 | 214 |
self.plugin_deps = {}
|
| 214 | 215 |
self.base_dir = base_dir |
| 215 | 216 |
self.projects = projects |
| 216 | 217 |
self.project = project |
| 218 |
+ self.tempest_plugins = tempest_plugins |
|
| 217 | 219 |
if services or base_services: |
| 218 | 220 |
self.handle_services(base_services, services or {})
|
| 219 | 221 |
self.handle_localrc(localrc) |
| ... | ... |
@@ -246,12 +248,15 @@ class LocalConf(object): |
| 246 | 246 |
|
| 247 | 247 |
def handle_localrc(self, localrc): |
| 248 | 248 |
lfg = False |
| 249 |
+ tp = False |
|
| 249 | 250 |
if localrc: |
| 250 | 251 |
vg = VarGraph(localrc) |
| 251 | 252 |
for k, v in vg.getVars(): |
| 252 | 253 |
self.localrc.append('{}={}'.format(k, v))
|
| 253 | 254 |
if k == 'LIBS_FROM_GIT': |
| 254 | 255 |
lfg = True |
| 256 |
+ elif k == 'TEMPEST_PLUGINS': |
|
| 257 |
+ tp = True |
|
| 255 | 258 |
|
| 256 | 259 |
if not lfg and (self.projects or self.project): |
| 257 | 260 |
required_projects = [] |
| ... | ... |
@@ -266,6 +271,19 @@ class LocalConf(object): |
| 266 | 266 |
self.localrc.append('LIBS_FROM_GIT={}'.format(
|
| 267 | 267 |
','.join(required_projects))) |
| 268 | 268 |
|
| 269 |
+ if self.tempest_plugins: |
|
| 270 |
+ if not tp: |
|
| 271 |
+ tp_dirs = [] |
|
| 272 |
+ for tempest_plugin in self.tempest_plugins: |
|
| 273 |
+ tp_dirs.append(os.path.join(self.base_dir, tempest_plugin)) |
|
| 274 |
+ self.localrc.append('TEMPEST_PLUGINS="{}"'.format(
|
|
| 275 |
+ ' '.join(tp_dirs))) |
|
| 276 |
+ else: |
|
| 277 |
+ self.warnings.append('TEMPEST_PLUGINS already defined ({}),'
|
|
| 278 |
+ 'requested value {} ignored'.format(
|
|
| 279 |
+ tp, self.tempest_plugins)) |
|
| 280 |
+ |
|
| 281 |
+ |
|
| 269 | 282 |
def handle_localconf(self, localconf): |
| 270 | 283 |
for phase, phase_data in localconf.items(): |
| 271 | 284 |
for fn, fn_data in phase_data.items(): |
| ... | ... |
@@ -300,6 +318,7 @@ def main(): |
| 300 | 300 |
path=dict(type='str'), |
| 301 | 301 |
projects=dict(type='dict'), |
| 302 | 302 |
project=dict(type='dict'), |
| 303 |
+ tempest_plugins=dict(type='list'), |
|
| 303 | 304 |
) |
| 304 | 305 |
) |
| 305 | 306 |
|
| ... | ... |
@@ -311,10 +330,11 @@ def main(): |
| 311 | 311 |
p.get('plugins'),
|
| 312 | 312 |
p.get('base_dir'),
|
| 313 | 313 |
p.get('projects'),
|
| 314 |
- p.get('project'))
|
|
| 314 |
+ p.get('project'),
|
|
| 315 |
+ p.get('tempest_plugins'))
|
|
| 315 | 316 |
lc.write(p['path']) |
| 316 | 317 |
|
| 317 |
- module.exit_json() |
|
| 318 |
+ module.exit_json(warnings=lc.warnings) |
|
| 318 | 319 |
|
| 319 | 320 |
|
| 320 | 321 |
try: |
| ... | ... |
@@ -23,6 +23,20 @@ from devstack_local_conf import LocalConf |
| 23 | 23 |
from collections import OrderedDict |
| 24 | 24 |
|
| 25 | 25 |
class TestDevstackLocalConf(unittest.TestCase): |
| 26 |
+ |
|
| 27 |
+ @staticmethod |
|
| 28 |
+ def _init_localconf(p): |
|
| 29 |
+ lc = LocalConf(p.get('localrc'),
|
|
| 30 |
+ p.get('local_conf'),
|
|
| 31 |
+ p.get('base_services'),
|
|
| 32 |
+ p.get('services'),
|
|
| 33 |
+ p.get('plugins'),
|
|
| 34 |
+ p.get('base_dir'),
|
|
| 35 |
+ p.get('projects'),
|
|
| 36 |
+ p.get('project'),
|
|
| 37 |
+ p.get('tempest_plugins'))
|
|
| 38 |
+ return lc |
|
| 39 |
+ |
|
| 26 | 40 |
def setUp(self): |
| 27 | 41 |
self.tmpdir = tempfile.mkdtemp() |
| 28 | 42 |
|
| ... | ... |
@@ -51,14 +65,7 @@ class TestDevstackLocalConf(unittest.TestCase): |
| 51 | 51 |
plugins=plugins, |
| 52 | 52 |
base_dir='./test', |
| 53 | 53 |
path=os.path.join(self.tmpdir, 'test.local.conf')) |
| 54 |
- lc = LocalConf(p.get('localrc'),
|
|
| 55 |
- p.get('local_conf'),
|
|
| 56 |
- p.get('base_services'),
|
|
| 57 |
- p.get('services'),
|
|
| 58 |
- p.get('plugins'),
|
|
| 59 |
- p.get('base_dir'),
|
|
| 60 |
- p.get('projects'),
|
|
| 61 |
- p.get('project'))
|
|
| 54 |
+ lc = self._init_localconf(p) |
|
| 62 | 55 |
lc.write(p['path']) |
| 63 | 56 |
|
| 64 | 57 |
plugins = [] |
| ... | ... |
@@ -104,14 +111,7 @@ class TestDevstackLocalConf(unittest.TestCase): |
| 104 | 104 |
plugins=plugins, |
| 105 | 105 |
base_dir=self.tmpdir, |
| 106 | 106 |
path=os.path.join(self.tmpdir, 'test.local.conf')) |
| 107 |
- lc = LocalConf(p.get('localrc'),
|
|
| 108 |
- p.get('local_conf'),
|
|
| 109 |
- p.get('base_services'),
|
|
| 110 |
- p.get('services'),
|
|
| 111 |
- p.get('plugins'),
|
|
| 112 |
- p.get('base_dir'),
|
|
| 113 |
- p.get('projects'),
|
|
| 114 |
- p.get('project'))
|
|
| 107 |
+ lc = self._init_localconf(p) |
|
| 115 | 108 |
lc.write(p['path']) |
| 116 | 109 |
|
| 117 | 110 |
plugins = [] |
| ... | ... |
@@ -145,14 +145,7 @@ class TestDevstackLocalConf(unittest.TestCase): |
| 145 | 145 |
path=os.path.join(self.tmpdir, 'test.local.conf'), |
| 146 | 146 |
projects=projects, |
| 147 | 147 |
project=project) |
| 148 |
- lc = LocalConf(p.get('localrc'),
|
|
| 149 |
- p.get('local_conf'),
|
|
| 150 |
- p.get('base_services'),
|
|
| 151 |
- p.get('services'),
|
|
| 152 |
- p.get('plugins'),
|
|
| 153 |
- p.get('base_dir'),
|
|
| 154 |
- p.get('projects'),
|
|
| 155 |
- p.get('project'))
|
|
| 148 |
+ lc = self._init_localconf(p) |
|
| 156 | 149 |
lc.write(p['path']) |
| 157 | 150 |
|
| 158 | 151 |
lfg = None |
| ... | ... |
@@ -184,14 +177,7 @@ class TestDevstackLocalConf(unittest.TestCase): |
| 184 | 184 |
base_dir='./test', |
| 185 | 185 |
path=os.path.join(self.tmpdir, 'test.local.conf'), |
| 186 | 186 |
projects=projects) |
| 187 |
- lc = LocalConf(p.get('localrc'),
|
|
| 188 |
- p.get('local_conf'),
|
|
| 189 |
- p.get('base_services'),
|
|
| 190 |
- p.get('services'),
|
|
| 191 |
- p.get('plugins'),
|
|
| 192 |
- p.get('base_dir'),
|
|
| 193 |
- p.get('projects'),
|
|
| 194 |
- p.get('project'))
|
|
| 187 |
+ lc = self._init_localconf(p) |
|
| 195 | 188 |
lc.write(p['path']) |
| 196 | 189 |
|
| 197 | 190 |
lfg = None |
| ... | ... |
@@ -238,14 +224,50 @@ class TestDevstackLocalConf(unittest.TestCase): |
| 238 | 238 |
base_dir=self.tmpdir, |
| 239 | 239 |
path=os.path.join(self.tmpdir, 'test.local.conf')) |
| 240 | 240 |
with self.assertRaises(Exception): |
| 241 |
- lc = LocalConf(p.get('localrc'),
|
|
| 242 |
- p.get('local_conf'),
|
|
| 243 |
- p.get('base_services'),
|
|
| 244 |
- p.get('services'),
|
|
| 245 |
- p.get('plugins'),
|
|
| 246 |
- p.get('base_dir'))
|
|
| 241 |
+ lc = self._init_localconf(p) |
|
| 247 | 242 |
lc.write(p['path']) |
| 248 | 243 |
|
| 244 |
+ def _find_tempest_plugins_value(self, file_path): |
|
| 245 |
+ tp = None |
|
| 246 |
+ with open(file_path) as f: |
|
| 247 |
+ for line in f: |
|
| 248 |
+ if line.startswith('TEMPEST_PLUGINS'):
|
|
| 249 |
+ found = line.strip().split('=')[1]
|
|
| 250 |
+ self.assertIsNone(tp, |
|
| 251 |
+ "TEMPEST_PLUGIN ({}) found again ({})".format(
|
|
| 252 |
+ tp, found)) |
|
| 253 |
+ tp = found |
|
| 254 |
+ return tp |
|
| 255 |
+ |
|
| 256 |
+ def test_tempest_plugins(self): |
|
| 257 |
+ "Test that TEMPEST_PLUGINS is correctly populated." |
|
| 258 |
+ p = dict(base_services=[], |
|
| 259 |
+ base_dir='./test', |
|
| 260 |
+ path=os.path.join(self.tmpdir, 'test.local.conf'), |
|
| 261 |
+ tempest_plugins=['heat-tempest-plugin', 'sahara-tests']) |
|
| 262 |
+ lc = self._init_localconf(p) |
|
| 263 |
+ lc.write(p['path']) |
|
| 264 |
+ |
|
| 265 |
+ tp = self._find_tempest_plugins_value(p['path']) |
|
| 266 |
+ self.assertEqual('"./test/heat-tempest-plugin ./test/sahara-tests"', tp)
|
|
| 267 |
+ self.assertEqual(len(lc.warnings), 0) |
|
| 268 |
+ |
|
| 269 |
+ def test_tempest_plugins_not_overridden(self): |
|
| 270 |
+ """Test that the existing value of TEMPEST_PLUGINS is not overridden |
|
| 271 |
+ by the user-provided value, but a warning is emitted.""" |
|
| 272 |
+ localrc = {'TEMPEST_PLUGINS': 'someplugin'}
|
|
| 273 |
+ p = dict(localrc=localrc, |
|
| 274 |
+ base_services=[], |
|
| 275 |
+ base_dir='./test', |
|
| 276 |
+ path=os.path.join(self.tmpdir, 'test.local.conf'), |
|
| 277 |
+ tempest_plugins=['heat-tempest-plugin', 'sahara-tests']) |
|
| 278 |
+ lc = self._init_localconf(p) |
|
| 279 |
+ lc.write(p['path']) |
|
| 280 |
+ |
|
| 281 |
+ tp = self._find_tempest_plugins_value(p['path']) |
|
| 282 |
+ self.assertEqual('someplugin', tp)
|
|
| 283 |
+ self.assertEqual(len(lc.warnings), 1) |
|
| 284 |
+ |
|
| 249 | 285 |
|
| 250 | 286 |
if __name__ == '__main__': |
| 251 | 287 |
unittest.main() |
| ... | ... |
@@ -10,4 +10,5 @@ |
| 10 | 10 |
local_conf: "{{ devstack_local_conf|default(omit) }}"
|
| 11 | 11 |
base_dir: "{{ devstack_base_dir|default(omit) }}"
|
| 12 | 12 |
projects: "{{ zuul.projects }}"
|
| 13 |
- project: "{{ zuul.project }}"
|
|
| 14 | 13 |
\ No newline at end of file |
| 14 |
+ project: "{{ zuul.project }}"
|
|
| 15 |
+ tempest_plugins: "{{ tempest_plugins|default(omit) }}"
|