Coverage for nova/conductor/rpcapi.py: 77%
148 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Copyright 2013 IBM Corp.
2# Copyright 2013 Red Hat, Inc.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
16"""Client side of the conductor RPC API."""
18import oslo_messaging as messaging
19from oslo_serialization import jsonutils
20from oslo_versionedobjects import base as ovo_base
22import nova.conf
23from nova import exception
24from nova.i18n import _
25from nova.objects import base as objects_base
26from nova import profiler
27from nova import rpc
29CONF = nova.conf.CONF
30RPC_TOPIC = 'conductor'
33@profiler.trace_cls("rpc")
34class ConductorAPI(object):
35 """Client side of the conductor RPC API
37 API version history:
39 * 1.0 - Initial version.
40 * 1.1 - Added migration_update
41 * 1.2 - Added instance_get_by_uuid and instance_get_all_by_host
42 * 1.3 - Added aggregate_host_add and aggregate_host_delete
43 * 1.4 - Added migration_get
44 * 1.5 - Added bw_usage_update
45 * 1.6 - Added get_backdoor_port()
46 * 1.7 - Added aggregate_get_by_host, aggregate_metadata_add,
47 and aggregate_metadata_delete
48 * 1.8 - Added security_group_get_by_instance and
49 security_group_rule_get_by_security_group
50 * 1.9 - Added provider_fw_rule_get_all
51 * 1.10 - Added agent_build_get_by_triple
52 * 1.11 - Added aggregate_get
53 * 1.12 - Added block_device_mapping_update_or_create
54 * 1.13 - Added block_device_mapping_get_all_by_instance
55 * 1.14 - Added block_device_mapping_destroy
56 * 1.15 - Added instance_get_all_by_filters and
57 instance_get_all_hung_in_rebooting and
58 instance_get_active_by_window
59 Deprecated instance_get_all_by_host
60 * 1.16 - Added instance_destroy
61 * 1.17 - Added instance_info_cache_delete
62 * 1.18 - Added instance_type_get
63 * 1.19 - Added vol_get_usage_by_time and vol_usage_update
64 * 1.20 - Added migration_get_unconfirmed_by_dest_compute
65 * 1.21 - Added service_get_all_by
66 * 1.22 - Added ping
67 * 1.23 - Added instance_get_all
68 Un-Deprecate instance_get_all_by_host
69 * 1.24 - Added instance_get
70 * 1.25 - Added action_event_start and action_event_finish
71 * 1.26 - Added instance_info_cache_update
72 * 1.27 - Added service_create
73 * 1.28 - Added binary arg to service_get_all_by
74 * 1.29 - Added service_destroy
75 * 1.30 - Added migration_create
76 * 1.31 - Added migration_get_in_progress_by_host_and_node
77 * 1.32 - Added optional node to instance_get_all_by_host
78 * 1.33 - Added compute_node_create and compute_node_update
79 * 1.34 - Added service_update
80 * 1.35 - Added instance_get_active_by_window_joined
81 * 1.36 - Added instance_fault_create
82 * 1.37 - Added task_log_get, task_log_begin_task, task_log_end_task
83 * 1.38 - Added service name to instance_update
84 * 1.39 - Added notify_usage_exists
85 * 1.40 - Added security_groups_trigger_handler and
86 security_groups_trigger_members_refresh
87 Remove instance_get_active_by_window
88 * 1.41 - Added fixed_ip_get_by_instance, network_get,
89 instance_floating_address_get_all, quota_commit,
90 quota_rollback
91 * 1.42 - Added get_ec2_ids, aggregate_metadata_get_by_host
92 * 1.43 - Added compute_stop
93 * 1.44 - Added compute_node_delete
94 * 1.45 - Added project_id to quota_commit and quota_rollback
95 * 1.46 - Added compute_confirm_resize
96 * 1.47 - Added columns_to_join to instance_get_all_by_host and
97 instance_get_all_by_filters
98 * 1.48 - Added compute_unrescue
100 ... Grizzly supports message version 1.48. So, any changes to existing
101 methods in 2.x after that point should be done such that they can
102 handle the version_cap being set to 1.48.
104 * 1.49 - Added columns_to_join to instance_get_by_uuid
105 * 1.50 - Added object_action() and object_class_action()
106 * 1.51 - Added the 'legacy' argument to
107 block_device_mapping_get_all_by_instance
108 * 1.52 - Pass instance objects for compute_confirm_resize
109 * 1.53 - Added compute_reboot
110 * 1.54 - Added 'update_cells' argument to bw_usage_update
111 * 1.55 - Pass instance objects for compute_stop
112 * 1.56 - Remove compute_confirm_resize and
113 migration_get_unconfirmed_by_dest_compute
114 * 1.57 - Remove migration_create()
115 * 1.58 - Remove migration_get()
117 ... Havana supports message version 1.58. So, any changes to existing
118 methods in 1.x after that point should be done such that they can
119 handle the version_cap being set to 1.58.
121 * 1.59 - Remove instance_info_cache_update()
122 * 1.60 - Remove aggregate_metadata_add() and aggregate_metadata_delete()
123 * ... - Remove security_group_get_by_instance() and
124 security_group_rule_get_by_security_group()
125 * 1.61 - Return deleted instance from instance_destroy()
126 * 1.62 - Added object_backport()
127 * 1.63 - Changed the format of values['stats'] from a dict to a JSON string
128 in compute_node_update()
129 * 1.64 - Added use_slave to instance_get_all_filters()
130 - Remove instance_type_get()
131 - Remove aggregate_get()
132 - Remove aggregate_get_by_host()
133 - Remove instance_get()
134 - Remove migration_update()
135 - Remove block_device_mapping_destroy()
137 * 2.0 - Drop backwards compatibility
138 - Remove quota_rollback() and quota_commit()
139 - Remove aggregate_host_add() and aggregate_host_delete()
140 - Remove network_migrate_instance_start() and
141 network_migrate_instance_finish()
142 - Remove vol_get_usage_by_time
144 ... Icehouse supports message version 2.0. So, any changes to
145 existing methods in 2.x after that point should be done such
146 that they can handle the version_cap being set to 2.0.
148 * Remove instance_destroy()
149 * Remove compute_unrescue()
150 * Remove instance_get_all_by_filters()
151 * Remove instance_get_active_by_window_joined()
152 * Remove instance_fault_create()
153 * Remove action_event_start() and action_event_finish()
154 * Remove instance_get_by_uuid()
155 * Remove agent_build_get_by_triple()
157 ... Juno supports message version 2.0. So, any changes to
158 existing methods in 2.x after that point should be done such
159 that they can handle the version_cap being set to 2.0.
161 * 2.1 - Make notify_usage_exists() take an instance object
162 * Remove bw_usage_update()
163 * Remove notify_usage_exists()
165 ... Kilo supports message version 2.1. So, any changes to
166 existing methods in 2.x after that point should be done such
167 that they can handle the version_cap being set to 2.1.
169 * Remove get_ec2_ids()
170 * Remove service_get_all_by()
171 * Remove service_create()
172 * Remove service_destroy()
173 * Remove service_update()
174 * Remove migration_get_in_progress_by_host_and_node()
175 * Remove aggregate_metadata_get_by_host()
176 * Remove block_device_mapping_update_or_create()
177 * Remove block_device_mapping_get_all_by_instance()
178 * Remove instance_get_all_by_host()
179 * Remove compute_node_update()
180 * Remove compute_node_delete()
181 * Remove security_groups_trigger_handler()
182 * Remove task_log_get()
183 * Remove task_log_begin_task()
184 * Remove task_log_end_task()
185 * Remove security_groups_trigger_members_refresh()
186 * Remove vol_usage_update()
187 * Remove instance_update()
189 * 2.2 - Add object_backport_versions()
190 * 2.3 - Add object_class_action_versions()
191 * Remove compute_node_create()
192 * Remove object_backport()
194 * 3.0 - Drop backwards compatibility
196 ... Liberty, Mitaka, Newton, and Ocata support message version 3.0. So,
197 any changes to existing methods in 3.x after that point should be done such
198 that they can handle the version_cap being set to 3.0.
200 * Remove provider_fw_rule_get_all()
201 """
203 VERSION_ALIASES = {
204 'grizzly': '1.48',
205 'havana': '1.58',
206 'icehouse': '2.0',
207 'juno': '2.0',
208 'kilo': '2.1',
209 'liberty': '3.0',
210 'mitaka': '3.0',
211 'newton': '3.0',
212 'ocata': '3.0',
213 }
215 def __init__(self):
216 super(ConductorAPI, self).__init__()
217 target = messaging.Target(topic=RPC_TOPIC, version='3.0')
218 version_cap = self.VERSION_ALIASES.get(CONF.upgrade_levels.conductor,
219 CONF.upgrade_levels.conductor)
220 serializer = objects_base.NovaObjectSerializer()
221 self.client = rpc.get_client(target,
222 version_cap=version_cap,
223 serializer=serializer)
225 # TODO(hanlind): This method can be removed once oslo.versionedobjects
226 # has been converted to use version_manifests in remotable_classmethod
227 # operations, which will use the new class action handler.
228 def object_class_action(self, context, objname, objmethod, objver,
229 args, kwargs):
230 versions = ovo_base.obj_tree_get_versions(objname)
231 return self.object_class_action_versions(context,
232 objname,
233 objmethod,
234 versions,
235 args, kwargs)
237 def object_class_action_versions(self, context, objname, objmethod,
238 object_versions, args, kwargs):
239 cctxt = self.client.prepare()
240 return cctxt.call(context, 'object_class_action_versions',
241 objname=objname, objmethod=objmethod,
242 object_versions=object_versions,
243 args=args, kwargs=kwargs)
245 def object_action(self, context, objinst, objmethod, args, kwargs):
246 cctxt = self.client.prepare()
247 return cctxt.call(context, 'object_action', objinst=objinst,
248 objmethod=objmethod, args=args, kwargs=kwargs)
250 def object_backport_versions(self, context, objinst, object_versions):
251 cctxt = self.client.prepare()
252 return cctxt.call(context, 'object_backport_versions', objinst=objinst,
253 object_versions=object_versions)
256@profiler.trace_cls("rpc")
257class ComputeTaskAPI(object):
258 """Client side of the conductor 'compute' namespaced RPC API
260 API version history:
262 1.0 - Initial version (empty).
263 1.1 - Added unified migrate_server call.
264 1.2 - Added build_instances
265 1.3 - Added unshelve_instance
266 1.4 - Added reservations to migrate_server.
267 1.5 - Added the legacy_bdm parameter to build_instances
268 1.6 - Made migrate_server use instance objects
269 1.7 - Do not send block_device_mapping and legacy_bdm to build_instances
270 1.8 - Add rebuild_instance
271 1.9 - Converted requested_networks to NetworkRequestList object
272 1.10 - Made migrate_server() and build_instances() send flavor objects
273 1.11 - Added clean_shutdown to migrate_server()
274 1.12 - Added request_spec to rebuild_instance()
275 1.13 - Added request_spec to migrate_server()
276 1.14 - Added request_spec to unshelve_instance()
277 1.15 - Added live_migrate_instance
278 1.16 - Added schedule_and_build_instances
279 1.17 - Added tags to schedule_and_build_instances()
280 1.18 - Added request_spec to build_instances().
281 1.19 - build_instances() now gets a 'host_lists' parameter that represents
282 potential alternate hosts for retries within a cell for each
283 instance.
284 1.20 - migrate_server() now gets a 'host_list' parameter that represents
285 potential alternate hosts for retries within a cell.
286 1.21 - Added cache_images()
287 1.22 - Added confirm_snapshot_based_resize()
288 1.23 - Added revert_snapshot_based_resize()
289 1.24 - Add reimage_boot_volume parameter to rebuild_instance()
290 1.25 - Add target_state parameter to rebuild_instance()
291 """
293 def __init__(self):
294 super(ComputeTaskAPI, self).__init__()
295 target = messaging.Target(topic=RPC_TOPIC,
296 namespace='compute_task',
297 version='1.0')
298 serializer = objects_base.NovaObjectSerializer()
299 self.client = rpc.get_client(target, serializer=serializer)
301 def live_migrate_instance(self, context, instance, scheduler_hint,
302 block_migration, disk_over_commit, request_spec):
303 kw = {'instance': instance, 'scheduler_hint': scheduler_hint,
304 'block_migration': block_migration,
305 'disk_over_commit': disk_over_commit,
306 'request_spec': request_spec,
307 }
308 version = '1.15'
309 cctxt = self.client.prepare(version=version)
310 cctxt.cast(context, 'live_migrate_instance', **kw)
312 # TODO(melwitt): Remove the reservations parameter in version 2.0 of the
313 # RPC API.
314 # TODO(mriedem): Make request_spec required *and* a RequestSpec object
315 # rather than a legacy dict in version 2.0 of the RPC API.
316 def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
317 flavor, block_migration, disk_over_commit,
318 reservations=None, clean_shutdown=True, request_spec=None,
319 host_list=None, do_cast=False):
320 kw = {'instance': instance, 'scheduler_hint': scheduler_hint,
321 'live': live, 'rebuild': rebuild, 'flavor': flavor,
322 'block_migration': block_migration,
323 'disk_over_commit': disk_over_commit,
324 'reservations': reservations,
325 'clean_shutdown': clean_shutdown,
326 'request_spec': request_spec,
327 'host_list': host_list,
328 }
329 version = '1.20'
330 if not self.client.can_send_version(version): 330 ↛ 331line 330 didn't jump to line 331 because the condition on line 330 was never true
331 del kw['host_list']
332 version = '1.13'
333 if not self.client.can_send_version(version): 333 ↛ 334line 333 didn't jump to line 334 because the condition on line 333 was never true
334 del kw['request_spec']
335 version = '1.11'
336 if not self.client.can_send_version(version): 336 ↛ 337line 336 didn't jump to line 337 because the condition on line 336 was never true
337 del kw['clean_shutdown']
338 version = '1.10'
339 if not self.client.can_send_version(version): 339 ↛ 340line 339 didn't jump to line 340 because the condition on line 339 was never true
340 kw['flavor'] = objects_base.obj_to_primitive(flavor)
341 version = '1.6'
342 if not self.client.can_send_version(version): 342 ↛ 343line 342 didn't jump to line 343 because the condition on line 342 was never true
343 kw['instance'] = jsonutils.to_primitive(
344 objects_base.obj_to_primitive(instance))
345 version = '1.4'
346 cctxt = self.client.prepare(
347 version=version,
348 call_monitor_timeout=CONF.rpc_response_timeout,
349 timeout=CONF.long_rpc_timeout)
350 if do_cast:
351 return cctxt.cast(context, 'migrate_server', **kw)
352 return cctxt.call(context, 'migrate_server', **kw)
354 def build_instances(self, context, instances, image, filter_properties,
355 admin_password, injected_files, requested_networks,
356 security_groups, block_device_mapping, legacy_bdm=True,
357 request_spec=None, host_lists=None):
358 image_p = jsonutils.to_primitive(image)
359 kwargs = {"instances": instances, "image": image_p,
360 "filter_properties": filter_properties,
361 "admin_password": admin_password,
362 "injected_files": injected_files,
363 "requested_networks": requested_networks,
364 "security_groups": security_groups,
365 "request_spec": request_spec,
366 "host_lists": host_lists}
367 version = '1.19'
368 if not self.client.can_send_version(version):
369 version = '1.18'
370 kwargs.pop("host_lists")
371 if not self.client.can_send_version(version):
372 version = '1.10'
373 kwargs.pop("request_spec")
374 if not self.client.can_send_version(version): 374 ↛ 375line 374 didn't jump to line 375 because the condition on line 374 was never true
375 version = '1.9'
376 if 'instance_type' in filter_properties:
377 flavor = filter_properties['instance_type']
378 flavor_p = objects_base.obj_to_primitive(flavor)
379 kwargs["filter_properties"] = dict(filter_properties,
380 instance_type=flavor_p)
381 if not self.client.can_send_version(version): 381 ↛ 382line 381 didn't jump to line 382 because the condition on line 381 was never true
382 version = '1.8'
383 nets = kwargs['requested_networks'].as_tuples()
384 kwargs['requested_networks'] = nets
385 if not self.client.can_send_version('1.7'): 385 ↛ 386line 385 didn't jump to line 386 because the condition on line 385 was never true
386 version = '1.5'
387 bdm_p = objects_base.obj_to_primitive(block_device_mapping)
388 kwargs.update({'block_device_mapping': bdm_p,
389 'legacy_bdm': legacy_bdm})
391 cctxt = self.client.prepare(version=version)
392 cctxt.cast(context, 'build_instances', **kwargs)
394 def schedule_and_build_instances(self, context, build_requests,
395 request_specs,
396 image, admin_password, injected_files,
397 requested_networks,
398 block_device_mapping,
399 tags=None):
400 version = '1.17'
401 kw = {'build_requests': build_requests,
402 'request_specs': request_specs,
403 'image': jsonutils.to_primitive(image),
404 'admin_password': admin_password,
405 'injected_files': injected_files,
406 'requested_networks': requested_networks,
407 'block_device_mapping': block_device_mapping,
408 'tags': tags}
410 if not self.client.can_send_version(version):
411 version = '1.16'
412 del kw['tags']
414 cctxt = self.client.prepare(version=version)
415 cctxt.cast(context, 'schedule_and_build_instances', **kw)
417 def unshelve_instance(self, context, instance, request_spec=None):
418 version = '1.14'
419 kw = {'instance': instance,
420 'request_spec': request_spec
421 }
422 if not self.client.can_send_version(version): 422 ↛ 423line 422 didn't jump to line 423 because the condition on line 422 was never true
423 version = '1.3'
424 del kw['request_spec']
425 cctxt = self.client.prepare(version=version)
426 cctxt.cast(context, 'unshelve_instance', **kw)
428 def rebuild_instance(self, ctxt, instance, new_pass, injected_files,
429 image_ref, orig_image_ref, orig_sys_metadata, bdms,
430 recreate=False, on_shared_storage=False, host=None,
431 preserve_ephemeral=False, request_spec=None,
432 reimage_boot_volume=False, target_state=None):
433 version = '1.25'
434 kw = {'instance': instance,
435 'new_pass': new_pass,
436 'injected_files': injected_files,
437 'image_ref': image_ref,
438 'orig_image_ref': orig_image_ref,
439 'orig_sys_metadata': orig_sys_metadata,
440 'bdms': bdms,
441 'recreate': recreate,
442 'on_shared_storage': on_shared_storage,
443 'preserve_ephemeral': preserve_ephemeral,
444 'host': host,
445 'request_spec': request_spec,
446 'reimage_boot_volume': reimage_boot_volume,
447 'target_state': target_state,
448 }
449 if not self.client.can_send_version(version):
450 if kw['target_state']:
451 raise exception.UnsupportedRPCVersion(
452 api="rebuild_instance", required="1.25")
453 else:
454 del kw['target_state']
455 version = '1.24'
456 if not self.client.can_send_version(version):
457 if kw['reimage_boot_volume']:
458 raise exception.NovaException(
459 'Conductor RPC version does not support '
460 'reimage_boot_volume parameter.')
461 else:
462 del kw['reimage_boot_volume']
463 version = '1.12'
464 if not self.client.can_send_version(version):
465 version = '1.8'
466 del kw['request_spec']
467 cctxt = self.client.prepare(version=version)
468 cctxt.cast(ctxt, 'rebuild_instance', **kw)
470 def cache_images(self, ctxt, aggregate, image_ids):
471 version = '1.21'
472 if not self.client.can_send_version(version):
473 raise exception.NovaException('Conductor RPC version pin does not '
474 'allow cache_images() to be called')
475 cctxt = self.client.prepare(version=version)
476 cctxt.cast(ctxt, 'cache_images', aggregate=aggregate,
477 image_ids=image_ids)
479 def confirm_snapshot_based_resize(
480 self, ctxt, instance, migration, do_cast=True):
481 version = '1.22'
482 if not self.client.can_send_version(version):
483 raise exception.ServiceTooOld(_('nova-conductor too old'))
484 kw = {'instance': instance, 'migration': migration}
485 cctxt = self.client.prepare(version=version)
486 if do_cast:
487 return cctxt.cast(ctxt, 'confirm_snapshot_based_resize', **kw)
488 return cctxt.call(ctxt, 'confirm_snapshot_based_resize', **kw)
490 def revert_snapshot_based_resize(self, ctxt, instance, migration):
491 version = '1.23'
492 if not self.client.can_send_version(version): 492 ↛ 494line 492 didn't jump to line 494 because the condition on line 492 was always true
493 raise exception.ServiceTooOld(_('nova-conductor too old'))
494 kw = {'instance': instance, 'migration': migration}
495 cctxt = self.client.prepare(version=version)
496 cctxt.cast(ctxt, 'revert_snapshot_based_resize', **kw)