blob: 3750b113f84e5d5158755702526441dff2dfd1ac [file] [log] [blame]
Attila Fazekas0abbc952013-07-01 19:19:42 +02001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
lkuchlan52d7b0d2016-11-07 20:53:19 +020013import re
Attila Fazekas0abbc952013-07-01 19:19:42 +020014import time
15
Doug Hellmann583ce2c2015-03-11 14:55:46 +000016from oslo_log import log as logging
Matthew Treinish01472ff2015-02-20 17:26:52 -050017
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -070018from tempest.common import image as common_image
Attila Fazekas0abbc952013-07-01 19:19:42 +020019from tempest import config
20from tempest import exceptions
zhufl88c89b52016-07-01 18:09:05 +080021from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050022from tempest.lib import exceptions as lib_exc
Ken'ichi Ohmichi41721012016-06-22 10:41:26 -070023from tempest.lib.services.image.v1 import images_client as images_v1_client
Attila Fazekas0abbc952013-07-01 19:19:42 +020024
Sean Dague86bd8422013-12-20 09:56:44 -050025CONF = config.CONF
Attila Fazekas0abbc952013-07-01 19:19:42 +020026LOG = logging.getLogger(__name__)
27
28
Matt Riedemannf748c112017-02-03 11:33:11 -050029def _get_task_state(body):
30 return body.get('OS-EXT-STS:task_state', None)
31
32
Attila Fazekas0abbc952013-07-01 19:19:42 +020033# NOTE(afazekas): This function needs to know a token and a subject.
Ken'ichi Ohmichi39437e22013-10-06 00:21:38 +090034def wait_for_server_status(client, server_id, status, ready_wait=True,
Zhi Kun Liue5401762013-09-11 20:45:48 +080035 extra_timeout=0, raise_on_error=True):
Attila Fazekas0abbc952013-07-01 19:19:42 +020036 """Waits for a server to reach a given status."""
37
Attila Fazekas0abbc952013-07-01 19:19:42 +020038 # NOTE(afazekas): UNKNOWN status possible on ERROR
39 # or in a very early stage.
ghanshyam0f825252015-08-25 16:02:50 +090040 body = client.show_server(server_id)['server']
Attila Fazekas0abbc952013-07-01 19:19:42 +020041 old_status = server_status = body['status']
42 old_task_state = task_state = _get_task_state(body)
43 start_time = int(time.time())
Ken'ichi Ohmichi39437e22013-10-06 00:21:38 +090044 timeout = client.build_timeout + extra_timeout
Attila Fazekas0abbc952013-07-01 19:19:42 +020045 while True:
46 # NOTE(afazekas): Now the BUILD status only reached
Shane Wang111f86c2014-02-20 16:40:22 +080047 # between the UNKNOWN->ACTIVE transition.
Attila Fazekas0abbc952013-07-01 19:19:42 +020048 # TODO(afazekas): enumerate and validate the stable status set
49 if status == 'BUILD' and server_status != 'UNKNOWN':
50 return
51 if server_status == status:
52 if ready_wait:
53 if status == 'BUILD':
54 return
55 # NOTE(afazekas): The instance is in "ready for action state"
56 # when no task in progress
Ken'ichi Ohmichi534a05e2016-08-03 14:45:15 -070057 if task_state is None:
Attila Fazekas0abbc952013-07-01 19:19:42 +020058 # without state api extension 3 sec usually enough
Sean Dague86bd8422013-12-20 09:56:44 -050059 time.sleep(CONF.compute.ready_wait)
Attila Fazekas0abbc952013-07-01 19:19:42 +020060 return
61 else:
62 return
63
64 time.sleep(client.build_interval)
ghanshyam0f825252015-08-25 16:02:50 +090065 body = client.show_server(server_id)['server']
Attila Fazekas0abbc952013-07-01 19:19:42 +020066 server_status = body['status']
67 task_state = _get_task_state(body)
68 if (server_status != old_status) or (task_state != old_task_state):
69 LOG.info('State transition "%s" ==> "%s" after %d second wait',
70 '/'.join((old_status, str(old_task_state))),
71 '/'.join((server_status, str(task_state))),
72 time.time() - start_time)
Zhi Kun Liue5401762013-09-11 20:45:48 +080073 if (server_status == 'ERROR') and raise_on_error:
Attila Fazekas0462a7f2014-06-20 07:38:06 +020074 if 'fault' in body:
75 raise exceptions.BuildErrorException(body['fault'],
Matthew Treinish1d14c542014-06-17 20:25:40 -040076 server_id=server_id)
Attila Fazekas0462a7f2014-06-20 07:38:06 +020077 else:
78 raise exceptions.BuildErrorException(server_id=server_id)
Attila Fazekas0abbc952013-07-01 19:19:42 +020079
Ken'ichi Ohmichi39437e22013-10-06 00:21:38 +090080 timed_out = int(time.time()) - start_time >= timeout
Attila Fazekas0abbc952013-07-01 19:19:42 +020081
82 if timed_out:
Matt Riedemann629fa7c2013-12-11 18:20:56 -080083 expected_task_state = 'None' if ready_wait else 'n/a'
84 message = ('Server %(server_id)s failed to reach %(status)s '
85 'status and task state "%(expected_task_state)s" '
86 'within the required time (%(timeout)s s).' %
87 {'server_id': server_id,
88 'status': status,
89 'expected_task_state': expected_task_state,
90 'timeout': timeout})
Attila Fazekas0abbc952013-07-01 19:19:42 +020091 message += ' Current status: %s.' % server_status
Matt Riedemann629fa7c2013-12-11 18:20:56 -080092 message += ' Current task state: %s.' % task_state
zhufl88c89b52016-07-01 18:09:05 +080093 caller = test_utils.find_test_caller()
Matt Riedemann128c23e2014-05-02 13:46:39 -070094 if caller:
95 message = '(%s) %s' % (caller, message)
guo yunxianebb15f22016-11-01 21:03:35 +080096 raise lib_exc.TimeoutException(message)
Attila Fazekas0abbc952013-07-01 19:19:42 +020097 old_status = server_status
98 old_task_state = task_state
Matt Riedemannc00f3262013-12-14 12:03:55 -080099
100
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000101def wait_for_server_termination(client, server_id, ignore_error=False):
102 """Waits for server to reach termination."""
Matt Riedemannf748c112017-02-03 11:33:11 -0500103 try:
104 body = client.show_server(server_id)['server']
105 except lib_exc.NotFound:
106 return
zhuflf5cff8b2019-04-28 15:26:32 +0800107 old_status = body['status']
108 old_task_state = _get_task_state(body)
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000109 start_time = int(time.time())
110 while True:
Matt Riedemannf748c112017-02-03 11:33:11 -0500111 time.sleep(client.build_interval)
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000112 try:
ghanshyam0f825252015-08-25 16:02:50 +0900113 body = client.show_server(server_id)['server']
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000114 except lib_exc.NotFound:
115 return
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000116 server_status = body['status']
Matt Riedemannf748c112017-02-03 11:33:11 -0500117 task_state = _get_task_state(body)
118 if (server_status != old_status) or (task_state != old_task_state):
119 LOG.info('State transition "%s" ==> "%s" after %d second wait',
120 '/'.join((old_status, str(old_task_state))),
121 '/'.join((server_status, str(task_state))),
122 time.time() - start_time)
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000123 if server_status == 'ERROR' and not ignore_error:
zhufl0ded98f2019-06-13 11:44:24 +0800124 raise lib_exc.DeleteErrorException(
125 "Server %s failed to delete and is in ERROR status" %
126 server_id)
ericxiett5f65bf52020-09-25 08:42:26 +0000127
ericxiettd0ef93e2019-12-16 08:55:05 +0000128 if server_status == 'SOFT_DELETED':
129 # Soft-deleted instances need to be forcibly deleted to
130 # prevent some test cases from failing.
131 LOG.debug("Automatically force-deleting soft-deleted server %s",
132 server_id)
ericxiett5f65bf52020-09-25 08:42:26 +0000133 try:
134 client.force_delete_server(server_id)
135 except lib_exc.NotFound:
136 # The instance may have been deleted so ignore
137 # NotFound exception
138 return
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000139
140 if int(time.time()) - start_time >= client.build_timeout:
guo yunxianebb15f22016-11-01 21:03:35 +0800141 raise lib_exc.TimeoutException
Matt Riedemannf748c112017-02-03 11:33:11 -0500142 old_status = server_status
143 old_task_state = task_state
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000144
145
Matt Riedemannc00f3262013-12-14 12:03:55 -0800146def wait_for_image_status(client, image_id, status):
147 """Waits for an image to reach a given status.
148
Ken'ichi Ohmichi5d410762015-05-22 01:10:03 +0000149 The client should have a show_image(image_id) method to get the image.
Matt Riedemannc00f3262013-12-14 12:03:55 -0800150 The client should also have build_interval and build_timeout attributes.
151 """
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300152 if isinstance(client, images_v1_client.ImagesClient):
153 # The 'check_image' method is used here because the show_image method
154 # returns image details plus the image itself which is very expensive.
155 # The 'check_image' method returns just image details.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700156 def _show_image_v1(image_id):
157 resp = client.check_image(image_id)
158 return common_image.get_image_meta_from_headers(resp)
159
160 show_image = _show_image_v1
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300161 else:
162 show_image = client.show_image
Matt Riedemannc00f3262013-12-14 12:03:55 -0800163
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300164 current_status = 'An unknown status'
165 start = int(time.time())
166 while int(time.time()) - start < client.build_timeout:
167 image = show_image(image_id)
168 # Compute image client returns response wrapped in 'image' element
Xiangfei Zhua8fd20a2016-07-26 21:28:12 -0700169 # which is not the case with Glance image client.
ghanshyam1756e0b2015-08-18 19:19:05 +0900170 if 'image' in image:
171 image = image['image']
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300172
173 current_status = image['status']
174 if current_status == status:
175 return
176 if current_status.lower() == 'killed':
177 raise exceptions.ImageKilledException(image_id=image_id,
178 status=status)
179 if current_status.lower() == 'error':
Matt Riedemannc00f3262013-12-14 12:03:55 -0800180 raise exceptions.AddImageException(image_id=image_id)
181
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300182 time.sleep(client.build_interval)
Matt Riedemannc00f3262013-12-14 12:03:55 -0800183
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300184 message = ('Image %(image_id)s failed to reach %(status)s state '
185 '(current state %(current_status)s) within the required '
186 'time (%(timeout)s s).' % {'image_id': image_id,
187 'status': status,
188 'current_status': current_status,
189 'timeout': client.build_timeout})
zhufl88c89b52016-07-01 18:09:05 +0800190 caller = test_utils.find_test_caller()
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300191 if caller:
192 message = '(%s) %s' % (caller, message)
guo yunxianebb15f22016-11-01 21:03:35 +0800193 raise lib_exc.TimeoutException(message)
Adam Gandelman00682612014-09-02 17:10:36 -0700194
195
Ghanshyam Mannb15b58e2021-04-29 19:45:29 -0500196def wait_for_image_tasks_status(client, image_id, status):
197 """Waits for an image tasks to reach a given status."""
198 pending_tasks = []
199 start = int(time.time())
200 while int(time.time()) - start < client.build_timeout:
201 tasks = client.show_image_tasks(image_id)['tasks']
202
203 pending_tasks = [task for task in tasks if task['status'] != status]
204 if not pending_tasks:
205 return tasks
206 time.sleep(client.build_interval)
207
208 message = ('Image %(image_id)s tasks: %(pending_tasks)s '
209 'failed to reach %(status)s state within the required '
210 'time (%(timeout)s s).' % {'image_id': image_id,
211 'pending_tasks': pending_tasks,
212 'status': status,
213 'timeout': client.build_timeout})
214 caller = test_utils.find_test_caller()
215 if caller:
216 message = '(%s) %s' % (caller, message)
217 raise lib_exc.TimeoutException(message)
218
219
Dan Smithef8e0542021-02-05 13:05:45 -0800220def wait_for_image_imported_to_stores(client, image_id, stores=None):
PranaliD491d63e2020-08-18 13:29:21 +0000221 """Waits for an image to be imported to all requested stores.
222
Dan Smithef8e0542021-02-05 13:05:45 -0800223 Short circuits to fail if the serer reports failure of any store.
224 If stores is None, just wait for status==active.
225
PranaliD491d63e2020-08-18 13:29:21 +0000226 The client should also have build_interval and build_timeout attributes.
227 """
228
Dan Smithef8e0542021-02-05 13:05:45 -0800229 exc_cls = lib_exc.TimeoutException
PranaliD491d63e2020-08-18 13:29:21 +0000230 start = int(time.time())
231 while int(time.time()) - start < client.build_timeout:
232 image = client.show_image(image_id)
Dan Smithef8e0542021-02-05 13:05:45 -0800233 if image['status'] == 'active' and (stores is None or
234 image['stores'] == stores):
PranaliD491d63e2020-08-18 13:29:21 +0000235 return
Dan Smithef8e0542021-02-05 13:05:45 -0800236 if image.get('os_glance_failed_import'):
237 exc_cls = lib_exc.OtherRestClientException
238 break
PranaliD491d63e2020-08-18 13:29:21 +0000239
240 time.sleep(client.build_interval)
241
zhufl414ffba2020-11-19 16:57:06 +0800242 message = ('Image %s failed to import on stores: %s' %
Dan Smithef8e0542021-02-05 13:05:45 -0800243 (image_id, str(image.get('os_glance_failed_import'))))
PranaliD491d63e2020-08-18 13:29:21 +0000244 caller = test_utils.find_test_caller()
245 if caller:
246 message = '(%s) %s' % (caller, message)
Dan Smithef8e0542021-02-05 13:05:45 -0800247 raise exc_cls(message)
PranaliD491d63e2020-08-18 13:29:21 +0000248
249
Ghanshyam Mann4346a822020-07-29 13:45:04 -0500250def wait_for_image_copied_to_stores(client, image_id):
251 """Waits for an image to be copied on all requested stores.
252
253 The client should also have build_interval and build_timeout attributes.
254 This return the list of stores where copy is failed.
255 """
256
257 start = int(time.time())
258 store_left = []
259 while int(time.time()) - start < client.build_timeout:
260 image = client.show_image(image_id)
261 store_left = image.get('os_glance_importing_to_stores')
262 # NOTE(danms): If os_glance_importing_to_stores is None, then
263 # we've raced with the startup of the task and should continue
264 # to wait.
265 if store_left is not None and not store_left:
266 return image['os_glance_failed_import']
267 if image['status'].lower() == 'killed':
268 raise exceptions.ImageKilledException(image_id=image_id,
269 status=image['status'])
270
271 time.sleep(client.build_interval)
272
zhufl414ffba2020-11-19 16:57:06 +0800273 message = ('Image %s failed to finish the copy operation '
274 'on stores: %s' % (image_id, str(store_left)))
Ghanshyam Mann4346a822020-07-29 13:45:04 -0500275 caller = test_utils.find_test_caller()
276 if caller:
277 message = '(%s) %s' % (caller, message)
278 raise lib_exc.TimeoutException(message)
279
280
Matt Riedemannb36186b2017-12-04 17:54:08 +0000281def wait_for_volume_resource_status(client, resource_id, status):
282 """Waits for a volume resource to reach a given status.
lkuchlan52d7b0d2016-11-07 20:53:19 +0200283
284 This function is a common function for volume, snapshot and backup
285 resources. The function extracts the name of the desired resource from
286 the client class name of the resource.
287 """
xing-yang41ed7152017-05-03 06:52:56 -0400288 resource_name = re.findall(
289 r'(volume|group-snapshot|snapshot|backup|group)',
290 client.resource_type)[-1].replace('-', '_')
lkuchlan52d7b0d2016-11-07 20:53:19 +0200291 show_resource = getattr(client, 'show_' + resource_name)
292 resource_status = show_resource(resource_id)[resource_name]['status']
Ken'ichi Ohmichib942be62015-07-08 08:16:12 +0000293 start = int(time.time())
294
Matt Riedemannb36186b2017-12-04 17:54:08 +0000295 while resource_status != status:
Ken'ichi Ohmichib942be62015-07-08 08:16:12 +0000296 time.sleep(client.build_interval)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200297 resource_status = show_resource(resource_id)[
298 '{}'.format(resource_name)]['status']
Matt Riedemannb36186b2017-12-04 17:54:08 +0000299 if resource_status == 'error' and resource_status != status:
lkuchlan52d7b0d2016-11-07 20:53:19 +0200300 raise exceptions.VolumeResourceBuildErrorException(
301 resource_name=resource_name, resource_id=resource_id)
302 if resource_name == 'volume' and resource_status == 'error_restoring':
303 raise exceptions.VolumeRestoreErrorException(volume_id=resource_id)
zhufl0ea2c012019-06-03 15:37:13 +0800304 if resource_status == 'error_extending' and resource_status != status:
305 raise exceptions.VolumeExtendErrorException(volume_id=resource_id)
Ken'ichi Ohmichib942be62015-07-08 08:16:12 +0000306
307 if int(time.time()) - start >= client.build_timeout:
lkuchlan52d7b0d2016-11-07 20:53:19 +0200308 message = ('%s %s failed to reach %s status (current %s) '
Ken'ichi Ohmichib942be62015-07-08 08:16:12 +0000309 'within the required time (%s s).' %
Matt Riedemannb36186b2017-12-04 17:54:08 +0000310 (resource_name, resource_id, status, resource_status,
Ken'ichi Ohmichib942be62015-07-08 08:16:12 +0000311 client.build_timeout))
guo yunxianebb15f22016-11-01 21:03:35 +0800312 raise lib_exc.TimeoutException(message)
zhufl019ad732017-08-28 13:51:22 +0800313 LOG.info('%s %s reached %s after waiting for %f seconds',
Matt Riedemannb36186b2017-12-04 17:54:08 +0000314 resource_name, resource_id, status, time.time() - start)
Ken'ichi Ohmichib942be62015-07-08 08:16:12 +0000315
316
Peter Penchev5c243a92020-09-06 02:26:03 +0300317def wait_for_volume_attachment_create(client, volume_id, server_id):
318 """Waits for a volume attachment to be created at a given volume."""
319 start = int(time.time())
320 while True:
321 attachments = client.show_volume(volume_id)['volume']['attachments']
322 found = [a for a in attachments if a['server_id'] == server_id]
323 if found:
324 LOG.info('Attachment %s created for volume %s to server %s after '
325 'waiting for %f seconds', found[0]['attachment_id'],
326 volume_id, server_id, time.time() - start)
327 return found[0]
328 time.sleep(client.build_interval)
329 if int(time.time()) - start >= client.build_timeout:
330 message = ('Failed to attach volume %s to server %s '
331 'within the required time (%s s).' %
332 (volume_id, server_id, client.build_timeout))
333 raise lib_exc.TimeoutException(message)
334
335
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000336def wait_for_volume_attachment_remove(client, volume_id, attachment_id):
337 """Waits for a volume attachment to be removed from a given volume."""
338 start = int(time.time())
339 attachments = client.show_volume(volume_id)['volume']['attachments']
340 while any(attachment_id == a['attachment_id'] for a in attachments):
341 time.sleep(client.build_interval)
342 if int(time.time()) - start >= client.build_timeout:
zhufl747300b2020-04-14 14:23:47 +0800343 message = ('Failed to remove attachment %s from volume %s '
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000344 'within the required time (%s s).' %
345 (attachment_id, volume_id, client.build_timeout))
346 raise lib_exc.TimeoutException(message)
347 attachments = client.show_volume(volume_id)['volume']['attachments']
348 LOG.info('Attachment %s removed from volume %s after waiting for %f '
349 'seconds', attachment_id, volume_id, time.time() - start)
350
351
Balazs Gibizer2e515fe2020-12-07 15:10:11 +0100352def wait_for_volume_attachment_remove_from_server(
353 client, server_id, volume_id):
354 """Waits for a volume to be removed from a given server.
355
356 This waiter checks the compute API if the volume attachment is removed.
357 """
358 start = int(time.time())
359 volumes = client.list_volume_attachments(server_id)['volumeAttachments']
360
361 while any(volume for volume in volumes if volume['volumeId'] == volume_id):
362 time.sleep(client.build_interval)
363
364 timed_out = int(time.time()) - start >= client.build_timeout
365 if timed_out:
366 message = ('Volume %s failed to detach from server %s within '
367 'the required time (%s s) from the compute API '
368 'perspective' %
369 (volume_id, server_id, client.build_timeout))
370 raise lib_exc.TimeoutException(message)
371
372 volumes = client.list_volume_attachments(server_id)[
373 'volumeAttachments']
374
375 return volumes
376
377
Lee Yarwoode5597402019-02-15 20:17:00 +0000378def wait_for_volume_migration(client, volume_id, new_host):
379 """Waits for a Volume to move to a new host."""
380 body = client.show_volume(volume_id)['volume']
381 host = body['os-vol-host-attr:host']
382 migration_status = body['migration_status']
383 start = int(time.time())
384
385 # new_host is hostname@backend while current_host is hostname@backend#type
386 while migration_status != 'success' or new_host not in host:
387 time.sleep(client.build_interval)
388 body = client.show_volume(volume_id)['volume']
389 host = body['os-vol-host-attr:host']
390 migration_status = body['migration_status']
391
392 if migration_status == 'error':
393 message = ('volume %s failed to migrate.' % (volume_id))
394 raise lib_exc.TempestException(message)
395
396 if int(time.time()) - start >= client.build_timeout:
397 message = ('Volume %s failed to migrate to %s (current %s) '
398 'within the required time (%s s).' %
399 (volume_id, new_host, host, client.build_timeout))
400 raise lib_exc.TimeoutException(message)
401
402
scottda61f68ac2016-06-07 12:07:55 -0600403def wait_for_volume_retype(client, volume_id, new_volume_type):
404 """Waits for a Volume to have a new volume type."""
405 body = client.show_volume(volume_id)['volume']
406 current_volume_type = body['volume_type']
407 start = int(time.time())
408
409 while current_volume_type != new_volume_type:
410 time.sleep(client.build_interval)
411 body = client.show_volume(volume_id)['volume']
412 current_volume_type = body['volume_type']
413
414 if int(time.time()) - start >= client.build_timeout:
415 message = ('Volume %s failed to reach %s volume type (current %s) '
416 'within the required time (%s s).' %
417 (volume_id, new_volume_type, current_volume_type,
418 client.build_timeout))
Matt Riedemann74eb3b52017-02-14 11:34:30 -0500419 raise lib_exc.TimeoutException(message)
scottda61f68ac2016-06-07 12:07:55 -0600420
421
lkuchlanec1ba4f2016-09-06 10:28:18 +0300422def wait_for_qos_operations(client, qos_id, operation, args=None):
423 """Waits for a qos operations to be completed.
424
425 NOTE : operation value is required for wait_for_qos_operations()
426 operation = 'qos-key' / 'disassociate' / 'disassociate-all'
427 args = keys[] when operation = 'qos-key'
428 args = volume-type-id disassociated when operation = 'disassociate'
429 args = None when operation = 'disassociate-all'
430 """
431 start_time = int(time.time())
432 while True:
433 if operation == 'qos-key-unset':
434 body = client.show_qos(qos_id)['qos_specs']
435 if not any(key in body['specs'] for key in args):
436 return
437 elif operation == 'disassociate':
438 body = client.show_association_qos(qos_id)['qos_associations']
439 if not any(args in body[i]['id'] for i in range(0, len(body))):
440 return
441 elif operation == 'disassociate-all':
442 body = client.show_association_qos(qos_id)['qos_associations']
443 if not body:
444 return
445 else:
446 msg = (" operation value is either not defined or incorrect.")
447 raise lib_exc.UnprocessableEntity(msg)
448
449 if int(time.time()) - start_time >= client.build_timeout:
guo yunxianebb15f22016-11-01 21:03:35 +0800450 raise lib_exc.TimeoutException
lkuchlanec1ba4f2016-09-06 10:28:18 +0300451 time.sleep(client.build_interval)
zhufl7b638332016-11-14 10:23:30 +0800452
453
Matt Riedemann2ea48f02017-04-03 11:36:19 -0400454def wait_for_interface_status(client, server_id, port_id, status):
zhufl7b638332016-11-14 10:23:30 +0800455 """Waits for an interface to reach a given status."""
Matt Riedemann2ea48f02017-04-03 11:36:19 -0400456 body = (client.show_interface(server_id, port_id)
zhufl7b638332016-11-14 10:23:30 +0800457 ['interfaceAttachment'])
458 interface_status = body['port_state']
459 start = int(time.time())
460
461 while(interface_status != status):
462 time.sleep(client.build_interval)
Matt Riedemann2ea48f02017-04-03 11:36:19 -0400463 body = (client.show_interface(server_id, port_id)
zhufl7b638332016-11-14 10:23:30 +0800464 ['interfaceAttachment'])
465 interface_status = body['port_state']
466
467 timed_out = int(time.time()) - start >= client.build_timeout
468
469 if interface_status != status and timed_out:
470 message = ('Interface %s failed to reach %s status '
471 '(current %s) within the required time (%s s).' %
472 (port_id, status, interface_status,
473 client.build_timeout))
474 raise lib_exc.TimeoutException(message)
475
476 return body
Artom Lifshitz3306d422018-03-22 12:20:54 -0400477
478
479def wait_for_interface_detach(client, server_id, port_id):
480 """Waits for an interface to be detached from a server."""
481 body = client.list_interfaces(server_id)['interfaceAttachments']
482 ports = [iface['port_id'] for iface in body]
483 start = int(time.time())
484
485 while port_id in ports:
486 time.sleep(client.build_interval)
487 body = client.list_interfaces(server_id)['interfaceAttachments']
488 ports = [iface['port_id'] for iface in body]
489 if port_id not in ports:
490 return body
491
492 timed_out = int(time.time()) - start >= client.build_timeout
493 if timed_out:
494 message = ('Interface %s failed to detach from server %s within '
495 'the required time (%s s)' % (port_id, server_id,
496 client.build_timeout))
497 raise lib_exc.TimeoutException(message)
Slawek Kaplonskie3405ba2020-11-09 17:24:13 +0100498
499
500def wait_for_guest_os_boot(client, server_id):
501 start_time = int(time.time())
502 while True:
503 console_output = client.get_console_output(server_id)['output']
504 for line in console_output.split('\n'):
505 if 'login:' in line.lower():
506 return
507 if int(time.time()) - start_time >= client.build_timeout:
508 LOG.info("Guest OS on server %s probably isn't ready or its "
509 "console log can't be parsed properly. If guest OS "
510 "isn't ready, that may cause problems with SSH to "
511 "the server.",
512 server_id)
513 return
514 time.sleep(client.build_interval)