Coverage for nova/virt/libvirt/blockinfo.py: 97%

287 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-04-24 11:16 +0000

1# Copyright (C) 2012-2013 Red Hat, Inc. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); you may 

4# not use this file except in compliance with the License. You may obtain 

5# a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

12# License for the specific language governing permissions and limitations 

13# under the License. 

14 

15""" 

16Handling of block device information and mapping. 

17 

18This module contains helper methods for interpreting the block 

19device information and determining the suitable mapping to 

20guest devices and libvirt XML. 

21 

22Throughout these methods there are a number of standard 

23variables / types used 

24 

25 * 'mapping': a dict contains the storage device mapping. 

26 

27 For the default disk types it will contain the following 

28 keys & values: 

29 

30 'disk' -> disk_info 

31 'disk.rescue' -> disk_info 

32 'disk.local' -> disk_info 

33 'disk.swap' -> disk_info 

34 'disk.config' -> disk_info 

35 

36 If any of the default disks are overridden by the block 

37 device info mappings, the hash value will be None 

38 

39 For any ephemeral device there will also be a dict entry 

40 

41 'disk.eph$NUM' -> disk_info 

42 

43 For any volume device there will also be a dict entry: 

44 

45 $path -> disk_info 

46 

47 Finally a special key will refer to the root device: 

48 

49 'root' -> disk_info 

50 

51 

52 * 'disk_info': a dict specifying disk configuration 

53 

54 It contains the following 3 required fields 

55 

56 bus (disk_bus), dev (disk_dev), type (device_type) 

57 

58 and possibly these optional fields: ('format', 'boot_index') 

59 

60 * 'disk_bus': the guest bus type ('ide', 'virtio', 'scsi', etc) 

61 

62 * 'disk_dev': the device name 'vda', 'hdc', 'sdf', etc 

63 

64 * 'device_type': type of device eg 'disk', 'cdrom', 'floppy' 

65 

66 * 'format': Which format to apply to the device if applicable 

67 

68 * 'boot_index': Number designating the boot order of the device 

69 

70""" 

71 

72import copy 

73import itertools 

74import operator 

75 

76from oslo_config import cfg 

77from oslo_serialization import jsonutils 

78 

79 

80from nova import block_device 

81from nova import exception 

82from nova.i18n import _ 

83from nova.objects import base as obj_base 

84from nova.objects import fields as obj_fields 

85from nova.virt import configdrive 

86from nova.virt import driver 

87from nova.virt.libvirt import utils as libvirt_utils 

88from nova.virt import osinfo 

89 

90CONF = cfg.CONF 

91 

92BOOT_DEV_FOR_TYPE = {'disk': 'hd', 'cdrom': 'cdrom', 'floppy': 'fd', 

93 'lun': 'hd'} 

94# NOTE(aspiers): If you change this, don't forget to update the docs and 

95# metadata for hw_*_bus in glance. 

96SUPPORTED_DEVICE_BUSES = { 

97 'qemu': ['virtio', 'scsi', 'ide', 'usb', 'fdc', 'sata'], 

98 'kvm': ['virtio', 'scsi', 'ide', 'usb', 'fdc', 'sata'], 

99 'lxc': ['lxc'], 

100 'parallels': ['ide', 'scsi'], 

101 # we no longer support UML or Xen, but we keep track of their bus types so 

102 # we can reject them for other virt types 

103 'xen': ['xen', 'ide'], 

104 'uml': ['uml'], 

105} 

106SUPPORTED_DEVICE_TYPES = ('disk', 'cdrom', 'floppy', 'lun') 

107 

108 

109def has_disk_dev(mapping, disk_dev): 

110 """Determine if a disk device name has already been used. 

111 

112 Looks at all the keys in mapping to see if any 

113 corresponding disk_info tuple has a device name 

114 matching disk_dev 

115 

116 Returns True if the disk_dev is in use. 

117 """ 

118 

