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