blob: c33589a0c7bd4148f1d12490fd1ed8eca1b9285b [file] [log] [blame]
Joe Gordonc97f5c72013-02-14 01:15:57 +00001# Copyright 2013 OpenStack Foundation
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Matt Riedemann27bdb052014-07-30 14:57:55 -070016import functools
Mikhail S Medvedev13168d02013-06-24 16:13:40 -050017import os
Pavel Sedláka2b757c2013-02-25 18:16:04 +010018import shlex
19import subprocess
Joe Gordonc97f5c72013-02-14 01:15:57 +000020
Matt Riedemann27bdb052014-07-30 14:57:55 -070021import testtools
22
Sean Daguef6825792013-05-08 13:51:26 -040023import tempest.cli.output_parser
Matthew Treinishe2b56b52014-01-29 19:25:50 +000024from tempest import config
Matthew Treinishaeb52742014-07-25 18:38:56 -040025from tempest import exceptions
Matthew Treinishf4a9b0f2013-07-26 16:58:26 -040026from tempest.openstack.common import log as logging
Matt Riedemann27bdb052014-07-30 14:57:55 -070027from tempest.openstack.common import versionutils
Pavel Sedláka2b757c2013-02-25 18:16:04 +010028import tempest.test
Joe Gordonc97f5c72013-02-14 01:15:57 +000029
Matthew Treinish90aedd12013-02-25 17:56:49 -050030
Joe Gordonc97f5c72013-02-14 01:15:57 +000031LOG = logging.getLogger(__name__)
32
Matthew Treinishe2b56b52014-01-29 19:25:50 +000033CONF = config.CONF
Pavel Sedláka2b757c2013-02-25 18:16:04 +010034
35
Matt Riedemann27bdb052014-07-30 14:57:55 -070036def execute(cmd, action, flags='', params='', fail_ok=False,
37 merge_stderr=False):
38 """Executes specified command for the given action."""
39 cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
40 flags, action, params])
41 LOG.info("running: '%s'" % cmd)
42 cmd = shlex.split(cmd.encode('utf-8'))
43 result = ''
44 result_err = ''
45 stdout = subprocess.PIPE
46 stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
47 proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
48 result, result_err = proc.communicate()
49 if not fail_ok and proc.returncode != 0:
50 raise exceptions.CommandFailed(proc.returncode,
51 cmd,
52 result,
53 result_err)
54 return result
55
56
57def check_client_version(client, version):
58 """Checks if the client's version is compatible with the given version
59
60 @param client: The client to check.
61 @param version: The version to compare against.
62 @return: True if the client version is compatible with the given version
63 parameter, False otherwise.
64 """
65 current_version = execute(client, '', params='--version',
66 merge_stderr=True)
67
68 if not current_version.strip():
69 raise exceptions.TempestException('"%s --version" output was empty' %
70 client)
71
72 return versionutils.is_compatible(version, current_version,
73 same_major=False)
74
75
76def min_client_version(*args, **kwargs):
77 """A decorator to skip tests if the client used isn't of the right version.
78
79 @param client: The client command to run. For python-novaclient, this is
80 'nova', for python-cinderclient this is 'cinder', etc.
81 @param version: The minimum version required to run the CLI test.
82 """
83 def decorator(func):
84 @functools.wraps(func)
85 def wrapper(*func_args, **func_kwargs):
86 if not check_client_version(kwargs['client'], kwargs['version']):
87 msg = "requires %s client version >= %s" % (kwargs['client'],
88 kwargs['version'])
89 raise testtools.TestCase.skipException(msg)
90 return func(*func_args, **func_kwargs)
91 return wrapper
92 return decorator
93
94
Pavel Sedláka2b757c2013-02-25 18:16:04 +010095class ClientTestBase(tempest.test.BaseTestCase):
96 @classmethod
97 def setUpClass(cls):
98 if not CONF.cli.enabled:
99 msg = "cli testing disabled"
100 raise cls.skipException(msg)
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100101 super(ClientTestBase, cls).setUpClass()
102
103 def __init__(self, *args, **kwargs):
Sean Daguef6825792013-05-08 13:51:26 -0400104 self.parser = tempest.cli.output_parser
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100105 super(ClientTestBase, self).__init__(*args, **kwargs)
106
107 def nova(self, action, flags='', params='', admin=True, fail_ok=False):
108 """Executes nova command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000109 flags += ' --endpoint-type %s' % CONF.compute.endpoint_type
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100110 return self.cmd_with_auth(
111 'nova', action, flags, params, admin, fail_ok)
112
Joe Gordone8b0e152013-03-25 13:37:15 -0400113 def nova_manage(self, action, flags='', params='', fail_ok=False,
Joe Gordon0e7cbf82013-03-25 19:49:12 +0000114 merge_stderr=False):
Joe Gordon4edb6452013-03-05 21:18:59 +0000115 """Executes nova-manage command for the given action."""
Matt Riedemann27bdb052014-07-30 14:57:55 -0700116 return execute(
Joe Gordone8b0e152013-03-25 13:37:15 -0400117 'nova-manage', action, flags, params, fail_ok, merge_stderr)
Joe Gordon4edb6452013-03-05 21:18:59 +0000118
Pavel Sedlák5ce5c032013-02-25 18:41:30 +0100119 def keystone(self, action, flags='', params='', admin=True, fail_ok=False):
120 """Executes keystone command for the given action."""
121 return self.cmd_with_auth(
122 'keystone', action, flags, params, admin, fail_ok)
123
afazekasf35f9402013-03-25 14:51:13 +0100124 def glance(self, action, flags='', params='', admin=True, fail_ok=False):
125 """Executes glance command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000126 flags += ' --os-endpoint-type %s' % CONF.image.endpoint_type
afazekasf35f9402013-03-25 14:51:13 +0100127 return self.cmd_with_auth(
128 'glance', action, flags, params, admin, fail_ok)
129
Mehdi Abaakouk8581c0b2013-10-04 10:45:42 +0200130 def ceilometer(self, action, flags='', params='', admin=True,
131 fail_ok=False):
132 """Executes ceilometer command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000133 flags += ' --os-endpoint-type %s' % CONF.telemetry.endpoint_type
Mehdi Abaakouk8581c0b2013-10-04 10:45:42 +0200134 return self.cmd_with_auth(
135 'ceilometer', action, flags, params, admin, fail_ok)
136
Steven Hardy5de54ee2013-12-31 15:58:30 +0000137 def heat(self, action, flags='', params='', admin=True,
138 fail_ok=False):
139 """Executes heat command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000140 flags += ' --os-endpoint-type %s' % CONF.orchestration.endpoint_type
Steven Hardy5de54ee2013-12-31 15:58:30 +0000141 return self.cmd_with_auth(
142 'heat', action, flags, params, admin, fail_ok)
143
saurabh467c4112013-07-08 17:08:31 +0530144 def cinder(self, action, flags='', params='', admin=True, fail_ok=False):
145 """Executes cinder command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000146 flags += ' --endpoint-type %s' % CONF.volume.endpoint_type
saurabh467c4112013-07-08 17:08:31 +0530147 return self.cmd_with_auth(
148 'cinder', action, flags, params, admin, fail_ok)
149
vishal mahajan6251b782014-05-29 13:15:58 +0530150 def swift(self, action, flags='', params='', admin=True, fail_ok=False):
151 """Executes swift command for the given action."""
152 flags += ' --os-endpoint-type %s' % CONF.object_storage.endpoint_type
153 return self.cmd_with_auth(
154 'swift', action, flags, params, admin, fail_ok)
155
saurabh55c29c72013-07-26 21:15:08 +0530156 def neutron(self, action, flags='', params='', admin=True, fail_ok=False):
157 """Executes neutron command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000158 flags += ' --endpoint-type %s' % CONF.network.endpoint_type
saurabh55c29c72013-07-26 21:15:08 +0530159 return self.cmd_with_auth(
160 'neutron', action, flags, params, admin, fail_ok)
161
Ajay Yadavacf2fda2014-06-18 12:01:43 +0530162 def sahara(self, action, flags='', params='', admin=True,
163 fail_ok=False, merge_stderr=True):
Sergey Lukjanov9c95a252014-03-13 23:59:22 +0400164 """Executes sahara command for the given action."""
JordanP71c85f62014-02-26 15:53:43 +0000165 flags += ' --endpoint-type %s' % CONF.data_processing.endpoint_type
Sergey Lukjanov582d1c62014-01-21 19:51:21 +0400166 return self.cmd_with_auth(
Ajay Yadavacf2fda2014-06-18 12:01:43 +0530167 'sahara', action, flags, params, admin, fail_ok, merge_stderr)
Sergey Lukjanov582d1c62014-01-21 19:51:21 +0400168
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100169 def cmd_with_auth(self, cmd, action, flags='', params='',
Ajay Yadavacf2fda2014-06-18 12:01:43 +0530170 admin=True, fail_ok=False, merge_stderr=False):
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100171 """Executes given command with auth attributes appended."""
Attila Fazekasc3a095b2013-08-17 09:15:44 +0200172 # TODO(jogo) make admin=False work
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100173 creds = ('--os-username %s --os-tenant-name %s --os-password %s '
JordanP71c85f62014-02-26 15:53:43 +0000174 '--os-auth-url %s' %
Matthew Treinishe2b56b52014-01-29 19:25:50 +0000175 (CONF.identity.admin_username,
176 CONF.identity.admin_tenant_name,
177 CONF.identity.admin_password,
178 CONF.identity.uri))
Pavel Sedláka2b757c2013-02-25 18:16:04 +0100179 flags = creds + ' ' + flags
Matt Riedemann27bdb052014-07-30 14:57:55 -0700180 return execute(cmd, action, flags, params, fail_ok, merge_stderr)
Pavel Sedlák5ce5c032013-02-25 18:41:30 +0100181
182 def assertTableStruct(self, items, field_names):
183 """Verify that all items has keys listed in field_names."""
184 for item in items:
185 for field in field_names:
186 self.assertIn(field, item)
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200187
Pavel Sedlák4c18fa12013-08-22 21:29:45 +0200188 def assertFirstLineStartsWith(self, lines, beginning):
189 self.assertTrue(lines[0].startswith(beginning),
190 msg=('Beginning of first line has invalid content: %s'
191 % lines[:3]))