blob: a43d002239b4838f2138d5fe31aac21e0e7d806d [file] [log] [blame]
Matthew Treinish9e26ca82016-02-23 11:43:20 -05001# 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
16import logging
17import os
18import shlex
19import subprocess
20
21import six
22
23from tempest.lib import base
24import tempest.lib.cli.output_parser
25from tempest.lib import exceptions
26
27
28LOG = logging.getLogger(__name__)
29
30
31def execute(cmd, action, flags='', params='', fail_ok=False,
32 merge_stderr=False, cli_dir='/usr/bin'):
33 """Executes specified command for the given action.
34
35 :param cmd: command to be executed
36 :type cmd: string
37 :param action: string of the cli command to run
38 :type action: string
39 :param flags: any optional cli flags to use
40 :type flags: string
41 :param params: string of any optional positional args to use
42 :type params: string
43 :param fail_ok: boolean if True an exception is not raised when the
44 cli return code is non-zero
45 :type fail_ok: boolean
46 :param merge_stderr: boolean if True the stderr buffer is merged into
47 stdout
48 :type merge_stderr: boolean
49 :param cli_dir: The path where the cmd can be executed
50 :type cli_dir: string
51 """
52 cmd = ' '.join([os.path.join(cli_dir, cmd),
53 flags, action, params])
54 LOG.info("running: '%s'" % cmd)
55 if six.PY2:
56 cmd = cmd.encode('utf-8')
57 cmd = shlex.split(cmd)
58 result = ''
59 result_err = ''
60 stdout = subprocess.PIPE
61 stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
62 proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
63 result, result_err = proc.communicate()
64 if not fail_ok and proc.returncode != 0:
65 raise exceptions.CommandFailed(proc.returncode,
66 cmd,
67 result,
68 result_err)
69 if six.PY2:
70 return result
71 else:
72 return os.fsdecode(result)
73
74
75class CLIClient(object):
76 """Class to use OpenStack official python client CLI's with auth
77
78 :param username: The username to authenticate with
79 :type username: string
80 :param password: The password to authenticate with
81 :type password: string
82 :param tenant_name: The name of the tenant to use with the client calls
83 :type tenant_name: string
84 :param uri: The auth uri for the OpenStack Deployment
85 :type uri: string
86 :param cli_dir: The path where the python client binaries are installed.
87 defaults to /usr/bin
88 :type cli_dir: string
89 :param insecure: if True, --insecure is passed to python client binaries.
90 :type insecure: boolean
91 """
92
93 def __init__(self, username='', password='', tenant_name='', uri='',
94 cli_dir='', insecure=False, *args, **kwargs):
95 """Initialize a new CLIClient object."""
96 super(CLIClient, self).__init__()
97 self.cli_dir = cli_dir if cli_dir else '/usr/bin'
98 self.username = username
99 self.tenant_name = tenant_name
100 self.password = password
101 self.uri = uri
102 self.insecure = insecure
103
104 def nova(self, action, flags='', params='', fail_ok=False,
105 endpoint_type='publicURL', merge_stderr=False):
106 """Executes nova command for the given action.
107
108 :param action: the cli command to run using nova
109 :type action: string
110 :param flags: any optional cli flags to use
111 :type flags: string
112 :param params: any optional positional args to use
113 :type params: string
114 :param fail_ok: if True an exception is not raised when the
115 cli return code is non-zero
116 :type fail_ok: boolean
117 :param endpoint_type: the type of endpoint for the service
118 :type endpoint_type: string
119 :param merge_stderr: if True the stderr buffer is merged into stdout
120 :type merge_stderr: boolean
121 """
Kevin_Zhengc6795b52016-05-26 19:21:19 +0800122 flags += ' --os-endpoint-type %s' % endpoint_type
Matthew Treinish9e26ca82016-02-23 11:43:20 -0500123 return self.cmd_with_auth(
124 'nova', action, flags, params, fail_ok, merge_stderr)
125
126 def nova_manage(self, action, flags='', params='', fail_ok=False,
127 merge_stderr=False):
128 """Executes nova-manage command for the given action.
129
130 :param action: the cli command to run using nova-manage
131 :type action: string
132 :param flags: any optional cli flags to use
133 :type flags: string
134 :param params: any optional positional args to use
135 :type params: string
136 :param fail_ok: if True an exception is not raised when the
137 cli return code is non-zero
138 :type fail_ok: boolean
139 :param merge_stderr: if True the stderr buffer is merged into stdout
140 :type merge_stderr: boolean
141 """
142 return execute(
143 'nova-manage', action, flags, params, fail_ok, merge_stderr,
144 self.cli_dir)
145
146 def keystone(self, action, flags='', params='', fail_ok=False,
147 merge_stderr=False):
148 """Executes keystone command for the given action.
149
150 :param action: the cli command to run using keystone
151 :type action: string
152 :param flags: any optional cli flags to use
153 :type flags: string
154 :param params: any optional positional args to use
155 :type params: string
156 :param fail_ok: if True an exception is not raised when the
157 cli return code is non-zero
158 :type fail_ok: boolean
159 :param merge_stderr: if True the stderr buffer is merged into stdout
160 :type merge_stderr: boolean
161 """
162 return self.cmd_with_auth(
163 'keystone', action, flags, params, fail_ok, merge_stderr)
164
165 def glance(self, action, flags='', params='', fail_ok=False,
166 endpoint_type='publicURL', merge_stderr=False):
167 """Executes glance command for the given action.
168
169 :param action: the cli command to run using glance
170 :type action: string
171 :param flags: any optional cli flags to use
172 :type flags: string
173 :param params: any optional positional args to use
174 :type params: string
175 :param fail_ok: if True an exception is not raised when the
176 cli return code is non-zero
177 :type fail_ok: boolean
178 :param endpoint_type: the type of endpoint for the service
179 :type endpoint_type: string
180 :param merge_stderr: if True the stderr buffer is merged into stdout
181 :type merge_stderr: boolean
182 """
183 flags += ' --os-endpoint-type %s' % endpoint_type
184 return self.cmd_with_auth(
185 'glance', action, flags, params, fail_ok, merge_stderr)
186
187 def ceilometer(self, action, flags='', params='',
188 fail_ok=False, endpoint_type='publicURL',
189 merge_stderr=False):
190 """Executes ceilometer command for the given action.
191
192 :param action: the cli command to run using ceilometer
193 :type action: string
194 :param flags: any optional cli flags to use
195 :type flags: string
196 :param params: any optional positional args to use
197 :type params: string
198 :param fail_ok: if True an exception is not raised when the
199 cli return code is non-zero
200 :type fail_ok: boolean
201 :param endpoint_type: the type of endpoint for the service
202 :type endpoint_type: string
203 :param merge_stderr: if True the stderr buffer is merged into stdout
204 :type merge_stderr: boolean
205 """
206 flags += ' --os-endpoint-type %s' % endpoint_type
207 return self.cmd_with_auth(
208 'ceilometer', action, flags, params, fail_ok, merge_stderr)
209
210 def heat(self, action, flags='', params='',
211 fail_ok=False, endpoint_type='publicURL', merge_stderr=False):
212 """Executes heat command for the given action.
213
214 :param action: the cli command to run using heat
215 :type action: string
216 :param flags: any optional cli flags to use
217 :type flags: string
218 :param params: any optional positional args to use
219 :type params: string
220 :param fail_ok: if True an exception is not raised when the
221 cli return code is non-zero
222 :type fail_ok: boolean
223 :param endpoint_type: the type of endpoint for the service
224 :type endpoint_type: string
225 :param merge_stderr: if True the stderr buffer is merged into stdout
226 :type merge_stderr: boolean
227 """
228 flags += ' --os-endpoint-type %s' % endpoint_type
229 return self.cmd_with_auth(
230 'heat', action, flags, params, fail_ok, merge_stderr)
231
232 def cinder(self, action, flags='', params='', fail_ok=False,
233 endpoint_type='publicURL', merge_stderr=False):
234 """Executes cinder command for the given action.
235
236 :param action: the cli command to run using cinder
237 :type action: string
238 :param flags: any optional cli flags to use
239 :type flags: string
240 :param params: any optional positional args to use
241 :type params: string
242 :param fail_ok: if True an exception is not raised when the
243 cli return code is non-zero
244 :type fail_ok: boolean
245 :param endpoint_type: the type of endpoint for the service
246 :type endpoint_type: string
247 :param merge_stderr: if True the stderr buffer is merged into stdout
248 :type merge_stderr: boolean
249 """
afazekas84fd2b22016-05-26 13:59:32 +0200250 flags += ' --endpoint-type %s' % endpoint_type
Matthew Treinish9e26ca82016-02-23 11:43:20 -0500251 return self.cmd_with_auth(
252 'cinder', action, flags, params, fail_ok, merge_stderr)
253
254 def swift(self, action, flags='', params='', fail_ok=False,
255 endpoint_type='publicURL', merge_stderr=False):
256 """Executes swift command for the given action.
257
258 :param action: the cli command to run using swift
259 :type action: string
260 :param flags: any optional cli flags to use
261 :type flags: string
262 :param params: any optional positional args to use
263 :type params: string
264 :param fail_ok: if True an exception is not raised when the
265 cli return code is non-zero
266 :type fail_ok: boolean
267 :param endpoint_type: the type of endpoint for the service
268 :type endpoint_type: string
269 :param merge_stderr: if True the stderr buffer is merged into stdout
270 :type merge_stderr: boolean
271 """
272 flags += ' --os-endpoint-type %s' % endpoint_type
273 return self.cmd_with_auth(
274 'swift', action, flags, params, fail_ok, merge_stderr)
275
276 def neutron(self, action, flags='', params='', fail_ok=False,
277 endpoint_type='publicURL', merge_stderr=False):
278 """Executes neutron command for the given action.
279
280 :param action: the cli command to run using neutron
281 :type action: string
282 :param flags: any optional cli flags to use
283 :type flags: string
284 :param params: any optional positional args to use
285 :type params: string
286 :param fail_ok: if True an exception is not raised when the
287 cli return code is non-zero
288 :type fail_ok: boolean
289 :param endpoint_type: the type of endpoint for the service
290 :type endpoint_type: string
291 :param merge_stderr: if True the stderr buffer is merged into stdout
292 :type merge_stderr: boolean
293 """
294 flags += ' --endpoint-type %s' % endpoint_type
295 return self.cmd_with_auth(
296 'neutron', action, flags, params, fail_ok, merge_stderr)
297
298 def sahara(self, action, flags='', params='',
299 fail_ok=False, endpoint_type='publicURL', merge_stderr=True):
300 """Executes sahara command for the given action.
301
302 :param action: the cli command to run using sahara
303 :type action: string
304 :param flags: any optional cli flags to use
305 :type flags: string
306 :param params: any optional positional args to use
307 :type params: string
308 :param fail_ok: if True an exception is not raised when the
309 cli return code is non-zero
310 :type fail_ok: boolean
311 :param endpoint_type: the type of endpoint for the service
312 :type endpoint_type: string
313 :param merge_stderr: if True the stderr buffer is merged into stdout
314 :type merge_stderr: boolean
315 """
316 flags += ' --endpoint-type %s' % endpoint_type
317 return self.cmd_with_auth(
318 'sahara', action, flags, params, fail_ok, merge_stderr)
319
320 def openstack(self, action, flags='', params='', fail_ok=False,
321 merge_stderr=False):
322 """Executes openstack command for the given action.
323
324 :param action: the cli command to run using openstack
325 :type action: string
326 :param flags: any optional cli flags to use
327 :type flags: string
328 :param params: any optional positional args to use
329 :type params: string
330 :param fail_ok: if True an exception is not raised when the
331 cli return code is non-zero
332 :type fail_ok: boolean
333 :param merge_stderr: if True the stderr buffer is merged into stdout
334 :type merge_stderr: boolean
335 """
336 return self.cmd_with_auth(
337 'openstack', action, flags, params, fail_ok, merge_stderr)
338
339 def cmd_with_auth(self, cmd, action, flags='', params='',
340 fail_ok=False, merge_stderr=False):
341 """Executes given command with auth attributes appended.
342
343 :param cmd: command to be executed
344 :type cmd: string
345 :param action: command on cli to run
346 :type action: string
347 :param flags: optional cli flags to use
348 :type flags: string
349 :param params: optional positional args to use
350 :type params: string
351 :param fail_ok: if True an exception is not raised when the cli return
352 code is non-zero
353 :type fail_ok: boolean
354 :param merge_stderr: if True the stderr buffer is merged into stdout
355 :type merge_stderr: boolean
356 """
357 creds = ('--os-username %s --os-tenant-name %s --os-password %s '
358 '--os-auth-url %s' %
359 (self.username,
360 self.tenant_name,
361 self.password,
362 self.uri))
363 if self.insecure:
364 flags = creds + ' --insecure ' + flags
365 else:
366 flags = creds + ' ' + flags
367 return execute(cmd, action, flags, params, fail_ok, merge_stderr,
368 self.cli_dir)
369
370
371class ClientTestBase(base.BaseTestCase):
372 """Base test class for testing the OpenStack client CLI interfaces."""
373
374 def setUp(self):
375 super(ClientTestBase, self).setUp()
376 self.clients = self._get_clients()
377 self.parser = tempest.lib.cli.output_parser
378
379 def _get_clients(self):
380 """Abstract method to initialize CLIClient object.
381
382 This method must be overloaded in child test classes. It should be
383 used to initialize the CLIClient object with the appropriate
384 credentials during the setUp() phase of tests.
385 """
386 raise NotImplementedError
387
388 def assertTableStruct(self, items, field_names):
389 """Verify that all items has keys listed in field_names.
390
391 :param items: items to assert are field names in the output table
392 :type items: list
393 :param field_names: field names from the output table of the cmd
394 :type field_names: list
395 """
396 for item in items:
397 for field in field_names:
398 self.assertIn(field, item)
399
400 def assertFirstLineStartsWith(self, lines, beginning):
401 """Verify that the first line starts with a string
402
403 :param lines: strings for each line of output
404 :type lines: list
405 :param beginning: verify this is at the beginning of the first line
406 :type beginning: string
407 """
408 self.assertTrue(lines[0].startswith(beginning),
409 msg=('Beginning of first line has invalid content: %s'
410 % lines[:3]))