blob: 8e6b9fbdac392925b7acb49a733eb5f1d539743a [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
13
14import time
15
16from tempest import config
17from tempest import exceptions
18from tempest.openstack.common import log as logging
19
Sean Dague86bd8422013-12-20 09:56:44 -050020CONF = config.CONF
Attila Fazekas0abbc952013-07-01 19:19:42 +020021LOG = logging.getLogger(__name__)
22
23
24# NOTE(afazekas): This function needs to know a token and a subject.
Ken'ichi Ohmichi39437e22013-10-06 00:21:38 +090025def wait_for_server_status(client, server_id, status, ready_wait=True,
Zhi Kun Liue5401762013-09-11 20:45:48 +080026 extra_timeout=0, raise_on_error=True):
Attila Fazekas0abbc952013-07-01 19:19:42 +020027 """Waits for a server to reach a given status."""
28
29 def _get_task_state(body):
ivan-zhu2ca89b32013-08-07 22:37:32 +080030 if client.service == CONF.compute.catalog_v3_type:
31 task_state = body.get("os-extended-status:task_state", None)
32 else:
33 task_state = body.get('OS-EXT-STS:task_state', None)
Attila Fazekas0abbc952013-07-01 19:19:42 +020034 return task_state
35
36 # NOTE(afazekas): UNKNOWN status possible on ERROR
37 # or in a very early stage.
38 resp, body = client.get_server(server_id)
39 old_status = server_status = body['status']
40 old_task_state = task_state = _get_task_state(body)
41 start_time = int(time.time())
Ken'ichi Ohmichi39437e22013-10-06 00:21:38 +090042 timeout = client.build_timeout + extra_timeout
Attila Fazekas0abbc952013-07-01 19:19:42 +020043 while True:
44 # NOTE(afazekas): Now the BUILD status only reached
Shane Wang111f86c2014-02-20 16:40:22 +080045 # between the UNKNOWN->ACTIVE transition.
Attila Fazekas0abbc952013-07-01 19:19:42 +020046 # TODO(afazekas): enumerate and validate the stable status set
47 if status == 'BUILD' and server_status != 'UNKNOWN':
48 return
49 if server_status == status:
50 if ready_wait:
51 if status == 'BUILD':
52 return
53 # NOTE(afazekas): The instance is in "ready for action state"
54 # when no task in progress
55 # NOTE(afazekas): Converted to string bacuse of the XML
56 # responses
57 if str(task_state) == "None":
58 # 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)
65 resp, body = client.get_server(server_id)
66 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 Fazekas0abbc952013-07-01 19:19:42 +020074 raise exceptions.BuildErrorException(server_id=server_id)
75
Ken'ichi Ohmichi39437e22013-10-06 00:21:38 +090076 timed_out = int(time.time()) - start_time >= timeout
Attila Fazekas0abbc952013-07-01 19:19:42 +020077
78 if timed_out:
Matt Riedemann629fa7c2013-12-11 18:20:56 -080079 expected_task_state = 'None' if ready_wait else 'n/a'
80 message = ('Server %(server_id)s failed to reach %(status)s '
81 'status and task state "%(expected_task_state)s" '
82 'within the required time (%(timeout)s s).' %
83 {'server_id': server_id,
84 'status': status,
85 'expected_task_state': expected_task_state,
86 'timeout': timeout})
Attila Fazekas0abbc952013-07-01 19:19:42 +020087 message += ' Current status: %s.' % server_status
Matt Riedemann629fa7c2013-12-11 18:20:56 -080088 message += ' Current task state: %s.' % task_state
Attila Fazekas0abbc952013-07-01 19:19:42 +020089 raise exceptions.TimeoutException(message)
90 old_status = server_status
91 old_task_state = task_state
Matt Riedemannc00f3262013-12-14 12:03:55 -080092
93
94def wait_for_image_status(client, image_id, status):
95 """Waits for an image to reach a given status.
96
97 The client should have a get_image(image_id) method to get the image.
98 The client should also have build_interval and build_timeout attributes.
99 """
100 resp, image = client.get_image(image_id)
101 start = int(time.time())
102
103 while image['status'] != status:
104 time.sleep(client.build_interval)
105 resp, image = client.get_image(image_id)
106 if image['status'] == 'ERROR':
107 raise exceptions.AddImageException(image_id=image_id)
108
109 # check the status again to avoid a false negative where we hit
110 # the timeout at the same time that the image reached the expected
111 # status
112 if image['status'] == status:
113 return
114
115 if int(time.time()) - start >= client.build_timeout:
116 message = ('Image %(image_id)s failed to reach %(status)s '
117 'status within the required time (%(timeout)s s).' %
118 {'image_id': image_id,
119 'status': status,
120 'timeout': client.build_timeout})
121 message += ' Current status: %s.' % image['status']
122 raise exceptions.TimeoutException(message)