119 for disk in mapping: 

120 info = mapping[disk] 

121 if info['dev'] == disk_dev: 

122 return True 

123 return False 

124 

125 

126def get_dev_prefix_for_disk_bus(disk_bus): 

127 """Determine the dev prefix for a disk bus. 

128 

129 Determine the dev prefix to be combined 

130 with a disk number to fix a disk_dev. 

131 eg 'hd' for 'ide' bus can be used to 

132 form a disk dev 'hda' 

133 

134 Returns the dev prefix or raises an 

135 exception if the disk bus is unknown. 

136 """ 

137 

138 if CONF.libvirt.disk_prefix: 

139 return CONF.libvirt.disk_prefix 

140 if disk_bus == "ide": 

141 return "hd" 

142 elif disk_bus == "virtio": 

143 return "vd" 

144 elif disk_bus == "scsi": 

145 return "sd" 

146 elif disk_bus == "usb": 

147 return "sd" 

148 elif disk_bus == "fdc": 

149 return "fd" 

150 elif disk_bus == "lxc": 

151 return None 

152 elif disk_bus == "sata": 152 ↛ 155line 152 didn't jump to line 155 because the condition on line 152 was always true

153 return "sd" 

154 else: 

155 raise exception.InternalError( 

156 _("Unable to determine disk prefix for %s") % 

157 disk_bus) 

158 

159 

160def get_dev_count_for_disk_bus(disk_bus): 

161 """Determine the number disks supported. 

162 

163 Determine how many disks can be supported in 

164 a single VM for a particular disk bus. 

165 

166 Returns the number of disks supported or None 

167 if there is no limit. 

168 """ 

169 

170 if disk_bus == "ide": 

171 return 4 

172 else: 

173 if CONF.compute.max_disk_devices_to_attach < 0: 173 ↛ 175line 173 didn't jump to line 175 because the condition on line 173 was always true

174 return None 

175 return CONF.compute.max_disk_devices_to_attach 

176 

177 

178def find_disk_dev_for_disk_bus(mapping, bus, 

179 assigned_devices=None): 

180 """Identify a free disk dev name for a bus. 

181 

182 Determines the possible disk dev names for 

183 the bus, and then checks them in order until 

184 it identifies one that is not yet used in the 

185 disk mapping. 

186 

187 Returns the chosen disk_dev name, or raises an 

188 exception if none is available. 

189 """ 

190 

191 dev_prefix = get_dev_prefix_for_disk_bus(bus) 

192 if dev_prefix is None: 

193 return None 

194 

195 if assigned_devices is None: 

196 assigned_devices = [] 

197 

198 max_dev = get_dev_count_for_disk_bus(bus) 

199 

200 idx = 0 

201 while True: 

202 if max_dev is not None and idx >= max_dev: 

203 raise exception.TooManyDiskDevices(maximum=max_dev) 

204 disk_dev = block_device.generate_device_name(dev_prefix, idx) 

205 if not has_disk_dev(mapping, disk_dev): 

206 if disk_dev not in assigned_devices: 

207 return disk_dev 

208 idx += 1 

209 

210 raise exception.TooManyDiskDevices(maximum=max_dev) 

211 

212 

213def is_disk_bus_valid_for_virt(virt_type, disk_bus): 

214 if virt_type not in SUPPORTED_DEVICE_BUSES: 214 ↛ 215line 214 didn't jump to line 215 because the condition on line 214 was never true

215 raise exception.UnsupportedVirtType(virt=virt_type) 

216 return disk_bus in SUPPORTED_DEVICE_BUSES[virt_type] 

217 

218 

219def get_disk_bus_for_device_type(instance, 

220 virt_type, 

221 image_meta, 

222 device_type="disk"): 

