blob: 6d0f7d2bbd512e859fa5c72e98633c9e412a983e [file] [log] [blame]
Anton Arefiev44f678c2016-03-17 12:11:30 +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 os
15import time
16
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020017import tempest
Anton Arefiev44f678c2016-03-17 12:11:30 +020018from tempest import config
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020019from tempest.lib.common.api_version_utils import LATEST_MICROVERSION
Anton Arefiev44f678c2016-03-17 12:11:30 +020020
21from ironic_inspector.test.inspector_tempest_plugin import exceptions
22from ironic_inspector.test.inspector_tempest_plugin.services import \
23 introspection_client
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020024from ironic_tempest_plugin.tests.api.admin.api_microversion_fixture import \
25 APIMicroversionFixture as IronicMicroversionFixture
26from ironic_tempest_plugin.tests.scenario.baremetal_manager import \
27 BaremetalProvisionStates
Anton Arefiev44f678c2016-03-17 12:11:30 +020028from ironic_tempest_plugin.tests.scenario.baremetal_manager import \
29 BaremetalScenarioTest
30
31
32CONF = config.CONF
33
34
35class InspectorScenarioTest(BaremetalScenarioTest):
36 """Provide harness to do Inspector scenario tests."""
37
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020038 wait_provisioning_state_interval = 15
39
Anton Arefiev44f678c2016-03-17 12:11:30 +020040 credentials = ['primary', 'admin']
41
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020042 ironic_api_version = LATEST_MICROVERSION
43
Anton Arefiev44f678c2016-03-17 12:11:30 +020044 @classmethod
45 def setup_clients(cls):
46 super(InspectorScenarioTest, cls).setup_clients()
47 inspector_manager = introspection_client.Manager()
48 cls.introspection_client = inspector_manager.introspection_client
49
50 def setUp(self):
51 super(InspectorScenarioTest, self).setUp()
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020052 # we rely on the 'available' provision_state; using latest
53 # microversion
54 self.useFixture(IronicMicroversionFixture(self.ironic_api_version))
Anton Arefiev44f678c2016-03-17 12:11:30 +020055 self.flavor = self.baremetal_flavor()
Dmitry Tantsur290c96b2016-07-01 14:22:51 +020056 self.node_ids = {node['uuid'] for node in
57 self.node_filter(filter=lambda node:
58 node['provision_state'] ==
59 BaremetalProvisionStates.AVAILABLE)}
60 self.rule_purge()
Anton Arefiev44f678c2016-03-17 12:11:30 +020061
62 def item_filter(self, list_method, show_method,
63 filter=lambda item: True, items=None):
64 if items is None:
65 items = [show_method(item['uuid']) for item in
66 list_method()]
67 return [item for item in items if filter(item)]
68
69 def node_list(self):
70 return self.baremetal_client.list_nodes()[1]['nodes']
71
72 def node_update(self, uuid, patch):
73 return self.baremetal_client.update_node(uuid, **patch)
74
75 def node_show(self, uuid):
76 return self.baremetal_client.show_node(uuid)[1]
77
78 def node_filter(self, filter=lambda node: True, nodes=None):
79 return self.item_filter(self.node_list, self.node_show,
80 filter=filter, items=nodes)
81
82 def hypervisor_stats(self):
83 return (self.admin_manager.hypervisor_client.
84 show_hypervisor_statistics())
85
86 def server_show(self, uuid):
87 self.servers_client.show_server(uuid)
88
89 def rule_purge(self):
90 self.introspection_client.purge_rules()
91
92 def rule_import(self, rule_path):
93 self.introspection_client.import_rule(rule_path)
94
95 def introspection_status(self, uuid):
96 return self.introspection_client.get_status(uuid)[1]
97
98 def introspection_data(self, uuid):
99 return self.introspection_client.get_data(uuid)[1]
100
101 def baremetal_flavor(self):
102 flavor_id = CONF.compute.flavor_ref
103 flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
104 flavor['properties'] = self.flavors_client.list_flavor_extra_specs(
105 flavor_id)['extra_specs']
106 return flavor
107
108 def get_rule_path(self, rule_file):
109 base_path = os.path.split(
110 os.path.dirname(os.path.abspath(__file__)))[0]
111 base_path = os.path.split(base_path)[0]
112 return os.path.join(base_path, "inspector_tempest_plugin",
113 "rules", rule_file)
114
Anton Arefiev84a09c62016-07-19 19:35:18 +0300115 def boot_instance(self):
116 return super(InspectorScenarioTest, self).boot_instance()
117
118 def terminate_instance(self, instance):
119 return super(InspectorScenarioTest, self).terminate_instance(instance)
120
Anton Arefiev44f678c2016-03-17 12:11:30 +0200121 # TODO(aarefiev): switch to call_until_true
122 def wait_for_introspection_finished(self, node_ids):
123 """Waits for introspection of baremetal nodes to finish.
124
125 """
126 start = int(time.time())
127 not_introspected = {node_id for node_id in node_ids}
128
129 while not_introspected:
130 time.sleep(CONF.baremetal_introspection.introspection_sleep)
131 for node_id in node_ids:
132 status = self.introspection_status(node_id)
133 if status['finished']:
134 if status['error']:
135 message = ('Node %(node_id)s introspection failed '
136 'with %(error)s.' %
137 {'node_id': node_id,
138 'error': status['error']})
139 raise exceptions.IntrospectionFailed(message)
140 not_introspected = not_introspected - {node_id}
141
142 if (int(time.time()) - start >=
143 CONF.baremetal_introspection.introspection_timeout):
144 message = ('Introspection timed out for nodes: %s' %
145 not_introspected)
146 raise exceptions.IntrospectionTimeout(message)
147
148 def wait_for_nova_aware_of_bvms(self):
149 start = int(time.time())
150 while True:
151 time.sleep(CONF.baremetal_introspection.hypervisor_update_sleep)
152 stats = self.hypervisor_stats()
153 expected_cpus = self.baremetal_flavor()['vcpus']
154 if int(stats['hypervisor_statistics']['vcpus']) >= expected_cpus:
155 break
156
157 timeout = CONF.baremetal_introspection.hypervisor_update_timeout
158 if (int(time.time()) - start >= timeout):
159 message = (
160 'Timeout while waiting for nova hypervisor-stats: '
161 '%(stats)s required time (%(timeout)s s).' %
162 {'stats': stats,
163 'timeout': timeout})
164 raise exceptions.HypervisorUpdateTimeout(message)
Dmitry Tantsur290c96b2016-07-01 14:22:51 +0200165
166 def node_cleanup(self, node_id):
167 if (self.node_show(node_id)['provision_state'] ==
168 BaremetalProvisionStates.AVAILABLE):
169 return
170 try:
171 self.baremetal_client.set_node_provision_state(node_id, 'provide')
172 except tempest.lib.exceptions.RestClientException:
173 # maybe node already cleaning or available
174 pass
175
176 self.wait_provisioning_state(
177 node_id, [BaremetalProvisionStates.AVAILABLE,
178 BaremetalProvisionStates.NOSTATE],
179 timeout=CONF.baremetal.unprovision_timeout,
180 interval=self.wait_provisioning_state_interval)
181
182 def introspect_node(self, node_id):
183 # in case there are properties remove those
184 patch = {('properties/%s' % key): None for key in
185 self.node_show(node_id)['properties']}
186 # reset any previous rule result
187 patch['extra/rule_success'] = None
188 self.node_update(node_id, patch)
189
190 self.baremetal_client.set_node_provision_state(node_id, 'manage')
191 self.baremetal_client.set_node_provision_state(node_id, 'inspect')
192 self.addCleanup(self.node_cleanup, node_id)