summaryrefslogtreecommitdiff
path: root/watcher_tempest_plugin/tests/scenario/test_execute_actuator.py
diff options
context:
space:
mode:
Diffstat (limited to 'watcher_tempest_plugin/tests/scenario/test_execute_actuator.py')
-rw-r--r--watcher_tempest_plugin/tests/scenario/test_execute_actuator.py340
1 files changed, 0 insertions, 340 deletions
diff --git a/watcher_tempest_plugin/tests/scenario/test_execute_actuator.py b/watcher_tempest_plugin/tests/scenario/test_execute_actuator.py
deleted file mode 100644
index fd4a18d..0000000
--- a/watcher_tempest_plugin/tests/scenario/test_execute_actuator.py
+++ /dev/null
@@ -1,340 +0,0 @@
1# -*- encoding: utf-8 -*-
2# Copyright (c) 2016 b<>com
3#
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14# implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18from __future__ import unicode_literals
19
20import collections
21import functools
22
23from tempest import config
24from tempest.lib.common.utils import test_utils
25
26from watcher_tempest_plugin.tests.scenario import base
27
28CONF = config.CONF
29
30
31class TestExecuteActionsViaActuator(base.BaseInfraOptimScenarioTest):
32
33 scenarios = [
34 ("nop", {"actions": [
35 {"action_type": "nop",
36 "input_parameters": {
37 "message": "hello World"}}]}),
38 ("sleep", {"actions": [
39 {"action_type": "sleep",
40 "input_parameters": {
41 "duration": 1.0}}]}),
42 ("change_nova_service_state", {"actions": [
43 {"action_type": "change_nova_service_state",
44 "input_parameters": {
45 "state": "enabled"},
46 "filling_function":
47 "_prerequisite_param_for_"
48 "change_nova_service_state_action"}]}),
49 ("resize", {"actions": [
50 {"action_type": "resize",
51 "filling_function": "_prerequisite_param_for_resize_action"}]}),
52 ("migrate", {"actions": [
53 {"action_type": "migrate",
54 "input_parameters": {
55 "migration_type": "live"},
56 "filling_function": "_prerequisite_param_for_migrate_action"},
57 {"action_type": "migrate",
58 "filling_function": "_prerequisite_param_for_migrate_action"}]})
59 ]
60
61 @classmethod
62 def resource_setup(cls):
63 super(TestExecuteActionsViaActuator, cls).resource_setup()
64 if CONF.compute.min_compute_nodes < 2:
65 raise cls.skipException(
66 "Less than 2 compute nodes, skipping multinode tests.")
67 if not CONF.compute_feature_enabled.live_migration:
68 raise cls.skipException("Live migration is not enabled")
69
70 cls.initial_compute_nodes_setup = cls.get_compute_nodes_setup()
71 enabled_compute_nodes = [cn for cn in cls.initial_compute_nodes_setup
72 if cn.get('status') == 'enabled']
73
74 cls.wait_for_compute_node_setup()
75
76 if len(enabled_compute_nodes) < 2:
77 raise cls.skipException(
78 "Less than 2 compute nodes are enabled, "
79 "skipping multinode tests.")
80
81 @classmethod
82 def get_compute_nodes_setup(cls):
83 services_client = cls.mgr.services_client
84 available_services = services_client.list_services()['services']
85
86 return [srv for srv in available_services
87 if srv.get('binary') == 'nova-compute']
88
89 @classmethod
90 def wait_for_compute_node_setup(cls):
91
92 def _are_compute_nodes_setup():
93 try:
94 hypervisors_client = cls.mgr.hypervisor_client
95 hypervisors = hypervisors_client.list_hypervisors(
96 detail=True)['hypervisors']
97 available_hypervisors = set(
98 hyp['hypervisor_hostname'] for hyp in hypervisors)
99 available_services = set(
100 service['host']
101 for service in cls.get_compute_nodes_setup())
102
103 return (
104 available_hypervisors == available_services and
105 len(hypervisors) >= 2)
106 except Exception:
107 return False
108
109 assert test_utils.call_until_true(
110 func=_are_compute_nodes_setup,
111 duration=600,
112 sleep_for=2
113 )
114
115 @classmethod
116 def rollback_compute_nodes_status(cls):
117 current_compute_nodes_setup = cls.get_compute_nodes_setup()
118 for cn_setup in current_compute_nodes_setup:
119 cn_hostname = cn_setup.get('host')
120 matching_cns = [
121 cns for cns in cls.initial_compute_nodes_setup
122 if cns.get('host') == cn_hostname
123 ]
124 initial_cn_setup = matching_cns[0] # Should return a single result
125 if cn_setup.get('status') != initial_cn_setup.get('status'):
126 if initial_cn_setup.get('status') == 'enabled':
127 rollback_func = cls.mgr.services_client.enable_service
128 else:
129 rollback_func = cls.mgr.services_client.disable_service
130 rollback_func(binary='nova-compute', host=cn_hostname)
131
132 def _create_one_instance_per_host(self):
133 """Create 1 instance per compute node
134
135 This goes up to the min_compute_nodes threshold so that things don't
136 get crazy if you have 1000 compute nodes but set min to 3.
137 """
138 host_client = self.mgr.hosts_client
139 all_hosts = host_client.list_hosts()['hosts']
140 compute_nodes = [x for x in all_hosts if x['service'] == 'compute']
141
142 created_servers = []
143 for _ in compute_nodes[:CONF.compute.min_compute_nodes]:
144 # by getting to active state here, this means this has
145 # landed on the host in question.
146 created_servers.append(
147 self.create_server(image_id=CONF.compute.image_ref,
148 wait_until='ACTIVE',
149 clients=self.mgr))
150
151 return created_servers
152
153 def _get_flavors(self):
154 return self.mgr.flavors_client.list_flavors()['flavors']
155
156 def _prerequisite_param_for_migrate_action(self):
157 created_instances = self._create_one_instance_per_host()
158 instance = created_instances[0]
159 source_node = created_instances[0]["OS-EXT-SRV-ATTR:host"]
160 destination_node = created_instances[-1]["OS-EXT-SRV-ATTR:host"]
161
162 parameters = {
163 "resource_id": instance['id'],
164 "migration_type": "live",
165 "source_node": source_node,
166 "destination_node": destination_node
167 }
168
169 return parameters
170
171 def _prerequisite_param_for_resize_action(self):
172 created_instances = self._create_one_instance_per_host()
173 instance = created_instances[0]
174 current_flavor_id = instance['flavor']['id']
175
176 flavors = self._get_flavors()
177 new_flavors = [f for f in flavors if f['id'] != current_flavor_id]
178 new_flavor = new_flavors[0]
179
180 parameters = {
181 "resource_id": instance['id'],
182 "flavor": new_flavor['name']
183 }
184
185 return parameters
186
187 def _prerequisite_param_for_change_nova_service_state_action(self):
188 enabled_compute_nodes = [cn for cn in
189 self.initial_compute_nodes_setup
190 if cn.get('status') == 'enabled']
191 enabled_compute_node = enabled_compute_nodes[0]
192
193 parameters = {
194 "resource_id": enabled_compute_node['host'],
195 "state": "enabled"
196 }
197
198 return parameters
199
200 def _fill_actions(self, actions):
201 for action in actions:
202 filling_function_name = action.pop('filling_function', None)
203
204 if filling_function_name is not None:
205 filling_function = getattr(self, filling_function_name, None)
206
207 if filling_function is not None:
208 parameters = filling_function()
209
210 resource_id = parameters.pop('resource_id', None)
211
212 if resource_id is not None:
213 action['resource_id'] = resource_id
214
215 input_parameters = action.get('input_parameters', None)
216
217 if input_parameters is not None:
218 parameters.update(input_parameters)
219 input_parameters.update(parameters)
220 else:
221 action['input_parameters'] = parameters
222
223 def _execute_actions(self, actions):
224 self.wait_for_all_action_plans_to_finish()
225
226 _, goal = self.client.show_goal("unclassified")
227 _, strategy = self.client.show_strategy("actuator")
228 _, audit_template = self.create_audit_template(
229 goal['uuid'], strategy=strategy['uuid'])
230 _, audit = self.create_audit(
231 audit_template['uuid'], parameters={"actions": actions})
232
233 self.assertTrue(test_utils.call_until_true(
234 func=functools.partial(self.has_audit_succeeded, audit['uuid']),
235 duration=30,
236 sleep_for=.5
237 ))
238 _, action_plans = self.client.list_action_plans(
239 audit_uuid=audit['uuid'])
240 action_plan = action_plans['action_plans'][0]
241
242 _, action_plan = self.client.show_action_plan(action_plan['uuid'])
243
244 # Execute the action plan
245 _, updated_ap = self.client.start_action_plan(action_plan['uuid'])
246
247 self.assertTrue(test_utils.call_until_true(
248 func=functools.partial(
249 self.has_action_plan_finished, action_plan['uuid']),
250 duration=300,
251 sleep_for=1
252 ))
253 _, finished_ap = self.client.show_action_plan(action_plan['uuid'])
254 _, action_list = self.client.list_actions(
255 action_plan_uuid=finished_ap["uuid"])
256
257 self.assertIn(updated_ap['state'], ('PENDING', 'ONGOING'))
258 self.assertIn(finished_ap['state'], ('SUCCEEDED', 'SUPERSEDED'))
259
260 expected_action_counter = collections.Counter(
261 act['action_type'] for act in actions)
262 action_counter = collections.Counter(
263 act['action_type'] for act in action_list['actions'])
264
265 self.assertEqual(expected_action_counter, action_counter)
266
267 def test_execute_nop(self):
268 self.addCleanup(self.rollback_compute_nodes_status)
269
270 actions = [{
271 "action_type": "nop",
272 "input_parameters": {"message": "hello World"}}]
273 self._execute_actions(actions)
274
275 def test_execute_sleep(self):
276 self.addCleanup(self.rollback_compute_nodes_status)
277
278 actions = [
279 {"action_type": "sleep",
280 "input_parameters": {"duration": 1.0}}
281 ]
282 self._execute_actions(actions)
283
284 def test_execute_change_nova_service_state(self):
285 self.addCleanup(self.rollback_compute_nodes_status)
286
287 enabled_compute_nodes = [
288 cn for cn in self.initial_compute_nodes_setup
289 if cn.get('status') == 'enabled']
290
291 enabled_compute_node = enabled_compute_nodes[0]
292 actions = [
293 {"action_type": "change_nova_service_state",
294 "resource_id": enabled_compute_node['host'],
295 "input_parameters": {"state": "enabled"}}
296 ]
297 self._execute_actions(actions)
298
299 def test_execute_resize(self):
300 self.addCleanup(self.rollback_compute_nodes_status)
301
302 created_instances = self._create_one_instance_per_host()
303 instance = created_instances[0]
304 current_flavor_id = instance['flavor']['id']
305
306 flavors = self._get_flavors()
307 new_flavors = [f for f in flavors if f['id'] != current_flavor_id]
308 new_flavor = new_flavors[0]
309
310 actions = [
311 {"action_type": "resize",
312 "resource_id": instance['id'],
313 "input_parameters": {"flavor": new_flavor['name']}}
314 ]
315 self._execute_actions(actions)
316
317 def test_execute_migrate(self):
318 self.addCleanup(self.rollback_compute_nodes_status)
319
320 created_instances = self._create_one_instance_per_host()
321 instance = created_instances[0]
322 source_node = created_instances[0]["OS-EXT-SRV-ATTR:host"]
323 destination_node = created_instances[-1]["OS-EXT-SRV-ATTR:host"]
324 actions = [
325 {"action_type": "migrate",
326 "resource_id": instance['id'],
327 "input_parameters": {
328 "migration_type": "live",
329 "source_node": source_node,
330 "destination_node": destination_node}}
331 ]
332 self._execute_actions(actions)
333
334 def test_execute_scenarios(self):
335 self.addCleanup(self.rollback_compute_nodes_status)
336
337 for _, scenario in self.scenarios:
338 actions = scenario['actions']
339 self._fill_actions(actions)
340 self._execute_actions(actions)