223 """Determine the best disk bus to use for a device type. 

224 

225 Considering the currently configured virtualization type, return the 

226 optimal disk_bus to use for a given device type. For example, for a disk 

227 on KVM it will return 'virtio', while for a CDROM, it will return 'ide' 

228 for the 'pc' machine type on x86_64, 'sata' for the 'q35' machine type on 

229 x86_64 and 'scsi' on ppc64. 

230 

231 Returns the disk_bus, or returns None if the device type is not supported 

232 for this virtualization 

233 """ 

234 

235 # Prefer a disk bus set against the image first of all 

236 if device_type == "disk": 

237 disk_bus = osinfo.HardwareProperties(image_meta).disk_model 

238 else: 

239 key = "hw_" + device_type + "_bus" 

240 disk_bus = image_meta.properties.get(key) 

241 if disk_bus is not None: 

242 if not is_disk_bus_valid_for_virt(virt_type, disk_bus): 

243 raise exception.UnsupportedHardware(model=disk_bus, 

244 virt=virt_type) 

245 return disk_bus 

246 

247 # Otherwise pick a hypervisor default disk bus 

248 if virt_type in ("qemu", "kvm"): 

249 if device_type == "cdrom": 

250 guestarch = libvirt_utils.get_arch(image_meta) 

251 if guestarch in ( 

252 obj_fields.Architecture.PPC, 

253 obj_fields.Architecture.PPC64, 

254 obj_fields.Architecture.PPCLE, 

255 obj_fields.Architecture.PPC64LE, 

256 obj_fields.Architecture.S390, 

257 obj_fields.Architecture.S390X, 

258 obj_fields.Architecture.AARCH64): 

259 return "scsi" 

260 machine_type = libvirt_utils.get_machine_type(image_meta) 

261 # NOTE(lyarwood): We can't be any more explicit here as QEMU 

262 # provides a version of the Q35 machine type per release. 

263 # Additionally downstream distributions can also provide their own. 

264 if machine_type and 'q35' in machine_type: 

265 # NOTE(lyarwood): The Q35 machine type does not provide an IDE 

266 # bus and as such we must use a SATA bus for cdroms. 

267 return "sata" 

268 else: 

269 return "ide" 

270 elif device_type == "disk": 

271 return "virtio" 

272 elif device_type == "floppy": 272 ↛ 285line 272 didn't jump to line 285 because the condition on line 272 was always true

273 return "fdc" 

274 elif virt_type == "lxc": 

275 return "lxc" 

276 elif virt_type == "parallels": 

277 if device_type == "cdrom": 

278 return "ide" 

279 elif device_type == "disk": 279 ↛ 285line 279 didn't jump to line 285 because the condition on line 279 was always true

280 return "scsi" 

281 else: 

282 # If virt-type not in list then it is unsupported 

283 raise exception.UnsupportedVirtType(virt=virt_type) 

284 

285 return None 

286 

287 

288def get_disk_bus_for_disk_dev(virt_type, disk_dev): 

289 """Determine the disk bus for a disk device. 

290 

291 Given a disk device like 'hda' or 'sdf', guess what the most appropriate 

292 disk bus is for the currently configured virtualization technology 

293 

294 :return: The preferred disk bus for the given disk prefix. 

295 :raises: InternalError if the disk device prefix is unknown. 

296 """ 

297 

298 if disk_dev.startswith('hd'): 

299 return "ide" 

300 elif disk_dev.startswith('sd'): 

301 # Reverse mapping 'sd' is not reliable 

302 # there are many possible mappings. So 

303 # this picks the most likely mappings 

304 return "scsi" 

305 elif disk_dev.startswith('vd'): 

306 return "virtio" 

307 elif disk_dev.startswith('fd'): 

308 return "fdc" 

309 else: 

310 msg = _("Unable to determine disk bus for '%s'") % disk_dev[:1] 

311 raise exception.InternalError(msg) 

312 

313 

314def get_next_disk_info(mapping, disk_bus, 

315 device_type='disk', 

316 boot_index=None, 

317 assigned_devices=None): 

