diff options
Diffstat (limited to 'nova/virt')
-rw-r--r-- | nova/virt/fake.py | 35 | ||||
-rw-r--r-- | nova/virt/hyperv/vmops.py | 2 | ||||
-rw-r--r-- | nova/virt/hyperv/volumeops.py | 12 | ||||
-rw-r--r-- | nova/virt/images.py | 31 | ||||
-rw-r--r-- | nova/virt/libvirt/config.py | 3 | ||||
-rw-r--r-- | nova/virt/libvirt/driver.py | 74 | ||||
-rw-r--r-- | nova/virt/libvirt/guest.py | 7 | ||||
-rw-r--r-- | nova/virt/libvirt/host.py | 24 | ||||
-rw-r--r-- | nova/virt/libvirt/utils.py | 28 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/fibrechannel.py | 7 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/fs.py | 2 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/iscsi.py | 7 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/lightos.py | 7 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/nvme.py | 6 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/quobyte.py | 2 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/scaleio.py | 7 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/smbfs.py | 2 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/storpool.py | 5 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/volume.py | 2 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/vzstorage.py | 5 |
20 files changed, 217 insertions, 51 deletions
diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 5aab8ce300..02fc1f07bc 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -891,6 +891,36 @@ class FakeLiveMigrateDriverWithNestedCustomResources( class FakeDriverWithPciResources(SmallFakeDriver): + """NOTE: this driver provides symmetric compute nodes. Each compute will + have the same resources with the same addresses. It is dangerous as using + this driver can hide issues when in an asymmetric environment nova fails to + update entities according to the host specific addresses (e.g. pci_slot of + the neutron port bindings). + + The current non virt driver specific functional test environment has many + shortcomings making it really hard to simulate host specific virt drivers. + + 1) The virt driver is instantiated by the service logic from the name of + the driver class. This makes passing input to the driver instance from the + test at init time pretty impossible. This could be solved with some + fixtures around nova.virt.driver.load_compute_driver() + + 2) The compute service access the hypervisor not only via the virt + interface but also reads the sysfs of the host. So simply providing a fake + virt driver instance is not enough to isolate simulated compute services + that are running on the same host. Also these low level sysfs reads are not + having host specific information in the call params. So simply mocking the + low level call does not give a way to provide host specific return values. + + 3) CONF is global, and it is read dynamically by the driver. So + providing host specific CONF to driver instances without race conditions + between the drivers are extremely hard especially if periodic tasks are + enabled. + + The libvirt based functional test env under nova.tests.functional.libvirt + has better support to create asymmetric environments. So please consider + using that if possible instead. + """ PCI_ADDR_PF1 = '0000:01:00.0' PCI_ADDR_PF1_VF1 = '0000:01:00.1' @@ -955,6 +985,11 @@ class FakeDriverWithPciResources(SmallFakeDriver): ], group='pci') + # These mocks should be removed after bug + # https://bugs.launchpad.net/nova/+bug/1961587 has been fixed and + # every SRIOV device related information is transferred through the + # virt driver and the PciDevice object instead of queried with + # sysfs calls by the network.neutron.API code. self.useFixture(fixtures.MockPatch( 'nova.pci.utils.get_mac_by_pci_address', return_value='52:54:00:1e:59:c6')) diff --git a/nova/virt/hyperv/vmops.py b/nova/virt/hyperv/vmops.py index 3ec7e90c30..08adeada76 100644 --- a/nova/virt/hyperv/vmops.py +++ b/nova/virt/hyperv/vmops.py @@ -747,7 +747,7 @@ class VMOps(object): # should be disconnected even if the VM doesn't exist anymore, # so they are not leaked. self.unplug_vifs(instance, network_info) - self._volumeops.disconnect_volumes(block_device_info) + self._volumeops.disconnect_volumes(block_device_info, force=True) if destroy_disks: self._delete_disk_files(instance_name) diff --git a/nova/virt/hyperv/volumeops.py b/nova/virt/hyperv/volumeops.py index da5b40f375..d2bfed2441 100644 --- a/nova/virt/hyperv/volumeops.py +++ b/nova/virt/hyperv/volumeops.py @@ -59,10 +59,10 @@ class VolumeOps(object): for vol in volumes: self.attach_volume(vol['connection_info'], instance_name) - def disconnect_volumes(self, block_device_info): + def disconnect_volumes(self, block_device_info, force=False): mapping = driver.block_device_info_get_mapping(block_device_info) for vol in mapping: - self.disconnect_volume(vol['connection_info']) + self.disconnect_volume(vol['connection_info'], force=force) def attach_volume(self, connection_info, instance_name, disk_bus=constants.CTRL_TYPE_SCSI): @@ -116,9 +116,9 @@ class VolumeOps(object): volume_driver.set_disk_qos_specs(connection_info, qos_specs) - def disconnect_volume(self, connection_info): + def disconnect_volume(self, connection_info, force=False): volume_driver = self._get_volume_driver(connection_info) - volume_driver.disconnect_volume(connection_info) + volume_driver.disconnect_volume(connection_info, force=force) def detach_volume(self, connection_info, instance_name): LOG.debug("Detaching volume: %(connection_info)s " @@ -231,8 +231,8 @@ class BaseVolumeDriver(object): def connect_volume(self, connection_info): return self._connector.connect_volume(connection_info['data']) - def disconnect_volume(self, connection_info): - self._connector.disconnect_volume(connection_info['data']) + def disconnect_volume(self, connection_info, force=False): + self._connector.disconnect_volume(connection_info['data'], force=force) def get_disk_resource_path(self, connection_info): disk_paths = self._connector.get_volume_paths(connection_info['data']) diff --git a/nova/virt/images.py b/nova/virt/images.py index 5358f3766a..f13c872290 100644 --- a/nova/virt/images.py +++ b/nova/virt/images.py @@ -110,6 +110,34 @@ def get_info(context, image_href): return IMAGE_API.get(context, image_href) +def check_vmdk_image(image_id, data): + # Check some rules about VMDK files. Specifically we want to make + # sure that the "create-type" of the image is one that we allow. + # Some types of VMDK files can reference files outside the disk + # image and we do not want to allow those for obvious reasons. + + types = CONF.compute.vmdk_allowed_types + + if not len(types): + LOG.warning('Refusing to allow VMDK image as vmdk_allowed_' + 'types is empty') + msg = _('Invalid VMDK create-type specified') + raise exception.ImageUnacceptable(image_id=image_id, reason=msg) + + try: + create_type = data.format_specific['data']['create-type'] + except KeyError: + msg = _('Unable to determine VMDK create-type') + raise exception.ImageUnacceptable(image_id=image_id, reason=msg) + + if create_type not in CONF.compute.vmdk_allowed_types: + LOG.warning('Refusing to process VMDK file with create-type of %r ' + 'which is not in allowed set of: %s', create_type, + ','.join(CONF.compute.vmdk_allowed_types)) + msg = _('Invalid VMDK create-type specified') + raise exception.ImageUnacceptable(image_id=image_id, reason=msg) + + def fetch_to_raw(context, image_href, path, trusted_certs=None): path_tmp = "%s.part" % path fetch(context, image_href, path_tmp, trusted_certs) @@ -129,6 +157,9 @@ def fetch_to_raw(context, image_href, path, trusted_certs=None): reason=(_("fmt=%(fmt)s backed by: %(backing_file)s") % {'fmt': fmt, 'backing_file': backing_file})) + if fmt == 'vmdk': + check_vmdk_image(image_href, data) + if fmt != "raw" and CONF.force_raw_images: staged = "%s.converted" % path LOG.debug("%s was %s, converting to raw", image_href, fmt) diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py index 1a81be3ade..47e92e3ca9 100644 --- a/nova/virt/libvirt/config.py +++ b/nova/virt/libvirt/config.py @@ -3299,6 +3299,7 @@ class LibvirtConfigNodeDeviceMdevInformation(LibvirtConfigObject): root_name="capability", **kwargs) self.type = None self.iommu_group = None + self.uuid = None def parse_dom(self, xmldoc): super(LibvirtConfigNodeDeviceMdevInformation, @@ -3308,6 +3309,8 @@ class LibvirtConfigNodeDeviceMdevInformation(LibvirtConfigObject): self.type = c.get('id') if c.tag == "iommuGroup": self.iommu_group = int(c.get('number')) + if c.tag == "uuid": + self.uuid = c.text class LibvirtConfigNodeDeviceVpdCap(LibvirtConfigObject): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 7c0abcb150..615a009e06 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -1639,7 +1639,7 @@ class LibvirtDriver(driver.ComputeDriver): try: self._disconnect_volume( context, connection_info, instance, - destroy_secrets=destroy_secrets) + destroy_secrets=destroy_secrets, force=True) except Exception as exc: with excutils.save_and_reraise_exception() as ctxt: if cleanup_instance_disks: @@ -1956,7 +1956,7 @@ class LibvirtDriver(driver.ComputeDriver): return (False if connection_count > 1 else True) def _disconnect_volume(self, context, connection_info, instance, - encryption=None, destroy_secrets=True): + encryption=None, destroy_secrets=True, force=False): self._detach_encryptor( context, connection_info, @@ -1968,7 +1968,8 @@ class LibvirtDriver(driver.ComputeDriver): multiattach = connection_info.get('multiattach', False) if self._should_disconnect_target( context, instance, multiattach, vol_driver, volume_id): - vol_driver.disconnect_volume(connection_info, instance) + vol_driver.disconnect_volume( + connection_info, instance, force=force) else: LOG.info('Detected multiple connections on this host for ' 'volume: %(volume)s, skipping target disconnect.', @@ -8019,15 +8020,52 @@ class LibvirtDriver(driver.ComputeDriver): def _get_mediated_device_information(self, devname): """Returns a dict of a mediated device.""" - virtdev = self._host.device_lookup_by_name(devname) + # LP #1951656 - In Libvirt 7.7, the mdev name now includes the PCI + # address of the parent device (e.g. mdev_<uuid>_<pci_address>) due to + # the mdevctl allowing for multiple mediated devs having the same UUID + # defined (only one can be active at a time). Since the guest + # information doesn't have the parent ID, try to lookup which + # mediated device is available that matches the UUID. If multiple + # devices are found that match the UUID, then this is an error + # condition. + try: + virtdev = self._host.device_lookup_by_name(devname) + except libvirt.libvirtError as ex: + if ex.get_error_code() != libvirt.VIR_ERR_NO_NODE_DEVICE: + raise + mdevs = [dev for dev in self._host.list_mediated_devices() + if dev.startswith(devname)] + # If no matching devices are found, simply raise the original + # exception indicating that no devices are found. + if not mdevs: + raise + elif len(mdevs) > 1: + msg = ("The mediated device name %(devname)s refers to a UUID " + "that is present in multiple libvirt mediated devices. " + "Matching libvirt mediated devices are %(devices)s. " + "Mediated device UUIDs must be unique for Nova." % + {'devname': devname, + 'devices': ', '.join(mdevs)}) + raise exception.InvalidLibvirtMdevConfig(reason=msg) + + LOG.debug('Found requested device %s as %s. Using that.', + devname, mdevs[0]) + virtdev = self._host.device_lookup_by_name(mdevs[0]) xmlstr = virtdev.XMLDesc(0) cfgdev = vconfig.LibvirtConfigNodeDevice() cfgdev.parse_str(xmlstr) + # Starting with Libvirt 7.3, the uuid information is available in the + # node device information. If its there, use that. Otherwise, + # fall back to the previous behavior of parsing the uuid from the + # devname. + if cfgdev.mdev_information.uuid: + mdev_uuid = cfgdev.mdev_information.uuid + else: + mdev_uuid = libvirt_utils.mdev_name2uuid(cfgdev.name) device = { "dev_id": cfgdev.name, - # name is like mdev_00ead764_fdc0_46b6_8db9_2963f5c815b4 - "uuid": libvirt_utils.mdev_name2uuid(cfgdev.name), + "uuid": mdev_uuid, # the physical GPU PCI device "parent": cfgdev.parent, "type": cfgdev.mdev_information.type, @@ -8115,6 +8153,7 @@ class LibvirtDriver(driver.ComputeDriver): :param requested_types: Filter out the result for only mediated devices having those types. """ + LOG.debug('Searching for available mdevs...') allocated_mdevs = self._get_all_assigned_mediated_devices() mdevs = self._get_mediated_devices(requested_types) available_mdevs = set() @@ -8130,6 +8169,7 @@ class LibvirtDriver(driver.ComputeDriver): available_mdevs.add(mdev["uuid"]) available_mdevs -= set(allocated_mdevs) + LOG.info('Available mdevs at: %s.', available_mdevs) return available_mdevs def _create_new_mediated_device(self, parent, uuid=None): @@ -8141,6 +8181,7 @@ class LibvirtDriver(driver.ComputeDriver): :returns: the newly created mdev UUID or None if not possible """ + LOG.debug('Attempting to create new mdev...') supported_types = self.supported_vgpu_types # Try to see if we can still create a new mediated device devices = self._get_mdev_capable_devices(supported_types) @@ -8152,6 +8193,7 @@ class LibvirtDriver(driver.ComputeDriver): # The device is not the one that was called, not creating # the mdev continue + LOG.debug('Trying on: %s.', dev_name) dev_supported_type = self._get_vgpu_type_per_pgpu(dev_name) if dev_supported_type and device['types'][ dev_supported_type]['availableInstances'] > 0: @@ -8161,7 +8203,13 @@ class LibvirtDriver(driver.ComputeDriver): pci_addr = "{}:{}:{}.{}".format(*dev_name[4:].split('_')) chosen_mdev = nova.privsep.libvirt.create_mdev( pci_addr, dev_supported_type, uuid=uuid) + LOG.info('Created mdev: %s on pGPU: %s.', + chosen_mdev, pci_addr) return chosen_mdev + LOG.debug('Failed: No available instances on device.') + LOG.info('Failed to create mdev. ' + 'No free space found among the following devices: %s.', + [dev['dev_id'] for dev in devices]) @utils.synchronized(VGPU_RESOURCE_SEMAPHORE) def _allocate_mdevs(self, allocations): @@ -8244,6 +8292,8 @@ class LibvirtDriver(driver.ComputeDriver): # Take the first available mdev chosen_mdev = mdevs_available.pop() else: + LOG.debug('No available mdevs where found. ' + 'Creating an new one...') chosen_mdev = self._create_new_mediated_device(parent_device) if not chosen_mdev: # If we can't find devices having available VGPUs, just raise @@ -8251,6 +8301,7 @@ class LibvirtDriver(driver.ComputeDriver): reason='mdev-capable resource is not available') else: chosen_mdevs.append(chosen_mdev) + LOG.info('Allocated mdev: %s.', chosen_mdev) return chosen_mdevs def _detach_mediated_devices(self, guest): @@ -10419,10 +10470,13 @@ class LibvirtDriver(driver.ComputeDriver): :param instance: the instance being migrated :param migrate_date: a LibvirtLiveMigrateData object """ - network_info = network_model.NetworkInfo( - [vif.source_vif for vif in migrate_data.vifs - if "source_vif" in vif and vif.source_vif]) - self._reattach_instance_vifs(context, instance, network_info) + # NOTE(artom) migrate_data.vifs might not be set if our Neutron doesn't + # have the multiple port bindings extension. + if 'vifs' in migrate_data and migrate_data.vifs: + network_info = network_model.NetworkInfo( + [vif.source_vif for vif in migrate_data.vifs + if "source_vif" in vif and vif.source_vif]) + self._reattach_instance_vifs(context, instance, network_info) def rollback_live_migration_at_destination(self, context, instance, network_info, diff --git a/nova/virt/libvirt/guest.py b/nova/virt/libvirt/guest.py index 53080e41f0..68bd4ca5b0 100644 --- a/nova/virt/libvirt/guest.py +++ b/nova/virt/libvirt/guest.py @@ -655,6 +655,7 @@ class Guest(object): stats = self._domain.jobStats() return JobInfo(**stats) except libvirt.libvirtError as ex: + errmsg = ex.get_error_message() if ex.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT: # Remote libvirt doesn't support new API LOG.debug("Missing remote virDomainGetJobStats: %s", ex) @@ -667,6 +668,12 @@ class Guest(object): # away completclsely LOG.debug("Domain has shutdown/gone away: %s", ex) return JobInfo(type=libvirt.VIR_DOMAIN_JOB_COMPLETED) + elif (ex.get_error_code() == libvirt.VIR_ERR_INTERNAL_ERROR and + errmsg and "migration was active, " + "but no RAM info was set" in errmsg): + LOG.debug("Migration is active or completed but " + "virDomainGetJobStats is missing ram: %s", ex) + return JobInfo(type=libvirt.VIR_DOMAIN_JOB_NONE) else: LOG.debug("Failed to get job stats: %s", ex) raise diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py index cdf47008de..ebcc112534 100644 --- a/nova/virt/libvirt/host.py +++ b/nova/virt/libvirt/host.py @@ -46,6 +46,7 @@ from oslo_log import log as logging from oslo_serialization import jsonutils from oslo_utils import excutils from oslo_utils import importutils +from oslo_utils import strutils from oslo_utils import units from oslo_utils import versionutils @@ -1267,6 +1268,20 @@ class Host(object): return None return vpd_cap.card_serial_number + def _get_pf_details(self, device: dict, pci_address: str) -> dict: + if device.get('dev_type') != fields.PciDeviceType.SRIOV_PF: + return {} + + try: + return { + 'mac_address': pci_utils.get_mac_by_pci_address(pci_address) + } + except exception.PciDeviceNotFoundById: + LOG.debug( + 'Cannot get MAC address of the PF %s. It is probably attached ' + 'to a guest already', pci_address) + return {} + def _get_pcidev_info( self, devname: str, @@ -1426,6 +1441,7 @@ class Host(object): _get_device_type(cfgdev, address, dev, net_devs, vdpa_devs)) device.update(_get_device_capabilities(device, dev, net_devs)) device.update(_get_vpd_details(device, dev, pci_devs)) + device.update(self._get_pf_details(device, address)) return device def get_vdpa_nodedev_by_address( @@ -1487,7 +1503,7 @@ class Host(object): def list_mediated_devices(self, flags=0): """Lookup mediated devices. - :returns: a list of virNodeDevice instance + :returns: a list of strings with the name of the instance """ return self._list_devices("mdev", flags=flags) @@ -1656,9 +1672,9 @@ class Host(object): return False with open(SEV_KERNEL_PARAM_FILE) as f: - contents = f.read() - LOG.debug("%s contains [%s]", SEV_KERNEL_PARAM_FILE, contents) - return contents == "1\n" + content = f.read() + LOG.debug("%s contains [%s]", SEV_KERNEL_PARAM_FILE, content) + return strutils.bool_from_string(content) @property def supports_amd_sev(self) -> bool: diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py index 834f242c79..a1b9459b7e 100644 --- a/nova/virt/libvirt/utils.py +++ b/nova/virt/libvirt/utils.py @@ -581,17 +581,31 @@ def get_default_machine_type(arch: str) -> ty.Optional[str]: def mdev_name2uuid(mdev_name: str) -> str: - """Convert an mdev name (of the form mdev_<uuid_with_underscores>) to a - uuid (of the form 8-4-4-4-12). + """Convert an mdev name (of the form mdev_<uuid_with_underscores> or + mdev_<uuid_with_underscores>_<pciaddress>) to a uuid + (of the form 8-4-4-4-12). + + :param mdev_name: the name of the mdev to parse the UUID from + :returns: string containing the uuid """ - return str(uuid.UUID(mdev_name[5:].replace('_', '-'))) + mdev_uuid = mdev_name[5:].replace('_', '-') + # Unconditionnally remove the PCI address from the name + mdev_uuid = mdev_uuid[:36] + return str(uuid.UUID(mdev_uuid)) + +def mdev_uuid2name(mdev_uuid: str, parent: str = None) -> str: + """Convert an mdev uuid (of the form 8-4-4-4-12) and optionally its parent + device to a name (of the form mdev_<uuid_with_underscores>[_<pciid>]). -def mdev_uuid2name(mdev_uuid: str) -> str: - """Convert an mdev uuid (of the form 8-4-4-4-12) to a name (of the form - mdev_<uuid_with_underscores>). + :param mdev_uuid: the uuid of the mediated device + :param parent: the parent device id for the mediated device + :returns: name of the mdev to reference in libvirt """ - return "mdev_" + mdev_uuid.replace('-', '_') + name = "mdev_" + mdev_uuid.replace('-', '_') + if parent and parent.startswith('pci_'): + name = name + parent[4:] + return name def get_flags_by_flavor_specs(flavor: 'objects.Flavor') -> ty.Set[str]: diff --git a/nova/virt/libvirt/volume/fibrechannel.py b/nova/virt/libvirt/volume/fibrechannel.py index b50db3aa1c..1f890c95c1 100644 --- a/nova/virt/libvirt/volume/fibrechannel.py +++ b/nova/virt/libvirt/volume/fibrechannel.py @@ -59,7 +59,7 @@ class LibvirtFibreChannelVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): connection_info['data']['multipath_id'] = \ device_info['multipath_id'] - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Detach the volume from instance_name.""" LOG.debug("calling os-brick to detach FC Volume", instance=instance) @@ -69,11 +69,12 @@ class LibvirtFibreChannelVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): # the 2nd param of disconnect_volume and be consistent # with the rest of the connectors. self.connector.disconnect_volume(connection_info['data'], - connection_info['data']) + connection_info['data'], + force=force) LOG.debug("Disconnected FC Volume", instance=instance) super(LibvirtFibreChannelVolumeDriver, - self).disconnect_volume(connection_info, instance) + self).disconnect_volume(connection_info, instance, force=force) def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" diff --git a/nova/virt/libvirt/volume/fs.py b/nova/virt/libvirt/volume/fs.py index 5fb9af4a52..992ef45016 100644 --- a/nova/virt/libvirt/volume/fs.py +++ b/nova/virt/libvirt/volume/fs.py @@ -116,7 +116,7 @@ class LibvirtMountedFileSystemVolumeDriver(LibvirtBaseFileSystemVolumeDriver, connection_info['data']['device_path'] = \ self._get_device_path(connection_info) - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Disconnect the volume.""" vol_name = connection_info['data']['name'] mountpoint = self._get_mount_path(connection_info) diff --git a/nova/virt/libvirt/volume/iscsi.py b/nova/virt/libvirt/volume/iscsi.py index 564bac14cc..2b25972a49 100644 --- a/nova/virt/libvirt/volume/iscsi.py +++ b/nova/virt/libvirt/volume/iscsi.py @@ -66,19 +66,20 @@ class LibvirtISCSIVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): connection_info['data']['device_path'] = device_info['path'] - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Detach the volume from instance_name.""" LOG.debug("calling os-brick to detach iSCSI Volume", instance=instance) try: - self.connector.disconnect_volume(connection_info['data'], None) + self.connector.disconnect_volume( + connection_info['data'], None, force=force) except os_brick_exception.VolumeDeviceNotFound as exc: LOG.warning('Ignoring VolumeDeviceNotFound: %s', exc) return LOG.debug("Disconnected iSCSI Volume", instance=instance) super(LibvirtISCSIVolumeDriver, - self).disconnect_volume(connection_info, instance) + self).disconnect_volume(connection_info, instance, force=force) def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" diff --git a/nova/virt/libvirt/volume/lightos.py b/nova/virt/libvirt/volume/lightos.py index d6d393994e..6a22bf6dc6 100644 --- a/nova/virt/libvirt/volume/lightos.py +++ b/nova/virt/libvirt/volume/lightos.py @@ -42,14 +42,15 @@ class LibvirtLightOSVolumeDriver(libvirt_volume.LibvirtVolumeDriver): LOG.debug("Connecting NVMe volume with device_info %s", device_info) connection_info['data']['device_path'] = device_info['path'] - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Detach the volume from the instance.""" LOG.debug("Disconnecting NVMe disk. instance:%s, volume_id:%s", connection_info.get("instance", ""), connection_info.get("volume_id", "")) - self.connector.disconnect_volume(connection_info['data'], None) + self.connector.disconnect_volume( + connection_info['data'], None, force=force) super(LibvirtLightOSVolumeDriver, self).disconnect_volume( - connection_info, instance) + connection_info, instance, force=force) def extend_volume(self, connection_info, instance, requested_size=None): """Extend the volume.""" diff --git a/nova/virt/libvirt/volume/nvme.py b/nova/virt/libvirt/volume/nvme.py index 7436552812..e2977c3572 100644 --- a/nova/virt/libvirt/volume/nvme.py +++ b/nova/virt/libvirt/volume/nvme.py @@ -45,13 +45,13 @@ class LibvirtNVMEVolumeDriver(libvirt_volume.LibvirtVolumeDriver): connection_info['data']['device_path'] = device_info['path'] - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Detach the volume from the instance.""" LOG.debug("Disconnecting NVMe disk", instance=instance) self.connector.disconnect_volume( - connection_info['data'], None) + connection_info['data'], None, force=force) super(LibvirtNVMEVolumeDriver, - self).disconnect_volume(connection_info, instance) + self).disconnect_volume(connection_info, instance, force=force) def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" diff --git a/nova/virt/libvirt/volume/quobyte.py b/nova/virt/libvirt/volume/quobyte.py index bb7a770e57..2eb4bcfb42 100644 --- a/nova/virt/libvirt/volume/quobyte.py +++ b/nova/virt/libvirt/volume/quobyte.py @@ -189,7 +189,7 @@ class LibvirtQuobyteVolumeDriver(fs.LibvirtBaseFileSystemVolumeDriver): instance=instance) @utils.synchronized('connect_qb_volume') - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Disconnect the volume.""" mount_path = self._get_mount_path(connection_info) diff --git a/nova/virt/libvirt/volume/scaleio.py b/nova/virt/libvirt/volume/scaleio.py index 7c414c2870..04a9423e8e 100644 --- a/nova/virt/libvirt/volume/scaleio.py +++ b/nova/virt/libvirt/volume/scaleio.py @@ -57,12 +57,13 @@ class LibvirtScaleIOVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): instance=instance) connection_info['data']['device_path'] = device_info['path'] - def disconnect_volume(self, connection_info, instance): - self.connector.disconnect_volume(connection_info['data'], None) + def disconnect_volume(self, connection_info, instance, force=False): + self.connector.disconnect_volume( + connection_info['data'], None, force=force) LOG.debug("Disconnected volume", instance=instance) super(LibvirtScaleIOVolumeDriver, self).disconnect_volume( - connection_info, instance) + connection_info, instance, force=force) def extend_volume(self, connection_info, instance, requested_size): LOG.debug("calling os-brick to extend ScaleIO Volume", diff --git a/nova/virt/libvirt/volume/smbfs.py b/nova/virt/libvirt/volume/smbfs.py index d112af750c..9de1ce23cd 100644 --- a/nova/virt/libvirt/volume/smbfs.py +++ b/nova/virt/libvirt/volume/smbfs.py @@ -52,7 +52,7 @@ class LibvirtSMBFSVolumeDriver(fs.LibvirtBaseFileSystemVolumeDriver): device_path = self._get_device_path(connection_info) connection_info['data']['device_path'] = device_path - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Disconnect the volume.""" smbfs_share = connection_info['data']['export'] mount_path = self._get_mount_path(connection_info) diff --git a/nova/virt/libvirt/volume/storpool.py b/nova/virt/libvirt/volume/storpool.py index 0e71221f5b..e6dffca39a 100644 --- a/nova/virt/libvirt/volume/storpool.py +++ b/nova/virt/libvirt/volume/storpool.py @@ -47,10 +47,11 @@ class LibvirtStorPoolVolumeDriver(libvirt_volume.LibvirtVolumeDriver): device_info, instance=instance) connection_info['data']['device_path'] = device_info['path'] - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): LOG.debug("Detaching StorPool volume %s", connection_info['data']['volume'], instance=instance) - self.connector.disconnect_volume(connection_info['data'], None) + self.connector.disconnect_volume( + connection_info['data'], None, force=force) LOG.debug("Detached StorPool volume", instance=instance) def extend_volume(self, connection_info, instance, requested_size): diff --git a/nova/virt/libvirt/volume/volume.py b/nova/virt/libvirt/volume/volume.py index 6d650c80e6..f76c3618b2 100644 --- a/nova/virt/libvirt/volume/volume.py +++ b/nova/virt/libvirt/volume/volume.py @@ -135,7 +135,7 @@ class LibvirtBaseVolumeDriver(object): """Connect the volume.""" pass - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Disconnect the volume.""" pass diff --git a/nova/virt/libvirt/volume/vzstorage.py b/nova/virt/libvirt/volume/vzstorage.py index 85ffb45076..babfdef55c 100644 --- a/nova/virt/libvirt/volume/vzstorage.py +++ b/nova/virt/libvirt/volume/vzstorage.py @@ -126,9 +126,10 @@ class LibvirtVZStorageVolumeDriver(fs.LibvirtBaseFileSystemVolumeDriver): return _connect_volume(connection_info, instance) - def disconnect_volume(self, connection_info, instance): + def disconnect_volume(self, connection_info, instance, force=False): """Detach the volume from instance_name.""" LOG.debug("calling os-brick to detach Vzstorage Volume", instance=instance) - self.connector.disconnect_volume(connection_info['data'], None) + self.connector.disconnect_volume( + connection_info['data'], None, force=force) LOG.debug("Disconnected Vzstorage Volume", instance=instance) |