Coverage for nova/compute/rpcapi.py: 94%

538 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-04-24 11:16 +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. 

13 

14""" 

15Client side of the compute RPC API. 

16""" 

17 

18from oslo_concurrency import lockutils 

19from oslo_log import log as logging 

20import oslo_messaging as messaging 

21from oslo_utils import excutils 

22 

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 

32 

33CONF = nova.conf.CONF 

34RPC_TOPIC = "compute" 

35 

36LOG = logging.getLogger(__name__) 

37LAST_VERSION = None 

38NO_COMPUTES_WARNING = False 

39# Global for ComputeAPI.router. 

40_ROUTER = None 

41 

42 

43def reset_globals(): 

44 global NO_COMPUTES_WARNING 

45 global LAST_VERSION 

46 global _ROUTER 

47 

48 NO_COMPUTES_WARNING = False 

49 LAST_VERSION = None 

50 _ROUTER = None 

51 

52 

53def _compute_host(host, instance): 

54 '''Get the destination host for a message. 

55 

56 :param host: explicit host to send the message to. 

57 :param instance: If an explicit host was not specified, use 

58 instance['host'] 

59 

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 

70 

71 

72@profiler.trace_cls("rpc") 

73class ComputeAPI(object): 

74 '''Client side of the compute rpc API. 

75 

76 API version history: 

77 

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() 

156 

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() 

189 

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. 

193 

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 

223 

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. 

227 

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 

231 

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. 

261 

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. 

265 

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 

281 

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. 

285 

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 

293 

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 

297 

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. 

301 

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() 

309 

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 

313 

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 

325 

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 

329 

330 * 4.12 - Remove migration_id from live_migration_force_complete 

331 * 4.13 - Make get_instance_diagnostics send an instance object 

332 

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 

336 

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. 

344 

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. 

348 

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() 

357 

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. 

362 

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() 

386 

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. 

391 

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 ''' 

410 

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 } 

436 

437 @property 

438 def router(self): 

439 """Provides singleton access to nova.rpc.ClientRouter for this API 

440 

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() 

457 

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) 

461 

462 default_client = self.get_client(target, version_cap, 

463 serializer) 

464 _ROUTER = rpc.ClientRouter(default_client) 

465 return _ROUTER 

466 

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 

482 

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 

489 

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') 

512 

513 history = service_obj.SERVICE_VERSION_HISTORY 

514 

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'] 

528 

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 

549 

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) 

565 

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) 

572 

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) 

583 

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) 

589 

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) 

610 

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) 

619 

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) 

631 

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) 

641 

642 def confirm_snapshot_based_resize_at_source( 

643 self, ctxt, instance, migration): 

644 """Confirms a snapshot-based resize on the source host. 

645 

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. 

649 

650 Deletes the allocations held by the migration consumer against the 

651 source compute node resource provider. 

652 

653 This is a synchronous RPC call using the ``long_rpc_timeout`` 

654 configuration option. 

655 

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) 

676 

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) 

683 

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) 

692 

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 } 

702 

703 client = self.router.client(ctxt) 

704 version = self._ver(ctxt, '5.2') 

705 

706 if not client.can_send_version(version): 

707 msg_args.pop('request_spec') 

708 version = '5.0' 

709 

710 cctxt = client.prepare( 

711 server=host, version=version) 

712 cctxt.cast(ctxt, 'finish_resize', **msg_args) 

713 

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 } 

721 

722 client = self.router.client(ctxt) 

723 version = self._ver(ctxt, '5.2') 

724 

725 if not client.can_send_version(version): 

726 msg_args.pop('request_spec') 

727 version = '5.0' 

728 

729 cctxt = client.prepare( 

730 server=host, version=version) 

731 cctxt.cast(ctxt, 'finish_revert_resize', **msg_args) 

732 

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. 

736 

737 Sets up block devices and networking on the destination compute and 

738 spawns the guest. 

739 

740 This is a synchronous RPC call using the ``long_rpc_timeout`` 

741 configuration option. 

742 

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) 

775 

776 def finish_revert_snapshot_based_resize_at_source( 

777 self, ctxt, instance, migration): 

778 """Reverts a snapshot-based resize at the source host. 

779 

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. 

782 

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. 

786 

787 This is a synchronous RPC call using the ``long_rpc_timeout`` 

788 configuration option. 

789 

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) 

810 

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) 

817 

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) 

823 

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) 

830 

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) 

837 

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) 

844 

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) 

851 

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) 

858 

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) 

866 

867 def host_maintenance_mode(self, ctxt, host, host_param, mode): 

868 '''Set host maintenance mode 

869 

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) 

881 

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) 

887 

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) 

893 

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) 

902 

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) 

910 

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) 

917 

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) 

923 

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) 

933 

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) 

952 

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) 

982 

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. 

987 

988 This runs on the destination host in a cross-cell resize operation 

989 before the resize is actually started. 

990 

991 Performs a resize_claim for resources that are not claimed in placement 

992 like PCI devices and NUMA topology. 

993 

994 Note that this is different from same-cell prep_resize in that this: 

995 

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. 

1000 

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) 

1033 

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 

1037 

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. 

1041 

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) 

1071 

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) 

1081 

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): 

1088 

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() 

1092 

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) 

1133 

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) 

1140 

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') 

1155 

1156 cctxt = client.prepare(server=host, version=version) 

1157 return cctxt.call(ctxt, 'remove_volume_connection', **kwargs) 

1158 

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) 

1170 

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) 

1181 

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 

1186 

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' 

1190 

1191 cctxt = client.prepare(server=_compute_host(None, instance), 

1192 version=version) 

1193 cctxt.cast(ctxt, 'resize_instance', **msg_args) 

1194 

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) 

1200 

1201 def revert_resize(self, ctxt, instance, migration, host, request_spec): 

1202 

1203 msg_args = { 

1204 'instance': instance, 

1205 'migration': migration, 

1206 'request_spec': request_spec, 

1207 } 

1208 

1209 client = self.router.client(ctxt) 

1210 version = self._ver(ctxt, '5.2') 

1211 

1212 if not client.can_send_version(version): 

1213 msg_args.pop('request_spec') 

1214 version = '5.0' 

1215 

1216 cctxt = client.prepare( 

1217 server=_compute_host(host, instance), version=version) 

1218 cctxt.cast(ctxt, 'revert_resize', **msg_args) 

1219 

1220 def revert_snapshot_based_resize_at_dest(self, ctxt, instance, migration): 

1221 """Reverts a snapshot-based resize at the destination host. 

1222 

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. 

1226 

1227 This is a synchronous RPC call using the ``long_rpc_timeout`` 

1228 configuration option. 

1229 

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) 

1250 

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) 

1260 

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) 

1268 

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) 

1282 

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) 

1289 

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) 

1297 

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) 

1309 

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') 

1315 

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) 

1330 

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) 

1341 

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) 

1349 

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) 

1355 

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) 

1364 

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) 

1370 

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) 

1377 

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) 

1383 

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) 

1389 

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) 

1396 

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) 

1402 

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) 

1424 

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) 

1440 

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 } 

1452 

1453 client = self.router.client(ctxt) 

1454 

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' 

1461 

1462 cctxt = client.prepare(server=host, version=version) 

1463 cctxt.cast(ctxt, 'unshelve_instance', **msg_kwargs) 

1464 

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) 

1472 

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) 

1481 

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 ) 

1497 

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 ) 

1513 

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) 

1522 

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) 

1552 

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) 

1558 

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) 

1565 

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) 

1572 

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)