318 """Determine the disk info for the next device on disk_bus. 

319 

320 Considering the disks already listed in the disk mapping, 

321 determine the next available disk dev that can be assigned 

322 for the disk bus. 

323 

324 Returns the disk_info for the next available disk. 

325 """ 

326 

327 disk_dev = find_disk_dev_for_disk_bus(mapping, 

328 disk_bus, 

329 assigned_devices) 

330 info = {'bus': disk_bus, 

331 'dev': disk_dev, 

332 'type': device_type} 

333 

334 if boot_index is not None and boot_index >= 0: 

335 info['boot_index'] = str(boot_index) 

336 

337 return info 

338 

339 

340def get_eph_disk(index): 

341 return 'disk.eph' + str(index) 

342 

343 

344def get_config_drive_type(): 

345 """Determine the type of config drive. 

346 

347 If config_drive_format is set to iso9660 then the config drive will 

348 be 'cdrom', otherwise 'disk'. 

349 

350 Returns a string indicating the config drive type. 

351 """ 

352 

353 if CONF.config_drive_format == 'iso9660': 

354 config_drive_type = 'cdrom' 

355 elif CONF.config_drive_format == 'vfat': 355 ↛ 358line 355 didn't jump to line 358 because the condition on line 355 was always true

356 config_drive_type = 'disk' 

357 else: 

358 raise exception.ConfigDriveUnknownFormat( 

359 format=CONF.config_drive_format) 

360 

361 return config_drive_type 

362 

363 

364def get_info_from_bdm(instance, virt_type, image_meta, bdm, 

365 mapping=None, disk_bus=None, 

366 dev_type=None, allowed_types=None, 

367 assigned_devices=None): 

368 mapping = mapping or {} 

369 allowed_types = allowed_types or SUPPORTED_DEVICE_TYPES 

370 device_name = block_device.strip_dev(get_device_name(bdm)) 

371 

372 bdm_type = bdm.get('device_type') or dev_type 

373 if bdm_type not in allowed_types: 

374 bdm_type = 'disk' 

375 

376 bdm_bus = bdm.get('disk_bus') or disk_bus 

377 if not is_disk_bus_valid_for_virt(virt_type, bdm_bus): 

378 if device_name: 

379 bdm_bus = get_disk_bus_for_disk_dev(virt_type, device_name) 

380 else: 

381 bdm_bus = get_disk_bus_for_device_type(instance, virt_type, 

382 image_meta, bdm_type) 

383 

384 if not device_name: 

385 if assigned_devices: 

386 padded_mapping = {dev: {'dev': dev} for dev in assigned_devices} 

387 padded_mapping.update(mapping) 

388 else: 

389 padded_mapping = mapping 

390 

391 device_name = find_disk_dev_for_disk_bus(padded_mapping, bdm_bus) 

392 

393 bdm_info = {'bus': bdm_bus, 

394 'dev': device_name, 

395 'type': bdm_type} 

396 

397 bdm_format = bdm.get('guest_format') 

398 if bdm_format: 

399 bdm_info.update({'format': bdm_format}) 

400 

401 boot_index = bdm.get('boot_index') 

402 if boot_index is not None and boot_index >= 0: 

403 # NOTE(ndipanov): libvirt starts ordering from 1, not 0 

404 bdm_info['boot_index'] = str(boot_index + 1) 

405 

406 # If the device is encrypted pass through the secret, format and options 

407 if bdm.get('encrypted'): 

408 bdm_info['encrypted'] = bdm.get('encrypted') 

409 bdm_info['encryption_secret_uuid'] = bdm.get('encryption_secret_uuid') 

410 bdm_info['encryption_format'] = bdm.get('encryption_format') 

411 encryption_options = bdm.get('encryption_options') 

412 if encryption_options: 

413 bdm_info['encryption_options'] = jsonutils.loads( 

414 encryption_options) 

415 

416 return bdm_info 

417 

418 

419def get_device_name(bdm): 

