Coverage for nova/compute/rpcapi.py: 94%
538 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 Red Hat, Inc.
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
14"""
15Client side of the compute RPC API.
16"""
18from oslo_concurrency import lockutils
19from oslo_log import log as logging
20import oslo_messaging as messaging
21from oslo_utils import excutils
23import nova.conf
24from nova import context
25from nova import exception
26from nova.i18n import _
27from nova import objects
28from nova.objects import base as objects_base
29from nova.objects import service as service_obj
30from nova import profiler
31from nova import rpc
33CONF = nova.conf.CONF
34RPC_TOPIC = "compute"
36LOG = logging.getLogger(__name__)
37LAST_VERSION = None
38NO_COMPUTES_WARNING = False
39# Global for ComputeAPI.router.
40_ROUTER = None
43def reset_globals():
44 global NO_COMPUTES_WARNING
45 global LAST_VERSION
46 global _ROUTER
48 NO_COMPUTES_WARNING = False
49 LAST_VERSION = None
50 _ROUTER = None
53def _compute_host(host, instance):
54 '''Get the destination host for a message.
56 :param host: explicit host to send the message to.
57 :param instance: If an explicit host was not specified, use
58 instance['host']
60 :returns: A host
61 '''
62 if host:
63 return host
64 if not instance: 64 ↛ 65line 64 didn't jump to line 65 because the condition on line 64 was never true
65 raise exception.NovaException(_('No compute host specified'))
66 if not instance.host: 66 ↛ 67line 66 didn't jump to line 67 because the condition on line 66 was never true
67 raise exception.NovaException(_('Unable to find host for '
68 'Instance %s') % instance.uuid)
69 return instance.host
72@profiler.trace_cls("rpc")
73class ComputeAPI(object):
74 '''Client side of the compute rpc API.
76 API version history:
78 * 1.0 - Initial version.
79 * 1.1 - Adds get_host_uptime()
80 * 1.2 - Adds check_can_live_migrate_[destination|source]
81 * 1.3 - Adds change_instance_metadata()
82 * 1.4 - Remove instance_uuid, add instance argument to
83 reboot_instance()
84 * 1.5 - Remove instance_uuid, add instance argument to
85 pause_instance(), unpause_instance()
86 * 1.6 - Remove instance_uuid, add instance argument to
87 suspend_instance()
88 * 1.7 - Remove instance_uuid, add instance argument to
89 get_console_output()
90 * 1.8 - Remove instance_uuid, add instance argument to
91 add_fixed_ip_to_instance()
92 * 1.9 - Remove instance_uuid, add instance argument to attach_volume()
93 * 1.10 - Remove instance_id, add instance argument to
94 check_can_live_migrate_destination()
95 * 1.11 - Remove instance_id, add instance argument to
96 check_can_live_migrate_source()
97 * 1.12 - Remove instance_uuid, add instance argument to
98 confirm_resize()
99 * 1.13 - Remove instance_uuid, add instance argument to detach_volume()
100 * 1.14 - Remove instance_uuid, add instance argument to finish_resize()
101 * 1.15 - Remove instance_uuid, add instance argument to
102 finish_revert_resize()
103 * 1.16 - Remove instance_uuid, add instance argument to
104 get_diagnostics()
105 * 1.17 - Remove instance_uuid, add instance argument to
106 get_vnc_console()
107 * 1.18 - Remove instance_uuid, add instance argument to inject_file()
108 * 1.19 - Remove instance_uuid, add instance argument to
109 inject_network_info()
110 * 1.20 - Remove instance_id, add instance argument to
111 post_live_migration_at_destination()
112 * 1.21 - Remove instance_uuid, add instance argument to
113 power_off_instance() and stop_instance()
114 * 1.22 - Remove instance_uuid, add instance argument to
115 power_on_instance() and start_instance()
116 * 1.23 - Remove instance_id, add instance argument to
117 pre_live_migration()
118 * 1.24 - Remove instance_uuid, add instance argument to
119 rebuild_instance()
120 * 1.25 - Remove instance_uuid, add instance argument to
121 remove_fixed_ip_from_instance()
122 * 1.26 - Remove instance_id, add instance argument to
123 remove_volume_connection()
124 * 1.27 - Remove instance_uuid, add instance argument to
125 rescue_instance()
126 * 1.28 - Remove instance_uuid, add instance argument to reset_network()
127 * 1.29 - Remove instance_uuid, add instance argument to
128 resize_instance()
129 * 1.30 - Remove instance_uuid, add instance argument to
130 resume_instance()
131 * 1.31 - Remove instance_uuid, add instance argument to revert_resize()
132 * 1.32 - Remove instance_id, add instance argument to
133 rollback_live_migration_at_destination()
134 * 1.33 - Remove instance_uuid, add instance argument to
135 set_admin_password()
136 * 1.34 - Remove instance_uuid, add instance argument to
137 snapshot_instance()
138 * 1.35 - Remove instance_uuid, add instance argument to
139 unrescue_instance()
140 * 1.36 - Remove instance_uuid, add instance argument to
141 change_instance_metadata()
142 * 1.37 - Remove instance_uuid, add instance argument to
143 terminate_instance()
144 * 1.38 - Changes to prep_resize():
145 * remove instance_uuid, add instance
146 * remove instance_type_id, add instance_type
147 * remove topic, it was unused
148 * 1.39 - Remove instance_uuid, add instance argument to run_instance()
149 * 1.40 - Remove instance_id, add instance argument to live_migration()
150 * 1.41 - Adds refresh_instance_security_rules()
151 * 1.42 - Add reservations arg to prep_resize(), resize_instance(),
152 finish_resize(), confirm_resize(), revert_resize() and
153 finish_revert_resize()
154 * 1.43 - Add migrate_data to live_migration()
155 * 1.44 - Adds reserve_block_device_name()
157 * 2.0 - Remove 1.x backwards compat
158 * 2.1 - Adds orig_sys_metadata to rebuild_instance()
159 * 2.2 - Adds slave_info parameter to add_aggregate_host() and
160 remove_aggregate_host()
161 * 2.3 - Adds volume_id to reserve_block_device_name()
162 * 2.4 - Add bdms to terminate_instance
163 * 2.5 - Add block device and network info to reboot_instance
164 * 2.6 - Remove migration_id, add migration to resize_instance
165 * 2.7 - Remove migration_id, add migration to confirm_resize
166 * 2.8 - Remove migration_id, add migration to finish_resize
167 * 2.9 - Add publish_service_capabilities()
168 * 2.10 - Adds filter_properties and request_spec to prep_resize()
169 * 2.11 - Adds soft_delete_instance() and restore_instance()
170 * 2.12 - Remove migration_id, add migration to revert_resize
171 * 2.13 - Remove migration_id, add migration to finish_revert_resize
172 * 2.14 - Remove aggregate_id, add aggregate to add_aggregate_host
173 * 2.15 - Remove aggregate_id, add aggregate to remove_aggregate_host
174 * 2.16 - Add instance_type to resize_instance
175 * 2.17 - Add get_backdoor_port()
176 * 2.18 - Add bdms to rebuild_instance
177 * 2.19 - Add node to run_instance
178 * 2.20 - Add node to prep_resize
179 * 2.21 - Add migrate_data dict param to pre_live_migration()
180 * 2.22 - Add recreate, on_shared_storage and host arguments to
181 rebuild_instance()
182 * 2.23 - Remove network_info from reboot_instance
183 * 2.24 - Added get_spice_console method
184 * 2.25 - Add attach_interface() and detach_interface()
185 * 2.26 - Add validate_console_port to ensure the service connects to
186 vnc on the correct port
187 * 2.27 - Adds 'reservations' to terminate_instance() and
188 soft_delete_instance()
190 ... Grizzly supports message version 2.27. So, any changes to existing
191 methods in 2.x after that point should be done such that they can
192 handle the version_cap being set to 2.27.
194 * 2.28 - Adds check_instance_shared_storage()
195 * 2.29 - Made start_instance() and stop_instance() take new-world
196 instance objects
197 * 2.30 - Adds live_snapshot_instance()
198 * 2.31 - Adds shelve_instance(), shelve_offload_instance, and
199 unshelve_instance()
200 * 2.32 - Make reboot_instance take a new world instance object
201 * 2.33 - Made suspend_instance() and resume_instance() take new-world
202 instance objects
203 * 2.34 - Added swap_volume()
204 * 2.35 - Made terminate_instance() and soft_delete_instance() take
205 new-world instance objects
206 * 2.36 - Made pause_instance() and unpause_instance() take new-world
207 instance objects
208 * 2.37 - Added the legacy_bdm_in_spec parameter to run_instance
209 * 2.38 - Made check_can_live_migrate_[destination|source] take
210 new-world instance objects
211 * 2.39 - Made revert_resize() and confirm_resize() take new-world
212 instance objects
213 * 2.40 - Made reset_network() take new-world instance object
214 * 2.41 - Make inject_network_info take new-world instance object
215 * 2.42 - Splits snapshot_instance() into snapshot_instance() and
216 backup_instance() and makes them take new-world instance
217 objects.
218 * 2.43 - Made prep_resize() take new-world instance object
219 * 2.44 - Add volume_snapshot_create(), volume_snapshot_delete()
220 * 2.45 - Made resize_instance() take new-world objects
221 * 2.46 - Made finish_resize() take new-world objects
222 * 2.47 - Made finish_revert_resize() take new-world objects
224 ... Havana supports message version 2.47. So, any changes to existing
225 methods in 2.x after that point should be done such that they can
226 handle the version_cap being set to 2.47.
228 * 2.48 - Make add_aggregate_host() and remove_aggregate_host() take
229 new-world objects
230 * ... - Remove live_snapshot() that was never actually used
232 * 3.0 - Remove 2.x compatibility
233 * 3.1 - Update get_spice_console() to take an instance object
234 * 3.2 - Update get_vnc_console() to take an instance object
235 * 3.3 - Update validate_console_port() to take an instance object
236 * 3.4 - Update rebuild_instance() to take an instance object
237 * 3.5 - Pass preserve_ephemeral flag to rebuild_instance()
238 * 3.6 - Make volume_snapshot_{create,delete} use new-world objects
239 * 3.7 - Update change_instance_metadata() to take an instance object
240 * 3.8 - Update set_admin_password() to take an instance object
241 * 3.9 - Update rescue_instance() to take an instance object
242 * 3.10 - Added get_rdp_console method
243 * 3.11 - Update unrescue_instance() to take an object
244 * 3.12 - Update add_fixed_ip_to_instance() to take an object
245 * 3.13 - Update remove_fixed_ip_from_instance() to take an object
246 * 3.14 - Update post_live_migration_at_destination() to take an object
247 * 3.15 - Adds filter_properties and node to unshelve_instance()
248 * 3.16 - Make reserve_block_device_name and attach_volume use new-world
249 objects, and add disk_bus and device_type params to
250 reserve_block_device_name, and bdm param to attach_volume
251 * 3.17 - Update attach_interface and detach_interface to take an object
252 * 3.18 - Update get_diagnostics() to take an instance object
253 * Removed inject_file(), as it was unused.
254 * 3.19 - Update pre_live_migration to take instance object
255 * 3.20 - Make restore_instance take an instance object
256 * 3.21 - Made rebuild take new-world BDM objects
257 * 3.22 - Made terminate_instance take new-world BDM objects
258 * 3.23 - Added external_instance_event()
259 * build_and_run_instance was added in Havana and not used or
260 documented.
262 ... Icehouse supports message version 3.23. So, any changes to
263 existing methods in 3.x after that point should be done such that they
264 can handle the version_cap being set to 3.23.
266 * 3.24 - Update rescue_instance() to take optional rescue_image_ref
267 * 3.25 - Make detach_volume take an object
268 * 3.26 - Make live_migration() and
269 rollback_live_migration_at_destination() take an object
270 * ... Removed run_instance()
271 * 3.27 - Make run_instance() accept a new-world object
272 * 3.28 - Update get_console_output() to accept a new-world object
273 * 3.29 - Make check_instance_shared_storage accept a new-world object
274 * 3.30 - Make remove_volume_connection() accept a new-world object
275 * 3.31 - Add get_instance_diagnostics
276 * 3.32 - Add destroy_disks and migrate_data optional parameters to
277 rollback_live_migration_at_destination()
278 * 3.33 - Make build_and_run_instance() take a NetworkRequestList object
279 * 3.34 - Add get_serial_console method
280 * 3.35 - Make reserve_block_device_name return a BDM object
282 ... Juno supports message version 3.35. So, any changes to
283 existing methods in 3.x after that point should be done such that they
284 can handle the version_cap being set to 3.35.
286 * 3.36 - Make build_and_run_instance() send a Flavor object
287 * 3.37 - Add clean_shutdown to stop, resize, rescue, shelve, and
288 shelve_offload
289 * 3.38 - Add clean_shutdown to prep_resize
290 * 3.39 - Add quiesce_instance and unquiesce_instance methods
291 * 3.40 - Make build_and_run_instance() take a new-world topology
292 limits object
294 ... Kilo supports messaging version 3.40. So, any changes to
295 existing methods in 3.x after that point should be done so that they
296 can handle the version_cap being set to 3.40
298 ... Version 4.0 is equivalent to 3.40. Kilo sends version 4.0 by
299 default, can accept 3.x calls from Juno nodes, and can be pinned to
300 3.x for Juno compatibility. All new changes should go against 4.x.
302 * 4.0 - Remove 3.x compatibility
303 * 4.1 - Make prep_resize() and resize_instance() send Flavor object
304 * 4.2 - Add migration argument to live_migration()
305 * 4.3 - Added get_mks_console method
306 * 4.4 - Make refresh_instance_security_rules send an instance object
307 * 4.5 - Add migration, scheduler_node and limits arguments to
308 rebuild_instance()
310 ... Liberty supports messaging version 4.5. So, any changes to
311 existing methods in 4.x after that point should be done so that they
312 can handle the version_cap being set to 4.5
314 * ... - Remove refresh_security_group_members()
315 * ... - Remove refresh_security_group_rules()
316 * 4.6 - Add trigger_crash_dump()
317 * 4.7 - Add attachment_id argument to detach_volume()
318 * 4.8 - Send migrate_data in object format for live_migration,
319 rollback_live_migration_at_destination, and
320 pre_live_migration.
321 * ... - Remove refresh_provider_fw_rules()
322 * 4.9 - Add live_migration_force_complete()
323 * 4.10 - Add live_migration_abort()
324 * 4.11 - Allow block_migration and disk_over_commit be None
326 ... Mitaka supports messaging version 4.11. So, any changes to
327 existing methods in 4.x after that point should be done so that they
328 can handle the version_cap being set to 4.11
330 * 4.12 - Remove migration_id from live_migration_force_complete
331 * 4.13 - Make get_instance_diagnostics send an instance object
333 ... Newton and Ocata support messaging version 4.13. So, any changes to
334 existing methods in 4.x after that point should be done so that they
335 can handle the version_cap being set to 4.13
337 * 4.14 - Make get_instance_diagnostics return a diagnostics object
338 instead of dictionary. Strictly speaking we don't need to bump
339 the version because this method was unused before. The version
340 was bumped to signal the availability of the corrected RPC API
341 * 4.15 - Add tag argument to reserve_block_device_name()
342 * 4.16 - Add tag argument to attach_interface()
343 * 4.17 - Add new_attachment_id to swap_volume.
345 ... Pike supports messaging version 4.17. So any changes to existing
346 methods in 4.x after that point should be done so that they can handle
347 the version_cap being set to 4.17.
349 * 4.18 - Add migration to prep_resize()
350 * 4.19 - build_and_run_instance() now gets a 'host_list' parameter
351 representing potential alternate hosts for retries within a
352 cell.
353 * 4.20 - Add multiattach argument to reserve_block_device_name().
354 * 4.21 - prep_resize() now gets a 'host_list' parameter representing
355 potential alternate hosts for retries within a cell.
356 * 4.22 - Add request_spec to rebuild_instance()
358 ... Version 5.0 is functionally equivalent to 4.22, aside from
359 removing deprecated parameters. Queens sends 5.0 by default,
360 can accept 4.x calls from Pike nodes, and can be pinned to 4.x
361 for Pike compatibility. All new changes should go against 5.x.
363 * 5.0 - Remove 4.x compatibility
364 * 5.1 - Make prep_resize() take a RequestSpec object rather than a
365 legacy dict.
366 * 5.2 - Add request_spec parameter for the following: resize_instance,
367 finish_resize, revert_resize, finish_revert_resize,
368 unshelve_instance
369 * 5.3 - Add migration and limits parameters to
370 check_can_live_migrate_destination(), and a new
371 drop_move_claim_at_destination() method
372 * 5.4 - Add cache_images() support
373 * 5.5 - Add prep_snapshot_based_resize_at_dest()
374 * 5.6 - Add prep_snapshot_based_resize_at_source()
375 * 5.7 - Add finish_snapshot_based_resize_at_dest()
376 * 5.8 - Add confirm_snapshot_based_resize_at_source()
377 * 5.9 - Add revert_snapshot_based_resize_at_dest()
378 * 5.10 - Add finish_revert_snapshot_based_resize_at_source()
379 * 5.11 - Add accel_uuids (accelerator requests) parameter to
380 build_and_run_instance()
381 * 5.12 - Add accel_uuids (accelerator requests) parameter to
382 rebuild_instance()
383 * 5.13 - Add accel_uuids (accelerator requests) parameter to
384 shelve_instance(), shelve_offload_instance() and
385 unshelve_instance()
387 ... Version 6.0 is functionally equivalent to 5.13, aside from
388 removing deprecated parameters and methods. Wallaby sends 6.0 by
389 default, can accept 5.x calls from Victoria nodes, and can be pinned to
390 5.x for Victoria compatibility. All new changes should go against 6.x.
392 * 6.0 - Remove 5.x compatibility
393 * ... - Remove add_aggregate_host()
394 * ... - Remove remove_aggregate_host()
395 * ... - Remove test_get_console_pool_info()
396 * ... - Remove test_get_console_topic()
397 * ... - Remove refresh_instance_security_rules()
398 * ... - Remove request_spec argument from
399 prep_snapshot_based_resize_at_dest() and
400 finish_snapshot_based_resize_at_dest()
401 * ... - Remove instance argument from check_instance_shared_storage()
402 * ... - Rename the instance_type argument of prep_resize() to flavor
403 * ... - Rename the instance_type argument of resize_instance() to
404 flavor
405 * 6.1 - Add reimage_boot_volume parameter to rebuild_instance()
406 * 6.2 - Add target_state parameter to rebuild_instance()
407 * 6.3 - Add delete_attachment parameter to remove_volume_connection
408 * 6.4 - Add allow_share() and deny_share()
409 '''
411 VERSION_ALIASES = {
412 'icehouse': '3.23',
413 'juno': '3.35',
414 'kilo': '4.0',
415 'liberty': '4.5',
416 'mitaka': '4.11',
417 'newton': '4.13',
418 'ocata': '4.13',
419 'pike': '4.17',
420 'queens': '5.0',
421 'rocky': '5.0',
422 'stein': '5.1',
423 'train': '5.3',
424 'ussuri': '5.11',
425 'victoria': '5.12',
426 'wallaby': '6.0',
427 'xena': '6.0',
428 'yoga': '6.0',
429 'zed': '6.1',
430 'antelope': '6.2',
431 'bobcat': '6.2',
432 'caracal': '6.3',
433 'dalmatian': '6.3',
434 'epoxy': '6.4',
435 }
437 @property
438 def router(self):
439 """Provides singleton access to nova.rpc.ClientRouter for this API
441 The ClientRouter is constructed and accessed as a singleton to avoid
442 querying all cells for a minimum nova-compute service version when
443 [upgrade_levels]/compute=auto and we have access to the API DB.
444 """
445 global _ROUTER
446 if _ROUTER is None:
447 with lockutils.lock('compute-rpcapi-router'):
448 if _ROUTER is None: 448 ↛ 465line 448 didn't jump to line 465
449 target = messaging.Target(topic=RPC_TOPIC, version='6.0')
450 upgrade_level = CONF.upgrade_levels.compute
451 if upgrade_level == 'auto':
452 version_cap = self._determine_version_cap(target)
453 else:
454 version_cap = self.VERSION_ALIASES.get(upgrade_level,
455 upgrade_level)
456 serializer = objects_base.NovaObjectSerializer()
458 # NOTE(danms): We need to poke this path to register CONF
459 # options that we use in self.get_client()
460 rpc.get_client(target, version_cap, serializer)
462 default_client = self.get_client(target, version_cap,
463 serializer)
464 _ROUTER = rpc.ClientRouter(default_client)
465 return _ROUTER
467 def _ver(self, ctxt, old):
468 """Determine compatibility version.
469 This is to be used when we could send either the current major or
470 a revision of the previous major when they are equivalent. This
471 should only be used by calls that are the exact same in the current
472 and previous major versions. Returns either old, or the current major
473 version.
474 :param old: The version under the previous major version that should
475 be sent if we're pinned to it.
476 """
477 client = self.router.client(ctxt)
478 if client.can_send_version('6.0'):
479 return '6.0'
480 else:
481 return old
483 @staticmethod
484 def _determine_version_cap(target):
485 global LAST_VERSION
486 global NO_COMPUTES_WARNING
487 if LAST_VERSION:
488 return LAST_VERSION
490 # NOTE(danms): If we have a connection to the api database,
491 # we should iterate all cells. If not, we must only look locally.
492 if CONF.api_database.connection:
493 try:
494 service_version = service_obj.get_minimum_version_all_cells(
495 context.get_admin_context(), ['nova-compute'])
496 except exception.DBNotAllowed:
497 # This most likely means we are in a nova-compute service
498 # configured with [upgrade_levels]/compute=auto and a
499 # connection to the API database. We should not be attempting
500 # to "get out" of our cell to look at the minimum versions of
501 # nova-compute services in other cells, so DBNotAllowed was
502 # raised. Log a user-friendly message and re-raise the error.
503 with excutils.save_and_reraise_exception():
504 LOG.error('This service is configured for access to the '
505 'API database but is not allowed to directly '
506 'access the database. You should run this '
507 'service without the [api_database]/connection '
508 'config option.')
509 else:
510 service_version = objects.Service.get_minimum_version(
511 context.get_admin_context(), 'nova-compute')
513 history = service_obj.SERVICE_VERSION_HISTORY
515 # NOTE(johngarbutt) when there are no nova-compute services running we
516 # get service_version == 0. In that case we do not want to cache
517 # this result, because we will get a better answer next time.
518 # As a sane default, return the current version.
519 if service_version == 0:
520 if not NO_COMPUTES_WARNING:
521 # NOTE(danms): Only show this warning once
522 LOG.debug("Not caching compute RPC version_cap, because min "
523 "service_version is 0. Please ensure a nova-compute "
524 "service has been started. Defaulting to current "
525 "version.")
526 NO_COMPUTES_WARNING = True
527 return history[service_obj.SERVICE_VERSION]['compute_rpc']
529 try:
530 version_cap = history[service_version]['compute_rpc']
531 except IndexError:
532 LOG.error('Failed to extract compute RPC version from '
533 'service history because I am too '
534 'old (minimum version is now %(version)i)',
535 {'version': service_version})
536 raise exception.ServiceTooOld(thisver=service_obj.SERVICE_VERSION,
537 minver=service_version)
538 except KeyError:
539 LOG.error('Failed to extract compute RPC version from '
540 'service history for version %(version)i',
541 {'version': service_version})
542 return target.version
543 LAST_VERSION = version_cap
544 LOG.info('Automatically selected compute RPC version %(rpc)s '
545 'from minimum service version %(service)i',
546 {'rpc': version_cap,
547 'service': service_version})
548 return version_cap
550 def get_client(self, target, version_cap, serializer):
551 if CONF.rpc_response_timeout > rpc.HEARTBEAT_THRESHOLD:
552 # NOTE(danms): If the operator has overridden RPC timeout
553 # to be longer than rpc.HEARTBEAT_THRESHOLD then configure
554 # the call monitor timeout to be the threshold to keep the
555 # failure timing characteristics that our code likely
556 # expects (from history) while allowing healthy calls
557 # to run longer.
558 cmt = rpc.HEARTBEAT_THRESHOLD
559 else:
560 cmt = None
561 return rpc.get_client(target,
562 version_cap=version_cap,
563 serializer=serializer,
564 call_monitor_timeout=cmt)
566 def add_fixed_ip_to_instance(self, ctxt, instance, network_id):
567 version = self._ver(ctxt, '5.0')
568 cctxt = self.router.client(ctxt).prepare(
569 server=_compute_host(None, instance), version=version)
570 cctxt.cast(ctxt, 'add_fixed_ip_to_instance',
571 instance=instance, network_id=network_id)
573 def attach_interface(self, ctxt, instance, network_id, port_id,
574 requested_ip, tag=None):
575 kw = {'instance': instance, 'network_id': network_id,
576 'port_id': port_id, 'requested_ip': requested_ip,
577 'tag': tag}
578 version = self._ver(ctxt, '5.0')
579 client = self.router.client(ctxt)
580 cctxt = client.prepare(server=_compute_host(None, instance),
581 version=version)
582 return cctxt.call(ctxt, 'attach_interface', **kw)
584 def attach_volume(self, ctxt, instance, bdm):
585 version = self._ver(ctxt, '5.0')
586 cctxt = self.router.client(ctxt).prepare(
587 server=_compute_host(None, instance), version=version)
588 cctxt.cast(ctxt, 'attach_volume', instance=instance, bdm=bdm)
590 def check_can_live_migrate_destination(self, ctxt, instance, destination,
591 block_migration, disk_over_commit,
592 migration, limits):
593 client = self.router.client(ctxt)
594 version = self._ver(ctxt, '5.3')
595 kwargs = {
596 'instance': instance,
597 'block_migration': block_migration,
598 'disk_over_commit': disk_over_commit,
599 'migration': migration,
600 'limits': limits
601 }
602 if not client.can_send_version(version):
603 kwargs.pop('migration')
604 kwargs.pop('limits')
605 version = '5.0'
606 cctxt = client.prepare(server=destination, version=version,
607 call_monitor_timeout=CONF.rpc_response_timeout,
608 timeout=CONF.long_rpc_timeout)
609 return cctxt.call(ctxt, 'check_can_live_migrate_destination', **kwargs)
611 def check_can_live_migrate_source(self, ctxt, instance, dest_check_data):
612 version = self._ver(ctxt, '5.0')
613 client = self.router.client(ctxt)
614 source = _compute_host(None, instance)
615 cctxt = client.prepare(server=source, version=version)
616 return cctxt.call(ctxt, 'check_can_live_migrate_source',
617 instance=instance,
618 dest_check_data=dest_check_data)
620 def check_instance_shared_storage(self, ctxt, data, instance=None,
621 host=None):
622 msg_args = {'data': data}
623 version = self._ver(ctxt, '5.0')
624 client = self.router.client(ctxt)
625 if not client.can_send_version('6.0'):
626 # We always pass the instance until the 5.0 version
627 msg_args['instance'] = instance
628 cctxt = client.prepare(
629 server=_compute_host(host, instance), version=version)
630 return cctxt.call(ctxt, 'check_instance_shared_storage', **msg_args)
632 def confirm_resize(self, ctxt, instance, migration, host,
633 cast=True):
634 client = self.router.client(ctxt)
635 version = self._ver(ctxt, '5.0')
636 cctxt = client.prepare(
637 server=_compute_host(host, instance), version=version)
638 rpc_method = cctxt.cast if cast else cctxt.call
639 return rpc_method(ctxt, 'confirm_resize',
640 instance=instance, migration=migration)
642 def confirm_snapshot_based_resize_at_source(
643 self, ctxt, instance, migration):
644 """Confirms a snapshot-based resize on the source host.
646 Cleans the guest from the source hypervisor including disks and drops
647 the MoveClaim which will free up "old_flavor" usage from the
648 ResourceTracker.
650 Deletes the allocations held by the migration consumer against the
651 source compute node resource provider.
653 This is a synchronous RPC call using the ``long_rpc_timeout``
654 configuration option.
656 :param ctxt: nova auth request context targeted at the source cell
657 :param instance: Instance object being resized which should have the
658 "old_flavor" attribute set
659 :param migration: Migration object for the resize operation
660 :raises: nova.exception.MigrationError if the source compute is too
661 old to perform the operation
662 :raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
663 times out
664 """
665 version = self._ver(ctxt, '5.8')
666 client = self.router.client(ctxt)
667 if not client.can_send_version(version):
668 raise exception.MigrationError(reason=_('Compute too old'))
669 cctxt = client.prepare(server=migration.source_compute,
670 version=version,
671 call_monitor_timeout=CONF.rpc_response_timeout,
672 timeout=CONF.long_rpc_timeout)
673 return cctxt.call(
674 ctxt, 'confirm_snapshot_based_resize_at_source',
675 instance=instance, migration=migration)
677 def detach_interface(self, ctxt, instance, port_id):
678 version = self._ver(ctxt, '5.0')
679 cctxt = self.router.client(ctxt).prepare(
680 server=_compute_host(None, instance), version=version)
681 cctxt.cast(ctxt, 'detach_interface',
682 instance=instance, port_id=port_id)
684 def detach_volume(self, ctxt, instance, volume_id, attachment_id=None):
685 version = self._ver(ctxt, '5.0')
686 client = self.router.client(ctxt)
687 cctxt = client.prepare(server=_compute_host(None, instance),
688 version=version)
689 cctxt.cast(ctxt, 'detach_volume',
690 instance=instance, volume_id=volume_id,
691 attachment_id=attachment_id)
693 def finish_resize(self, ctxt, instance, migration, image, disk_info, host,
694 request_spec):
695 msg_args = {
696 'instance': instance,
697 'migration': migration,
698 'image': image,
699 'disk_info': disk_info,
700 'request_spec': request_spec,
701 }
703 client = self.router.client(ctxt)
704 version = self._ver(ctxt, '5.2')
706 if not client.can_send_version(version):
707 msg_args.pop('request_spec')
708 version = '5.0'
710 cctxt = client.prepare(
711 server=host, version=version)
712 cctxt.cast(ctxt, 'finish_resize', **msg_args)
714 def finish_revert_resize(self, ctxt, instance, migration, host,
715 request_spec):
716 msg_args = {
717 'instance': instance,
718 'migration': migration,
719 'request_spec': request_spec,
720 }
722 client = self.router.client(ctxt)
723 version = self._ver(ctxt, '5.2')
725 if not client.can_send_version(version):
726 msg_args.pop('request_spec')
727 version = '5.0'
729 cctxt = client.prepare(
730 server=host, version=version)
731 cctxt.cast(ctxt, 'finish_revert_resize', **msg_args)
733 def finish_snapshot_based_resize_at_dest(
734 self, ctxt, instance, migration, snapshot_id, request_spec):
735 """Finishes the snapshot-based resize at the destination compute.
737 Sets up block devices and networking on the destination compute and
738 spawns the guest.
740 This is a synchronous RPC call using the ``long_rpc_timeout``
741 configuration option.
743 :param ctxt: nova auth request context targeted at the target cell DB
744 :param instance: The Instance object being resized with the
745 ``migration_context`` field set. Upon successful completion of this
746 method the vm_state should be "resized", the task_state should be
747 None, and migration context, host/node and flavor-related fields
748 should be set on the instance.
749 :param migration: The Migration object for this resize operation. Upon
750 successful completion of this method the migration status should
751 be "finished".
752 :param snapshot_id: ID of the image snapshot created for a
753 non-volume-backed instance, else None.
754 :param request_spec: nova.objects.RequestSpec object for the operation
755 :raises: nova.exception.MigrationError if the destination compute
756 service is too old for this method
757 :raises: oslo_messaging.exceptions.MessagingTimeout if the pre-check
758 RPC call times out
759 """
760 msg_args = {'instance': instance,
761 'migration': migration,
762 'snapshot_id': snapshot_id}
763 client = self.router.client(ctxt)
764 version = self._ver(ctxt, '5.7')
765 if not client.can_send_version('6.0'):
766 msg_args['request_spec'] = request_spec
767 if not client.can_send_version(version):
768 raise exception.MigrationError(reason=_('Compute too old'))
769 cctxt = client.prepare(
770 server=migration.dest_compute, version=version,
771 call_monitor_timeout=CONF.rpc_response_timeout,
772 timeout=CONF.long_rpc_timeout)
773 return cctxt.call(
774 ctxt, 'finish_snapshot_based_resize_at_dest', **msg_args)
776 def finish_revert_snapshot_based_resize_at_source(
777 self, ctxt, instance, migration):
778 """Reverts a snapshot-based resize at the source host.
780 Spawn the guest and re-connect volumes/VIFs on the source host and
781 revert the instance to use the old_flavor for resource usage reporting.
783 Updates allocations in the placement service to move the source node
784 allocations, held by the migration record, to the instance and drop
785 the allocations held by the instance on the destination node.
787 This is a synchronous RPC call using the ``long_rpc_timeout``
788 configuration option.
790 :param ctxt: nova auth request context targeted at the source cell
791 :param instance: Instance object whose vm_state is "resized" and
792 task_state is "resize_reverting".
793 :param migration: Migration object whose status is "reverting".
794 :raises: nova.exception.MigrationError if the source compute is too
795 old to perform the operation
796 :raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
797 times out
798 """
799 version = self._ver(ctxt, '5.10')
800 client = self.router.client(ctxt)
801 if not client.can_send_version(version):
802 raise exception.MigrationError(reason=_('Compute too old'))
803 cctxt = client.prepare(server=migration.source_compute,
804 version=version,
805 call_monitor_timeout=CONF.rpc_response_timeout,
806 timeout=CONF.long_rpc_timeout)
807 return cctxt.call(
808 ctxt, 'finish_revert_snapshot_based_resize_at_source',
809 instance=instance, migration=migration)
811 def get_console_output(self, ctxt, instance, tail_length):
812 version = self._ver(ctxt, '5.0')
813 cctxt = self.router.client(ctxt).prepare(
814 server=_compute_host(None, instance), version=version)
815 return cctxt.call(ctxt, 'get_console_output',
816 instance=instance, tail_length=tail_length)
818 def get_diagnostics(self, ctxt, instance):
819 version = self._ver(ctxt, '5.0')
820 cctxt = self.router.client(ctxt).prepare(
821 server=_compute_host(None, instance), version=version)
822 return cctxt.call(ctxt, 'get_diagnostics', instance=instance)
824 def get_instance_diagnostics(self, ctxt, instance):
825 version = self._ver(ctxt, '5.0')
826 client = self.router.client(ctxt)
827 cctxt = client.prepare(server=_compute_host(None, instance),
828 version=version)
829 return cctxt.call(ctxt, 'get_instance_diagnostics', instance=instance)
831 def get_vnc_console(self, ctxt, instance, console_type):
832 version = self._ver(ctxt, '5.0')
833 cctxt = self.router.client(ctxt).prepare(
834 server=_compute_host(None, instance), version=version)
835 return cctxt.call(ctxt, 'get_vnc_console',
836 instance=instance, console_type=console_type)
838 def get_spice_console(self, ctxt, instance, console_type):
839 version = self._ver(ctxt, '5.0')
840 cctxt = self.router.client(ctxt).prepare(
841 server=_compute_host(None, instance), version=version)
842 return cctxt.call(ctxt, 'get_spice_console',
843 instance=instance, console_type=console_type)
845 def get_mks_console(self, ctxt, instance, console_type):
846 version = self._ver(ctxt, '5.0')
847 cctxt = self.router.client(ctxt).prepare(
848 server=_compute_host(None, instance), version=version)
849 return cctxt.call(ctxt, 'get_mks_console',
850 instance=instance, console_type=console_type)
852 def get_serial_console(self, ctxt, instance, console_type):
853 version = self._ver(ctxt, '5.0')
854 cctxt = self.router.client(ctxt).prepare(
855 server=_compute_host(None, instance), version=version)
856 return cctxt.call(ctxt, 'get_serial_console',
857 instance=instance, console_type=console_type)
859 def validate_console_port(self, ctxt, instance, port, console_type):
860 version = self._ver(ctxt, '5.0')
861 cctxt = self.router.client(ctxt).prepare(
862 server=_compute_host(None, instance), version=version)
863 return cctxt.call(ctxt, 'validate_console_port',
864 instance=instance, port=port,
865 console_type=console_type)
867 def host_maintenance_mode(self, ctxt, host, host_param, mode):
868 '''Set host maintenance mode
870 :param ctxt: request context
871 :param host_param: This value is placed in the message to be the 'host'
872 parameter for the remote method.
873 :param mode:
874 :param host: This is the host to send the message to.
875 '''
876 version = self._ver(ctxt, '5.0')
877 cctxt = self.router.client(ctxt).prepare(
878 server=host, version=version)
879 return cctxt.call(ctxt, 'host_maintenance_mode',
880 host=host_param, mode=mode)
882 def host_power_action(self, ctxt, host, action):
883 version = self._ver(ctxt, '5.0')
884 cctxt = self.router.client(ctxt).prepare(
885 server=host, version=version)
886 return cctxt.call(ctxt, 'host_power_action', action=action)
888 def inject_network_info(self, ctxt, instance):
889 version = self._ver(ctxt, '5.0')
890 cctxt = self.router.client(ctxt).prepare(
891 server=_compute_host(None, instance), version=version)
892 cctxt.cast(ctxt, 'inject_network_info', instance=instance)
894 def live_migration(self, ctxt, instance, dest, block_migration, host,
895 migration, migrate_data=None):
896 version = self._ver(ctxt, '5.0')
897 client = self.router.client(ctxt)
898 cctxt = client.prepare(server=host, version=version)
899 cctxt.cast(ctxt, 'live_migration', instance=instance,
900 dest=dest, block_migration=block_migration,
901 migrate_data=migrate_data, migration=migration)
903 def live_migration_force_complete(self, ctxt, instance, migration):
904 version = self._ver(ctxt, '5.0')
905 client = self.router.client(ctxt)
906 cctxt = client.prepare(
907 server=_compute_host(migration.source_compute, instance),
908 version=version)
909 cctxt.cast(ctxt, 'live_migration_force_complete', instance=instance)
911 def live_migration_abort(self, ctxt, instance, migration_id):
912 version = self._ver(ctxt, '5.0')
913 cctxt = self.router.client(ctxt).prepare(
914 server=_compute_host(None, instance), version=version)
915 cctxt.cast(ctxt, 'live_migration_abort', instance=instance,
916 migration_id=migration_id)
918 def pause_instance(self, ctxt, instance):
919 version = self._ver(ctxt, '5.0')
920 cctxt = self.router.client(ctxt).prepare(
921 server=_compute_host(None, instance), version=version)
922 cctxt.cast(ctxt, 'pause_instance', instance=instance)
924 def post_live_migration_at_destination(self, ctxt, instance,
925 block_migration, host):
926 version = self._ver(ctxt, '5.0')
927 cctxt = self.router.client(ctxt).prepare(
928 server=host, version=version,
929 call_monitor_timeout=CONF.rpc_response_timeout,
930 timeout=CONF.long_rpc_timeout)
931 return cctxt.call(ctxt, 'post_live_migration_at_destination',
932 instance=instance, block_migration=block_migration)
934 # TODO(mriedem): Remove the unused block_migration argument in v6.0 of
935 # the compute RPC API.
936 def pre_live_migration(self, ctxt, instance, block_migration, disk,
937 host, migrate_data):
938 version = '6.0'
939 msg_args = {}
940 client = self.router.client(ctxt)
941 if not client.can_send_version(version): 941 ↛ 942line 941 didn't jump to line 942 because the condition on line 941 was never true
942 version = '5.0'
943 # We just need to honor the argument in the v5.0 RPC API method
944 msg_args['block_migration'] = None
945 cctxt = client.prepare(server=host, version=version,
946 timeout=CONF.long_rpc_timeout,
947 call_monitor_timeout=CONF.rpc_response_timeout)
948 return cctxt.call(ctxt, 'pre_live_migration',
949 instance=instance,
950 disk=disk, migrate_data=migrate_data,
951 **msg_args)
953 # TODO(mriedem): Drop compat for request_spec being a legacy dict in v6.0.
954 def prep_resize(self, ctxt, instance, image, flavor, host,
955 migration, request_spec, filter_properties, node,
956 clean_shutdown, host_list):
957 version = '6.0'
958 # TODO(mriedem): We should pass the ImageMeta object through to the
959 # compute but that also requires plumbing changes through the resize
960 # flow for other methods like resize_instance and finish_resize.
961 image_p = objects_base.obj_to_primitive(image)
962 msg_args = {'instance': instance,
963 'flavor': flavor,
964 'image': image_p,
965 'request_spec': request_spec,
966 'filter_properties': filter_properties,
967 'node': node,
968 'migration': migration,
969 'clean_shutdown': clean_shutdown,
970 'host_list': host_list}
971 client = self.router.client(ctxt)
972 if not client.can_send_version(version):
973 version = '5.1'
974 del msg_args['flavor']
975 msg_args['instance_type'] = flavor
976 if not client.can_send_version(version): 976 ↛ 980line 976 didn't jump to line 980 because the condition on line 976 was always true
977 version = '5.0'
978 msg_args['request_spec'] = (
979 request_spec.to_legacy_request_spec_dict())
980 cctxt = client.prepare(server=host, version=version)
981 cctxt.cast(ctxt, 'prep_resize', **msg_args)
983 def prep_snapshot_based_resize_at_dest(
984 self, ctxt, instance, flavor, nodename, migration, limits,
985 request_spec, destination):
986 """Performs pre-cross-cell resize resource claim on the dest host.
988 This runs on the destination host in a cross-cell resize operation
989 before the resize is actually started.
991 Performs a resize_claim for resources that are not claimed in placement
992 like PCI devices and NUMA topology.
994 Note that this is different from same-cell prep_resize in that this:
996 * Does not RPC cast to the source compute, that is orchestrated from
997 conductor.
998 * This does not reschedule on failure, conductor handles that since
999 conductor is synchronously RPC calling this method.
1001 :param ctxt: user auth request context
1002 :param instance: the instance being resized
1003 :param flavor: the flavor being resized to (unchanged for cold migrate)
1004 :param nodename: Name of the target compute node
1005 :param migration: nova.objects.Migration object for the operation
1006 :param limits: nova.objects.SchedulerLimits object of resource limits
1007 :param request_spec: nova.objects.RequestSpec object for the operation
1008 :param destination: possible target host for the cross-cell resize
1009 :returns: nova.objects.MigrationContext; the migration context created
1010 on the destination host during the resize_claim.
1011 :raises: nova.exception.MigrationPreCheckError if the pre-check
1012 validation fails for the given host selection or the destination
1013 compute service is too old for this method
1014 :raises: oslo_messaging.exceptions.MessagingTimeout if the pre-check
1015 RPC call times out
1016 """
1017 msg_args = {'instance': instance,
1018 'flavor': flavor,
1019 'nodename': nodename,
1020 'migration': migration,
1021 'limits': limits}
1022 version = self._ver(ctxt, '5.5')
1023 client = self.router.client(ctxt)
1024 if not client.can_send_version('6.0'):
1025 msg_args['request_spec'] = request_spec
1026 if not client.can_send_version(version):
1027 raise exception.MigrationPreCheckError(reason=_('Compute too old'))
1028 cctxt = client.prepare(server=destination, version=version,
1029 call_monitor_timeout=CONF.rpc_response_timeout,
1030 timeout=CONF.long_rpc_timeout)
1031 return cctxt.call(ctxt, 'prep_snapshot_based_resize_at_dest',
1032 **msg_args)
1034 def prep_snapshot_based_resize_at_source(
1035 self, ctxt, instance, migration, snapshot_id=None):
1036 """Prepares the instance at the source host for cross-cell resize
1038 Performs actions like powering off the guest, upload snapshot data if
1039 the instance is not volume-backed, disconnecting volumes, unplugging
1040 VIFs and activating the destination host port bindings.
1042 :param ctxt: user auth request context targeted at source cell
1043 :param instance: nova.objects.Instance; the instance being resized.
1044 The expected instance.task_state is "resize_migrating" when calling
1045 this method, and the expected task_state upon successful completion
1046 is "resize_migrated".
1047 :param migration: nova.objects.Migration object for the operation.
1048 The expected migration.status is "pre-migrating" when calling this
1049 method and the expected status upon successful completion is
1050 "post-migrating".
1051 :param snapshot_id: ID of the image snapshot to upload if not a
1052 volume-backed instance
1053 :raises: nova.exception.InstancePowerOffFailure if stopping the
1054 instance fails
1055 :raises: nova.exception.MigrationError if the source compute is too
1056 old to perform the operation
1057 :raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
1058 times out
1059 """
1060 version = self._ver(ctxt, '5.6')
1061 client = self.router.client(ctxt)
1062 if not client.can_send_version(version):
1063 raise exception.MigrationError(reason=_('Compute too old'))
1064 cctxt = client.prepare(server=_compute_host(None, instance),
1065 version=version,
1066 call_monitor_timeout=CONF.rpc_response_timeout,
1067 timeout=CONF.long_rpc_timeout)
1068 return cctxt.call(
1069 ctxt, 'prep_snapshot_based_resize_at_source',
1070 instance=instance, migration=migration, snapshot_id=snapshot_id)
1072 def reboot_instance(self, ctxt, instance, block_device_info,
1073 reboot_type):
1074 version = self._ver(ctxt, '5.0')
1075 cctxt = self.router.client(ctxt).prepare(
1076 server=_compute_host(None, instance), version=version)
1077 cctxt.cast(ctxt, 'reboot_instance',
1078 instance=instance,
1079 block_device_info=block_device_info,
1080 reboot_type=reboot_type)
1082 def rebuild_instance(
1083 self, ctxt, instance, new_pass, injected_files,
1084 image_ref, orig_image_ref, orig_sys_metadata, bdms,
1085 recreate, on_shared_storage, host, node,
1086 preserve_ephemeral, migration, limits, request_spec, accel_uuids,
1087 reimage_boot_volume, target_state):
1089 # NOTE(edleafe): compute nodes can only use the dict form of limits.
1090 if isinstance(limits, objects.SchedulerLimits): 1090 ↛ 1091line 1090 didn't jump to line 1091 because the condition on line 1090 was never true
1091 limits = limits.to_dict()
1093 msg_args = {
1094 'preserve_ephemeral': preserve_ephemeral,
1095 'migration': migration,
1096 'scheduled_node': node,
1097 'limits': limits,
1098 'request_spec': request_spec,
1099 'accel_uuids': accel_uuids,
1100 'reimage_boot_volume': reimage_boot_volume,
1101 'target_state': target_state,
1102 }
1103 version = '6.2'
1104 client = self.router.client(ctxt)
1105 if not client.can_send_version(version):
1106 if msg_args['target_state']:
1107 raise exception.UnsupportedRPCVersion(
1108 api="rebuild_instance",
1109 required="6.2")
1110 else:
1111 del msg_args['target_state']
1112 version = '6.1'
1113 if not client.can_send_version(version):
1114 if msg_args['reimage_boot_volume']:
1115 raise exception.NovaException(
1116 'Compute RPC version does not support '
1117 'reimage_boot_volume parameter.')
1118 else:
1119 del msg_args['reimage_boot_volume']
1120 version = self._ver(ctxt, '5.12')
1121 if not client.can_send_version(version):
1122 del msg_args['accel_uuids']
1123 version = '5.0'
1124 cctxt = client.prepare(server=_compute_host(host, instance),
1125 version=version)
1126 cctxt.cast(ctxt, 'rebuild_instance',
1127 instance=instance, new_pass=new_pass,
1128 injected_files=injected_files, image_ref=image_ref,
1129 orig_image_ref=orig_image_ref,
1130 orig_sys_metadata=orig_sys_metadata, bdms=bdms,
1131 recreate=recreate, on_shared_storage=on_shared_storage,
1132 **msg_args)
1134 def remove_fixed_ip_from_instance(self, ctxt, instance, address):
1135 version = self._ver(ctxt, '5.0')
1136 cctxt = self.router.client(ctxt).prepare(
1137 server=_compute_host(None, instance), version=version)
1138 cctxt.cast(ctxt, 'remove_fixed_ip_from_instance',
1139 instance=instance, address=address)
1141 def remove_volume_connection(
1142 self, ctxt, instance, volume_id, host,
1143 delete_attachment=False
1144 ):
1145 version = '6.3'
1146 client = self.router.client(ctxt)
1147 kwargs = {
1148 'instance': instance,
1149 'volume_id': volume_id,
1150 'delete_attachment': delete_attachment
1151 }
1152 if not client.can_send_version(version): 1152 ↛ 1153line 1152 didn't jump to line 1153 because the condition on line 1152 was never true
1153 kwargs.pop('delete_attachment')
1154 version = self._ver(ctxt, '5.0')
1156 cctxt = client.prepare(server=host, version=version)
1157 return cctxt.call(ctxt, 'remove_volume_connection', **kwargs)
1159 def rescue_instance(self, ctxt, instance, rescue_password,
1160 rescue_image_ref=None, clean_shutdown=True):
1161 version = self._ver(ctxt, '5.0')
1162 msg_args = {'rescue_password': rescue_password,
1163 'clean_shutdown': clean_shutdown,
1164 'rescue_image_ref': rescue_image_ref,
1165 'instance': instance,
1166 }
1167 cctxt = self.router.client(ctxt).prepare(
1168 server=_compute_host(None, instance), version=version)
1169 cctxt.cast(ctxt, 'rescue_instance', **msg_args)
1171 def resize_instance(self, ctxt, instance, migration, image, flavor,
1172 request_spec, clean_shutdown=True):
1173 version = '6.0'
1174 msg_args = {'instance': instance, 'migration': migration,
1175 'image': image,
1176 'flavor': flavor,
1177 'clean_shutdown': clean_shutdown,
1178 'request_spec': request_spec,
1179 }
1180 client = self.router.client(ctxt)
1182 if not client.can_send_version(version):
1183 version = self._ver(ctxt, '5.2')
1184 del msg_args['flavor']
1185 msg_args['instance_type'] = flavor
1187 if not client.can_send_version(version): 1187 ↛ 1191line 1187 didn't jump to line 1191 because the condition on line 1187 was always true
1188 msg_args.pop('request_spec')
1189 version = '5.0'
1191 cctxt = client.prepare(server=_compute_host(None, instance),
1192 version=version)
1193 cctxt.cast(ctxt, 'resize_instance', **msg_args)
1195 def resume_instance(self, ctxt, instance):
1196 version = self._ver(ctxt, '5.0')
1197 cctxt = self.router.client(ctxt).prepare(
1198 server=_compute_host(None, instance), version=version)
1199 cctxt.cast(ctxt, 'resume_instance', instance=instance)
1201 def revert_resize(self, ctxt, instance, migration, host, request_spec):
1203 msg_args = {
1204 'instance': instance,
1205 'migration': migration,
1206 'request_spec': request_spec,
1207 }
1209 client = self.router.client(ctxt)
1210 version = self._ver(ctxt, '5.2')
1212 if not client.can_send_version(version):
1213 msg_args.pop('request_spec')
1214 version = '5.0'
1216 cctxt = client.prepare(
1217 server=_compute_host(host, instance), version=version)
1218 cctxt.cast(ctxt, 'revert_resize', **msg_args)
1220 def revert_snapshot_based_resize_at_dest(self, ctxt, instance, migration):
1221 """Reverts a snapshot-based resize at the destination host.
1223 Cleans the guest from the destination compute service host hypervisor
1224 and related resources (ports, volumes) and frees resource usage from
1225 the compute service on that host.
1227 This is a synchronous RPC call using the ``long_rpc_timeout``
1228 configuration option.
1230 :param ctxt: nova auth request context targeted at the target cell
1231 :param instance: Instance object whose vm_state is "resized" and
1232 task_state is "resize_reverting".
1233 :param migration: Migration object whose status is "reverting".
1234 :raises: nova.exception.MigrationError if the destination compute
1235 service is too old to perform the operation
1236 :raises: oslo_messaging.exceptions.MessagingTimeout if the RPC call
1237 times out
1238 """
1239 version = self._ver(ctxt, '5.9')
1240 client = self.router.client(ctxt)
1241 if not client.can_send_version(version):
1242 raise exception.MigrationError(reason=_('Compute too old'))
1243 cctxt = client.prepare(server=migration.dest_compute,
1244 version=version,
1245 call_monitor_timeout=CONF.rpc_response_timeout,
1246 timeout=CONF.long_rpc_timeout)
1247 return cctxt.call(
1248 ctxt, 'revert_snapshot_based_resize_at_dest',
1249 instance=instance, migration=migration)
1251 def rollback_live_migration_at_destination(self, ctxt, instance, host,
1252 destroy_disks,
1253 migrate_data):
1254 version = self._ver(ctxt, '5.0')
1255 client = self.router.client(ctxt)
1256 cctxt = client.prepare(server=host, version=version)
1257 cctxt.cast(ctxt, 'rollback_live_migration_at_destination',
1258 instance=instance, destroy_disks=destroy_disks,
1259 migrate_data=migrate_data)
1261 # TODO(sbauza): Remove this when we bump the compute API to v6.0
1262 def supports_numa_live_migration(self, ctxt):
1263 """Returns whether we can send 5.3, needed for NUMA live migration.
1264 """
1265 client = self.router.client(ctxt)
1266 version = self._ver(ctxt, '5.3')
1267 return client.can_send_version(version)
1269 def drop_move_claim_at_destination(self, ctxt, instance, host):
1270 """Called by the source of a live migration that's being rolled back.
1271 This is a call not because we care about the return value, but because
1272 dropping the move claim depends on instance.migration_context being
1273 set, and we drop the migration context on the source. Thus, to avoid
1274 races, we call the destination synchronously to make sure it's done
1275 dropping the move claim before we drop the migration context from the
1276 instance.
1277 """
1278 version = self._ver(ctxt, '5.3')
1279 client = self.router.client(ctxt)
1280 cctxt = client.prepare(server=host, version=version)
1281 cctxt.call(ctxt, 'drop_move_claim_at_destination', instance=instance)
1283 def set_admin_password(self, ctxt, instance, new_pass):
1284 version = self._ver(ctxt, '5.0')
1285 cctxt = self.router.client(ctxt).prepare(
1286 server=_compute_host(None, instance), version=version)
1287 return cctxt.call(ctxt, 'set_admin_password',
1288 instance=instance, new_pass=new_pass)
1290 def set_host_enabled(self, ctxt, host, enabled):
1291 version = self._ver(ctxt, '5.0')
1292 cctxt = self.router.client(ctxt).prepare(
1293 server=host, version=version,
1294 call_monitor_timeout=CONF.rpc_response_timeout,
1295 timeout=CONF.long_rpc_timeout)
1296 return cctxt.call(ctxt, 'set_host_enabled', enabled=enabled)
1298 def swap_volume(self, ctxt, instance, old_volume_id, new_volume_id,
1299 new_attachment_id):
1300 version = self._ver(ctxt, '5.0')
1301 client = self.router.client(ctxt)
1302 kwargs = dict(instance=instance,
1303 old_volume_id=old_volume_id,
1304 new_volume_id=new_volume_id,
1305 new_attachment_id=new_attachment_id)
1306 cctxt = client.prepare(
1307 server=_compute_host(None, instance), version=version)
1308 cctxt.cast(ctxt, 'swap_volume', **kwargs)
1310 def get_host_uptime(self, ctxt, host):
1311 version = self._ver(ctxt, '5.0')
1312 cctxt = self.router.client(ctxt).prepare(
1313 server=host, version=version)
1314 return cctxt.call(ctxt, 'get_host_uptime')
1316 def reserve_block_device_name(self, ctxt, instance, device, volume_id,
1317 disk_bus, device_type, tag,
1318 multiattach):
1319 kw = {'instance': instance, 'device': device,
1320 'volume_id': volume_id, 'disk_bus': disk_bus,
1321 'device_type': device_type, 'tag': tag,
1322 'multiattach': multiattach}
1323 version = self._ver(ctxt, '5.0')
1324 client = self.router.client(ctxt)
1325 cctxt = client.prepare(server=_compute_host(None, instance),
1326 version=version,
1327 call_monitor_timeout=CONF.rpc_response_timeout,
1328 timeout=CONF.long_rpc_timeout)
1329 return cctxt.call(ctxt, 'reserve_block_device_name', **kw)
1331 def backup_instance(self, ctxt, instance, image_id, backup_type,
1332 rotation):
1333 version = self._ver(ctxt, '5.0')
1334 cctxt = self.router.client(ctxt).prepare(
1335 server=_compute_host(None, instance), version=version)
1336 cctxt.cast(ctxt, 'backup_instance',
1337 instance=instance,
1338 image_id=image_id,
1339 backup_type=backup_type,
1340 rotation=rotation)
1342 def snapshot_instance(self, ctxt, instance, image_id):
1343 version = self._ver(ctxt, '5.0')
1344 cctxt = self.router.client(ctxt).prepare(
1345 server=_compute_host(None, instance), version=version)
1346 cctxt.cast(ctxt, 'snapshot_instance',
1347 instance=instance,
1348 image_id=image_id)
1350 def start_instance(self, ctxt, instance):
1351 version = self._ver(ctxt, '5.0')
1352 cctxt = self.router.client(ctxt).prepare(
1353 server=_compute_host(None, instance), version=version)
1354 cctxt.cast(ctxt, 'start_instance', instance=instance)
1356 def stop_instance(self, ctxt, instance, do_cast=True, clean_shutdown=True):
1357 msg_args = {'instance': instance,
1358 'clean_shutdown': clean_shutdown}
1359 version = self._ver(ctxt, '5.0')
1360 cctxt = self.router.client(ctxt).prepare(
1361 server=_compute_host(None, instance), version=version)
1362 rpc_method = cctxt.cast if do_cast else cctxt.call
1363 return rpc_method(ctxt, 'stop_instance', **msg_args)
1365 def suspend_instance(self, ctxt, instance):
1366 version = self._ver(ctxt, '5.0')
1367 cctxt = self.router.client(ctxt).prepare(
1368 server=_compute_host(None, instance), version=version)
1369 cctxt.cast(ctxt, 'suspend_instance', instance=instance)
1371 def terminate_instance(self, ctxt, instance, bdms):
1372 client = self.router.client(ctxt)
1373 version = self._ver(ctxt, '5.0')
1374 cctxt = client.prepare(
1375 server=_compute_host(None, instance), version=version)
1376 cctxt.cast(ctxt, 'terminate_instance', instance=instance, bdms=bdms)
1378 def unpause_instance(self, ctxt, instance):
1379 version = self._ver(ctxt, '5.0')
1380 cctxt = self.router.client(ctxt).prepare(
1381 server=_compute_host(None, instance), version=version)
1382 cctxt.cast(ctxt, 'unpause_instance', instance=instance)
1384 def unrescue_instance(self, ctxt, instance):
1385 version = self._ver(ctxt, '5.0')
1386 cctxt = self.router.client(ctxt).prepare(
1387 server=_compute_host(None, instance), version=version)
1388 cctxt.cast(ctxt, 'unrescue_instance', instance=instance)
1390 def soft_delete_instance(self, ctxt, instance):
1391 client = self.router.client(ctxt)
1392 version = self._ver(ctxt, '5.0')
1393 cctxt = client.prepare(
1394 server=_compute_host(None, instance), version=version)
1395 cctxt.cast(ctxt, 'soft_delete_instance', instance=instance)
1397 def restore_instance(self, ctxt, instance):
1398 version = self._ver(ctxt, '5.0')
1399 cctxt = self.router.client(ctxt).prepare(
1400 server=_compute_host(None, instance), version=version)
1401 cctxt.cast(ctxt, 'restore_instance', instance=instance)
1403 def shelve_instance(self, ctxt, instance, image_id=None,
1404 clean_shutdown=True, accel_uuids=None):
1405 msg_kwargs = {
1406 'instance': instance,
1407 'image_id': image_id,
1408 'clean_shutdown': clean_shutdown,
1409 'accel_uuids': accel_uuids,
1410 }
1411 client = self.router.client(ctxt)
1412 version = self._ver(ctxt, '5.13')
1413 if not client.can_send_version(version):
1414 if accel_uuids: 1414 ↛ 1415line 1414 didn't jump to line 1415 because the condition on line 1414 was never true
1415 LOG.error("Shelve with accelerators is not supported as "
1416 "RPC version is too old.")
1417 raise exception.ForbiddenWithAccelerators()
1418 else:
1419 msg_kwargs.pop('accel_uuids')
1420 version = '5.0'
1421 cctxt = client.prepare(
1422 server=_compute_host(None, instance), version=version)
1423 cctxt.cast(ctxt, 'shelve_instance', **msg_kwargs)
1425 def shelve_offload_instance(self, ctxt, instance,
1426 clean_shutdown=True, accel_uuids=None):
1427 msg_kwargs = {
1428 'instance': instance,
1429 'clean_shutdown': clean_shutdown,
1430 'accel_uuids': accel_uuids,
1431 }
1432 client = self.router.client(ctxt)
1433 version = self._ver(ctxt, '5.13')
1434 if not client.can_send_version(version):
1435 msg_kwargs.pop('accel_uuids')
1436 version = '5.0'
1437 cctxt = client.prepare(
1438 server=_compute_host(None, instance), version=version)
1439 cctxt.cast(ctxt, 'shelve_offload_instance', **msg_kwargs)
1441 def unshelve_instance(self, ctxt, instance, host, request_spec, image=None,
1442 filter_properties=None, node=None, accel_uuids=None):
1443 version = self._ver(ctxt, '5.13')
1444 msg_kwargs = {
1445 'instance': instance,
1446 'image': image,
1447 'filter_properties': filter_properties,
1448 'node': node,
1449 'request_spec': request_spec,
1450 'accel_uuids': accel_uuids,
1451 }
1453 client = self.router.client(ctxt)
1455 if not client.can_send_version(version):
1456 msg_kwargs.pop('accel_uuids')
1457 version = '5.2'
1458 if not client.can_send_version(version):
1459 msg_kwargs.pop('request_spec')
1460 version = '5.0'
1462 cctxt = client.prepare(server=host, version=version)
1463 cctxt.cast(ctxt, 'unshelve_instance', **msg_kwargs)
1465 def volume_snapshot_create(self, ctxt, instance, volume_id,
1466 create_info):
1467 version = self._ver(ctxt, '5.0')
1468 cctxt = self.router.client(ctxt).prepare(
1469 server=_compute_host(None, instance), version=version)
1470 cctxt.cast(ctxt, 'volume_snapshot_create', instance=instance,
1471 volume_id=volume_id, create_info=create_info)
1473 def volume_snapshot_delete(self, ctxt, instance, volume_id, snapshot_id,
1474 delete_info):
1475 version = self._ver(ctxt, '5.0')
1476 cctxt = self.router.client(ctxt).prepare(
1477 server=_compute_host(None, instance), version=version)
1478 cctxt.cast(ctxt, 'volume_snapshot_delete', instance=instance,
1479 volume_id=volume_id, snapshot_id=snapshot_id,
1480 delete_info=delete_info)
1482 def allow_share(self, ctxt, instance, share_mapping):
1483 version = '6.4'
1484 client = self.router.client(ctxt)
1485 if not client.can_send_version(version): 1485 ↛ 1486line 1485 didn't jump to line 1486 because the condition on line 1485 was never true
1486 raise exception.UnsupportedRPCVersion(
1487 api="allow_share",
1488 required=version)
1489 cctxt = self.router.client(ctxt).prepare(
1490 server=_compute_host(None, instance), version=version)
1491 cctxt.cast(
1492 ctxt,
1493 "allow_share",
1494 instance=instance,
1495 share_mapping=share_mapping
1496 )
1498 def deny_share(self, ctxt, instance, share_mapping):
1499 version = '6.4'
1500 client = self.router.client(ctxt)
1501 if not client.can_send_version(version): 1501 ↛ 1502line 1501 didn't jump to line 1502 because the condition on line 1501 was never true
1502 raise exception.UnsupportedRPCVersion(
1503 api="deny_share",
1504 required=version)
1505 cctxt = self.router.client(ctxt).prepare(
1506 server=_compute_host(None, instance), version=version)
1507 cctxt.cast(
1508 ctxt,
1509 "deny_share",
1510 instance=instance,
1511 share_mapping=share_mapping,
1512 )
1514 def external_instance_event(self, ctxt, instances, events, host=None):
1515 instance = instances[0]
1516 version = self._ver(ctxt, '5.0')
1517 cctxt = self.router.client(ctxt).prepare(
1518 server=_compute_host(host, instance),
1519 version=version)
1520 cctxt.cast(ctxt, 'external_instance_event', instances=instances,
1521 events=events)
1523 def build_and_run_instance(self, ctxt, instance, host, image, request_spec,
1524 filter_properties, admin_password=None, injected_files=None,
1525 requested_networks=None, security_groups=None,
1526 block_device_mapping=None, node=None, limits=None,
1527 host_list=None, accel_uuids=None):
1528 # NOTE(edleafe): compute nodes can only use the dict form of limits.
1529 if isinstance(limits, objects.SchedulerLimits): 1529 ↛ 1530line 1529 didn't jump to line 1530 because the condition on line 1529 was never true
1530 limits = limits.to_dict()
1531 kwargs = {"instance": instance,
1532 "image": image,
1533 "request_spec": request_spec,
1534 "filter_properties": filter_properties,
1535 "admin_password": admin_password,
1536 "injected_files": injected_files,
1537 "requested_networks": requested_networks,
1538 "security_groups": security_groups,
1539 "block_device_mapping": block_device_mapping,
1540 "node": node,
1541 "limits": limits,
1542 "host_list": host_list,
1543 "accel_uuids": accel_uuids,
1544 }
1545 client = self.router.client(ctxt)
1546 version = self._ver(ctxt, '5.11')
1547 if not client.can_send_version(version):
1548 kwargs.pop('accel_uuids')
1549 version = '5.0'
1550 cctxt = client.prepare(server=host, version=version)
1551 cctxt.cast(ctxt, 'build_and_run_instance', **kwargs)
1553 def quiesce_instance(self, ctxt, instance):
1554 version = self._ver(ctxt, '5.0')
1555 cctxt = self.router.client(ctxt).prepare(
1556 server=_compute_host(None, instance), version=version)
1557 return cctxt.call(ctxt, 'quiesce_instance', instance=instance)
1559 def unquiesce_instance(self, ctxt, instance, mapping=None):
1560 version = self._ver(ctxt, '5.0')
1561 cctxt = self.router.client(ctxt).prepare(
1562 server=_compute_host(None, instance), version=version)
1563 cctxt.cast(ctxt, 'unquiesce_instance', instance=instance,
1564 mapping=mapping)
1566 def trigger_crash_dump(self, ctxt, instance):
1567 version = self._ver(ctxt, '5.0')
1568 client = self.router.client(ctxt)
1569 cctxt = client.prepare(server=_compute_host(None, instance),
1570 version=version)
1571 cctxt.cast(ctxt, "trigger_crash_dump", instance=instance)
1573 def cache_images(self, ctxt, host, image_ids):
1574 version = self._ver(ctxt, '5.4')
1575 client = self.router.client(ctxt)
1576 if not client.can_send_version(version):
1577 raise exception.NovaException('Compute RPC version pin does not '
1578 'allow cache_images() to be called')
1579 # This is a potentially very long-running call, so we provide the
1580 # two timeout values which enables the call monitor in oslo.messaging
1581 # so that this can run for extended periods.
1582 cctxt = client.prepare(server=host, version=version,
1583 call_monitor_timeout=CONF.rpc_response_timeout,
1584 timeout=CONF.long_rpc_timeout)
1585 return cctxt.call(ctxt, 'cache_images', image_ids=image_ids)