blob: d4a5e6af4ca1f2962027fbe67eb1788f23c063af [file] [log] [blame]
Yuiko Takadab6527002015-12-07 11:49:12 +09001# All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Julia Kreger32737082020-04-16 16:55:28 -070015from oslo_log import log
Vladyslav Drok0cad0442016-12-14 12:48:20 +020016from tempest import config
wangxiyuandbd33dc2017-02-10 09:40:50 +080017from tempest.lib.common.utils import test_utils
Lenny Verkhovsky88625042016-03-08 17:44:00 +020018from tempest.lib import exceptions as lib_exc
Yuiko Takadab6527002015-12-07 11:49:12 +090019
Vladyslav Drok0cad0442016-12-14 12:48:20 +020020from ironic_tempest_plugin.common import utils
21
Julia Kreger32737082020-04-16 16:55:28 -070022LOG = log.getLogger(__name__)
23
Vladyslav Drok0cad0442016-12-14 12:48:20 +020024CONF = config.CONF
25
26
27def _determine_and_check_timeout_interval(timeout, default_timeout,
28 interval, default_interval):
29 if timeout is None:
30 timeout = default_timeout
31 if interval is None:
32 interval = default_interval
Takashi Kajinami6bddaab2022-05-10 00:58:56 +090033 if (not isinstance(timeout, int)
34 or not isinstance(interval, int)
Riccardo Pittau441c5062020-03-30 15:06:28 +020035 or timeout < 0 or interval < 0):
Vladyslav Drok0cad0442016-12-14 12:48:20 +020036 raise AssertionError(
37 'timeout and interval should be >= 0 or None, current values are: '
38 '%(timeout)s, %(interval)s respectively. If timeout and/or '
39 'interval are None, the default_timeout and default_interval are '
40 'used, and they should be integers >= 0, current values are: '
41 '%(default_timeout)s, %(default_interval)s respectively.' % dict(
42 timeout=timeout, interval=interval,
43 default_timeout=default_timeout,
44 default_interval=default_interval)
45 )
46 return timeout, interval
47
Yuiko Takadab6527002015-12-07 11:49:12 +090048
Vladyslav Drok0ac08c82016-12-13 19:51:20 +020049def wait_for_bm_node_status(client, node_id, attr, status, timeout=None,
Dmitry Tantsur4e2116d2019-08-27 17:01:58 +020050 interval=None, abort_on_error_state=False):
Yuiko Takadab6527002015-12-07 11:49:12 +090051 """Waits for a baremetal node attribute to reach given status.
52
Vladyslav Drok0ac08c82016-12-13 19:51:20 +020053 :param client: an instance of tempest plugin BaremetalClient.
54 :param node_id: identifier of the node.
55 :param attr: node's API-visible attribute to check status of.
Vladyslav Drok0cad0442016-12-14 12:48:20 +020056 :param status: desired status. Can be a list of statuses.
Vladyslav Drok0ac08c82016-12-13 19:51:20 +020057 :param timeout: the timeout after which the check is considered as failed.
58 Defaults to client.build_timeout.
59 :param interval: an interval between show_node calls for status check.
60 Defaults to client.build_interval.
Dmitry Tantsur4e2116d2019-08-27 17:01:58 +020061 :param abort_on_error_state: whether to abort waiting if the node reaches
62 an error state.
Vladyslav Drok0ac08c82016-12-13 19:51:20 +020063
64 The client should have a show_node(node_id) method to get the node.
Yuiko Takadab6527002015-12-07 11:49:12 +090065 """
Vladyslav Drok0cad0442016-12-14 12:48:20 +020066 timeout, interval = _determine_and_check_timeout_interval(
67 timeout, client.build_timeout, interval, client.build_interval)
Vladyslav Drok0ac08c82016-12-13 19:51:20 +020068
Vladyslav Drok0cad0442016-12-14 12:48:20 +020069 if not isinstance(status, list):
70 status = [status]
Yuiko Takadab6527002015-12-07 11:49:12 +090071
Vladyslav Drok0cad0442016-12-14 12:48:20 +020072 def is_attr_in_status():
73 node = utils.get_node(client, node_id=node_id)
74 if node[attr] in status:
75 return True
Vasyl Saienko342e11c2025-04-11 13:07:20 +000076 elif not node['provision_state']:
77 return False
Dmitry Tantsur4e2116d2019-08-27 17:01:58 +020078 elif (abort_on_error_state
Julia Kreger982d1772022-03-30 16:40:44 -070079 and (node['provision_state'].endswith(' failed')
80 or node['provision_state'] == 'error')):
Julia Kreger32737082020-04-16 16:55:28 -070081 msg = ('Node %(node)s reached failure state %(state)s while '
82 'waiting for %(attr)s=%(expected)s. '
83 'Error: %(error)s' %
84 {'node': node_id, 'state': node['provision_state'],
85 'attr': attr, 'expected': status,
86 'error': node.get('last_error')})
87 LOG.debug(msg)
88 raise lib_exc.TempestException(msg)
Vladyslav Drok0cad0442016-12-14 12:48:20 +020089 return False
Yuiko Takadab6527002015-12-07 11:49:12 +090090
Vladyslav Drok0cad0442016-12-14 12:48:20 +020091 if not test_utils.call_until_true(is_attr_in_status, timeout,
92 interval):
93 message = ('Node %(node_id)s failed to reach %(attr)s=%(status)s '
94 'within the required time (%(timeout)s s).' %
95 {'node_id': node_id,
96 'attr': attr,
97 'status': status,
98 'timeout': timeout})
99 caller = test_utils.find_test_caller()
100 if caller:
101 message = '(%s) %s' % (caller, message)
Julia Kreger32737082020-04-16 16:55:28 -0700102 LOG.debug(message)
Vladyslav Drok0cad0442016-12-14 12:48:20 +0200103 raise lib_exc.TimeoutException(message)
Vladyslav Drok0ac08c82016-12-13 19:51:20 +0200104
Vladyslav Drok0cad0442016-12-14 12:48:20 +0200105
106def wait_node_instance_association(client, instance_uuid, timeout=None,
107 interval=None):
108 """Waits for a node to be associated with instance_id.
109
110 :param client: an instance of tempest plugin BaremetalClient.
111 :param instance_uuid: UUID of the instance.
112 :param timeout: the timeout after which the check is considered as failed.
113 Defaults to CONF.baremetal.association_timeout.
114 :param interval: an interval between show_node calls for status check.
115 Defaults to client.build_interval.
116 """
117 timeout, interval = _determine_and_check_timeout_interval(
118 timeout, CONF.baremetal.association_timeout,
119 interval, client.build_interval)
120
121 def is_some_node_associated():
122 node = utils.get_node(client, instance_uuid=instance_uuid)
123 return node is not None
124
125 if not test_utils.call_until_true(is_some_node_associated, timeout,
126 interval):
Vladyslav Drok401fd462017-03-13 16:33:52 +0000127 msg = ('Timed out waiting to get Ironic node by instance UUID '
128 '%(instance_uuid)s within the required time (%(timeout)s s).'
129 % {'instance_uuid': instance_uuid, 'timeout': timeout})
Vladyslav Drok0cad0442016-12-14 12:48:20 +0200130 raise lib_exc.TimeoutException(msg)
Dmitry Tantsur47ff4892019-02-08 17:24:46 +0100131
132
133def wait_for_allocation(client, allocation_ident, timeout=15, interval=1,
134 expect_error=False):
135 """Wait for the allocation to become active.
136
137 :param client: an instance of tempest plugin BaremetalClient.
138 :param allocation_ident: UUID or name of the allocation.
139 :param timeout: the timeout after which the allocation is considered as
140 failed. Defaults to 15 seconds.
141 :param interval: an interval between show_allocation calls.
142 Defaults to 1 second.
143 :param expect_error: if True, return successfully even in case of an error.
144 """
145 result = [None] # a mutable object to modify in the closure
146
147 def check():
148 result[0] = client.show_allocation(allocation_ident)
149 allocation = result[0][1]
150
151 if allocation['state'] == 'error' and not expect_error:
152 raise lib_exc.TempestException(
153 "Allocation %(ident)s failed: %(error)s" %
154 {'ident': allocation_ident,
155 'error': allocation.get('last_error')})
156 else:
157 return allocation['state'] != 'allocating'
158
159 if not test_utils.call_until_true(check, timeout, interval):
160 msg = ('Timed out waiting for the allocation %s to become active' %
161 allocation_ident)
162 raise lib_exc.TimeoutException(msg)
163
164 return result[0]
Julia Kreger982d1772022-03-30 16:40:44 -0700165
166
167def wait_node_value_in_field(client, node_id, field, value,
168 raise_if_insufficent_access=True,
169 timeout=None, interval=None):
170 """Waits for a node to have a field value appear.
171
172 :param client: an instance of tempest plugin BaremetalClient.
173 :param node_id: the UUID of the node
174 :param field: the field in the node object to examine
175 :param value: the value/key with-in the field to look for.
176 :param timeout: the timeout after which the check is considered as failed.
177 :param interval: an interval between show_node calls for status check.
178 """
179
180 def is_field_updated():
181 node = utils.get_node(client, node_id=node_id)
182 field_value = node[field]
183 if raise_if_insufficent_access and '** Redacted' in field_value:
184 msg = ('Unable to see contents of redacted field '
185 'indicating insufficent access to execute this test.')
186 raise lib_exc.InsufficientAPIAccess(msg)
187 return value in field_value
188
189 if not test_utils.call_until_true(is_field_updated, timeout,
190 interval):
191 msg = ('Timed out waiting to get Ironic node by node_id '
192 '%(node_id)s within the required time (%(timeout)s s). '
193 'Field value %(value) did not appear in field %(field)s.'
194 % {'node_id': node_id, 'timeout': timeout,
195 'field': field, 'value': value})
196 raise lib_exc.TimeoutException(msg)