420 """Get the device name if present regardless of the bdm format.""" 

421 if isinstance(bdm, obj_base.NovaObject): 

422 return bdm.device_name 

423 else: 

424 return bdm.get('device_name') or bdm.get('mount_device') 

425 

426 

427def get_root_info(instance, virt_type, image_meta, root_bdm, 

428 disk_bus, cdrom_bus, root_device_name=None): 

429 

430 # NOTE(mriedem): In case the image_meta object was constructed from 

431 # an empty dict, like in the case of evacuate, we have to first check 

432 # if disk_format is set on the ImageMeta object. 

433 if is_iso := (image_meta.obj_attr_is_set('disk_format') and 

434 image_meta.disk_format == 'iso'): 

435 root_device_bus = cdrom_bus 

436 root_device_type = 'cdrom' 

437 else: 

438 root_device_bus = disk_bus 

439 root_device_type = 'disk' 

440 

441 if root_bdm is None: 

442 if not root_device_name: 

443 root_device_name = find_disk_dev_for_disk_bus({}, root_device_bus) 

444 return {'bus': root_device_bus, 

445 'type': root_device_type, 

446 'dev': block_device.strip_dev(root_device_name), 

447 'boot_index': '1'} 

448 

449 root_bdm_copy = copy.deepcopy(root_bdm) 

450 

451 if is_iso: 

452 root_bdm_copy['disk_bus'] = root_device_bus 

453 root_bdm_copy['device_type'] = root_device_type 

454 

455 if not get_device_name(root_bdm_copy) and root_device_name: 

456 root_bdm_copy['device_name'] = root_device_name 

457 

458 return get_info_from_bdm( 

459 instance, virt_type, image_meta, root_bdm_copy, {}, disk_bus, 

460 ) 

461 

462 

463def default_device_names(virt_type, context, instance, block_device_info, 

464 image_meta): 

465 get_disk_info(virt_type, instance, image_meta, block_device_info) 

466 

467 for driver_bdm in itertools.chain( 

468 block_device_info['image'], 

469 block_device_info['ephemerals'], 

470 [block_device_info['swap']] if 

471 block_device_info['swap'] else [], 

472 block_device_info['block_device_mapping'] 

473 ): 

474 driver_bdm.save() 

475 

476 

477def get_default_ephemeral_info(instance, disk_bus, block_device_info, mapping): 

478 ephemerals = driver.block_device_info_get_ephemerals(block_device_info) 

479 if not instance.ephemeral_gb or instance.ephemeral_gb <= 0 or ephemerals: 

480 return None 

481 else: 

482 info = get_next_disk_info(mapping, disk_bus) 

483 if block_device.volume_in_mapping(info['dev'], block_device_info): 

484 return None 

485 return info 

486 

487 

488def update_bdm(bdm, info): 

489 device_name_field = ('device_name' 

490 if 'device_name' in bdm 

491 else 'mount_device') 

492 # Do not update the device name if it was already present 

493 bdm.update(dict(zip((device_name_field, 

494 'disk_bus', 'device_type'), 

495 ((bdm.get(device_name_field) or 

496 block_device.prepend_dev(info['dev'])), 

497 info['bus'], info['type'])))) 

498 

499 

500def get_disk_mapping(virt_type, instance, disk_bus, cdrom_bus, image_meta, 

501 block_device_info=None, rescue=False, 

502 rescue_image_meta=None): 

503 """Determine how to map default disks to the virtual machine. 

504 

505 This is about figuring out whether the default 'disk', 

506 'disk.local', 'disk.swap' and 'disk.config' images have 

507 been overridden by the block device mapping. 

508 

509 Returns the guest disk mapping for the devices. 

510 """ 

511 # NOTE(lyarwood): This is a legacy rescue attempt so provide a mapping with 

512 # the rescue disk, original root disk and optional config drive. 

513 if rescue and rescue_image_meta is None: 

514 return _get_rescue_disk_mapping( 

515 virt_type, instance, disk_bus, image_meta) 

516 

517 # NOTE(lyarwood): This is a new stable rescue attempt so provide a mapping 

518 # with the original mapping *and* rescue disk appended to the end. 

519 if rescue and rescue_image_meta: 

520 return _get_stable_device_rescue_mapping( 

521 virt_type, instance, disk_bus, cdrom_bus, image_meta, 

522 block_device_info, rescue_image_meta) 

523 

524 # NOTE(lyarwood): This is a normal spawn so fetch the full disk mapping. 

525 return _get_disk_mapping( 

526 virt_type, instance, disk_bus, cdrom_bus, image_meta, 

527 block_device_info) 

528 

529 

530def _get_rescue_disk_mapping(virt_type, instance, disk_bus, image_meta): 

531 """Build disk mapping for a legacy instance rescue 

532 

533 This legacy method of rescue requires that the rescue device is attached 

534 first, ahead of the original root disk and optional config drive. 

535 

536 :param virt_type: Virt type used by libvirt. 

537 :param instance: nova.objects.instance.Instance object 

538 :param disk_bus: Disk bus to use within the mapping 

539 :param image_meta: objects.image_meta.ImageMeta for the instance 

540 

541 :returns: Disk mapping for the given instance 

542 """ 

543 mapping = {} 

544 rescue_info = get_next_disk_info(mapping, 

545 disk_bus, boot_index=1) 

546 mapping['disk.rescue'] = rescue_info 

547 mapping['root'] = rescue_info 

548 

549 os_info = get_next_disk_info(mapping, 

550 disk_bus) 

551 mapping['disk'] = os_info 

552 

553 if configdrive.required_by(instance): 

554 device_type = get_config_drive_type() 

555 disk_bus = get_disk_bus_for_device_type(instance, 

556 virt_type, 

557 image_meta, 

558 device_type) 

559 config_info = get_next_disk_info(mapping, 

560 disk_bus, 

561 device_type) 

562 mapping['disk.config.rescue'] = config_info 

563 

564 return mapping 

565 

566 

567def _get_disk_mapping(virt_type, instance, disk_bus, cdrom_bus, image_meta, 

568 block_device_info): 

569 """Build disk mapping for a given instance 

570 

571 :param virt_type: Virt type used by libvirt. 

572 :param instance: nova.objects.instance.Instance object 

573 :param disk_bus: Disk bus to use within the mapping 

574 :param cdrom_bus: CD-ROM bus to use within the mapping 

575 :param image_meta: objects.image_meta.ImageMeta for the instance 

576 :param block_device_info: dict detailing disks and volumes attached 

577 

578 :returns: Disk mapping for the given instance. 

579 """ 

580 mapping = {} 

581 

582 driver_bdms = itertools.chain( 

583 driver.block_device_info_get_image(block_device_info), 

584 driver.block_device_info_get_ephemerals(block_device_info), 

585 [driver.block_device_info_get_swap(block_device_info)], 

586 driver.block_device_info_get_mapping(block_device_info) 

587 ) 

588 

589 pre_assigned_device_names = [ 

590 block_device.strip_dev(get_device_name(bdm)) 

591 for bdm in driver_bdms if get_device_name(bdm) 

592 ] 

593 

594 # Try to find the root driver bdm, either an image based disk or volume 

595 root_bdm = None 

596 if any(driver.block_device_info_get_image(block_device_info)): 

597 root_bdm = driver.block_device_info_get_image(block_device_info)[0] 

598 elif driver.block_device_info_get_mapping(block_device_info): 

599 root_bdm = block_device.get_root_bdm( 

600 driver.block_device_info_get_mapping(block_device_info)) 

601 root_device_name = block_device.strip_dev( 

602 driver.block_device_info_get_root_device(block_device_info)) 

603 root_info = get_root_info( 

604 instance, virt_type, image_meta, root_bdm, 

605 disk_bus, cdrom_bus, root_device_name) 

606 mapping['root'] = root_info 

607 

608 # NOTE (ft): If device name is not set in root bdm, root_info has a 

609 # generated one. We have to copy device name to root bdm to prevent its 

610 # second generation in loop through bdms. If device name is already 

611 # set, nothing is changed. 

612 # NOTE(melwitt): root_bdm can be None in the case of a ISO root device, for 

613 # example. 

614 if root_bdm: 

615 update_bdm(root_bdm, root_info) 

616 

617 if ( 

618 driver.block_device_info_get_image(block_device_info) or 

619 root_bdm is None 

620 ): 

621 mapping['disk'] = root_info 

622 

623 default_eph = get_default_ephemeral_info(instance, disk_bus, 

624 block_device_info, mapping) 

625 if default_eph: 

626 mapping['disk.local'] = default_eph 

627 

628 for idx, eph in enumerate(driver.block_device_info_get_ephemerals( 

629 block_device_info)): 

630 eph_info = get_info_from_bdm( 

631 instance, virt_type, image_meta, eph, mapping, disk_bus, 

632 assigned_devices=pre_assigned_device_names) 

633 mapping[get_eph_disk(idx)] = eph_info 

634 update_bdm(eph, eph_info) 

635 

636 swap = driver.block_device_info_get_swap(block_device_info) 

637 if swap and swap.get('swap_size', 0) > 0: 

638 swap_info = get_info_from_bdm( 

639 instance, virt_type, image_meta, 

640 swap, mapping, disk_bus) 

641 mapping['disk.swap'] = swap_info 

642 update_bdm(swap, swap_info) 

643 elif instance.get_flavor()['swap'] > 0: 

644 swap_info = get_next_disk_info(mapping, disk_bus, 

645 assigned_devices=pre_assigned_device_names) 

646 if not block_device.volume_in_mapping(swap_info['dev'], 646 ↛ 650line 646 didn't jump to line 650 because the condition on line 646 was always true

647 block_device_info): 

648 mapping['disk.swap'] = swap_info 

649 

650 block_device_mapping = driver.block_device_info_get_mapping( 

651 block_device_info) 

652 

653 for bdm in block_device_mapping: 

654 vol_info = get_info_from_bdm( 

655 instance, virt_type, image_meta, bdm, mapping, 

656 assigned_devices=pre_assigned_device_names) 

657 mapping[block_device.prepend_dev(vol_info['dev'])] = vol_info 

658 update_bdm(bdm, vol_info) 

659 

660 if configdrive.required_by(instance): 

661 device_type = get_config_drive_type() 

662 disk_bus = get_disk_bus_for_device_type(instance, 

663 virt_type, 

664 image_meta, 

665 device_type) 

666 config_info = get_next_disk_info(mapping, 

667 disk_bus, 

668 device_type) 

669 mapping['disk.config'] = config_info 

670 return mapping 

671 

672 

673def _get_stable_device_rescue_mapping(virt_type, instance, disk_bus, cdrom_bus, 

674 image_meta, block_device_info, rescue_image_meta): 

675 """Build a disk mapping for a given instance and add a rescue device 

676 

677 This method builds the original disk mapping of the instance before 

678 attaching the rescue device last. 

679 

680 :param virt_type: Virt type used by libvirt. 

681 :param instance: nova.objects.instance.Instance object 

682 :param disk_bus: Disk bus to use within the mapping 

683 :param cdrom_bus: CD-ROM bus to use within the mapping 

684 :param image_meta: objects.image_meta.ImageMeta for the instance 

685 :param block_device_info: dict detailing disks and volumes attached 

686 :param rescue_image_meta: objects.image_meta.ImageMeta of the rescue image 

687 

688 :returns: Disk mapping dict with rescue device added. 

689 """ 

690 mapping = _get_disk_mapping( 

691 virt_type, instance, disk_bus, cdrom_bus, image_meta, 

692 block_device_info) 

693 rescue_device = get_rescue_device(rescue_image_meta) 

694 rescue_bus = get_rescue_bus(instance, virt_type, rescue_image_meta, 

695 rescue_device) 

696 rescue_info = get_next_disk_info(mapping, rescue_bus, 

697 device_type=rescue_device) 

698 mapping['disk.rescue'] = rescue_info 

699 return mapping 

700 

701 

702def get_disk_info(virt_type, instance, image_meta, block_device_info=None, 

703 rescue=False, rescue_image_meta=None): 

704 """Determine guest disk mapping info. 

705 

706 This is a wrapper around get_disk_mapping, which 

707 also returns the chosen disk_bus and cdrom_bus. 

708 The returned data is in a dict 

709 

710 - disk_bus: the bus for harddisks 

711 - cdrom_bus: the bus for CDROMs 

712 - mapping: the disk mapping 

713 

714 Returns the disk mapping disk. 

715 """ 

716 

717 disk_bus = get_disk_bus_for_device_type(instance, virt_type, 

718 image_meta, "disk") 

719 cdrom_bus = get_disk_bus_for_device_type(instance, virt_type, 

720 image_meta, "cdrom") 

721 mapping = get_disk_mapping(virt_type, instance, 

722 disk_bus, cdrom_bus, 

723 image_meta, 

724 block_device_info=block_device_info, 

725 rescue=rescue, 

726 rescue_image_meta=rescue_image_meta) 

727 

728 return {'disk_bus': disk_bus, 

729 'cdrom_bus': cdrom_bus, 

730 'mapping': mapping} 

731 

732 

733def get_boot_order(disk_info): 

734 boot_mapping = (info for name, info in disk_info['mapping'].items() 

735 if name != 'root' and info.get('boot_index') is not None) 

736 boot_devs_dup = (BOOT_DEV_FOR_TYPE[dev['type']] for dev in 

737 sorted(boot_mapping, 

738 key=operator.itemgetter('boot_index'))) 

739 

740 def uniq(lst): 

741 s = set() 

742 return [el for el in lst if el not in s and not s.add(el)] 

743 

744 return uniq(boot_devs_dup) 

745 

746 

747def get_rescue_device(rescue_image_meta): 

748 """Find and validate the rescue device 

749 

750 :param rescue_image_meta: ImageMeta object provided when rescuing 

751 

752 :raises: UnsupportedRescueDevice if the requested device type is not 

753 supported 

754 :returns: A valid device type to be used during the rescue 

755 """ 

756 rescue_device = rescue_image_meta.properties.get("hw_rescue_device", 

757 "disk") 

758 if rescue_device not in SUPPORTED_DEVICE_TYPES: 

759 raise exception.UnsupportedRescueDevice(device=rescue_device) 

760 return rescue_device 

761 

762 

763def get_rescue_bus(instance, virt_type, rescue_image_meta, rescue_device): 

764 """Find and validate the rescue bus 

765 

766 :param instance: The instance to be rescued 

767 :param virt_type: The hypervisor the instance will run on 

768 :param rescue_image_meta: ImageMeta object provided when rescuing 

769 :param rescue_device: The rescue device being used 

770 

771 :raises: UnsupportedRescueBus if the requested bus is not 

772 supported by the hypervisor 

773 :returns: A valid device bus given virt_type and rescue device 

774 """ 

775 rescue_bus = rescue_image_meta.properties.get("hw_rescue_bus") 

776 if rescue_bus is not None: 

777 if is_disk_bus_valid_for_virt(virt_type, rescue_bus): 

778 return rescue_bus 

779 else: 

780 raise exception.UnsupportedRescueBus(bus=rescue_bus, 

781 virt=virt_type) 

782 return get_disk_bus_for_device_type(instance, virt_type, rescue_image_meta, 

783 device_type=rescue_device)