diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index fbcbd35573bb..ed5f364a41ad 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -6329,11 +6329,16 @@ class LibvirtConnTestCase(test.NoDBTestCase): mock.patch.object(drvr, '_get_volume_config', return_value=mock_conf), mock.patch.object(drvr, '_set_cache_mode'), - mock.patch.object(drvr, '_check_discard_for_attach_volume') + mock.patch.object(drvr, '_check_discard_for_attach_volume'), + mock.patch.object(drvr, '_build_device_metadata'), + mock.patch.object(objects.Instance, 'save') ) as (mock_connect_volume, mock_get_volume_config, - mock_set_cache_mode, mock_check_discard): + mock_set_cache_mode, mock_check_discard, + mock_build_metadata, mock_save): for state in (power_state.RUNNING, power_state.PAUSED): mock_dom.info.return_value = [state, 512, 512, 2, 1234, 5678] + mock_build_metadata.return_value = \ + objects.InstanceDeviceMetadata() drvr.attach_volume(self.context, connection_info, instance, "/dev/vdb", disk_bus=bdm['disk_bus'], @@ -6353,6 +6358,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): mock_dom.attachDeviceFlags.assert_called_with( mock_conf.to_xml(), flags=flags) mock_check_discard.assert_called_with(mock_conf, instance) + mock_build_metadata.assert_called_with(self.context, instance) + mock_save.assert_called_with() @mock.patch('nova.virt.libvirt.host.Host.get_domain') def test_detach_volume_with_vir_domain_affect_live_flag(self, diff --git a/nova/tests/unit/virt/test_virt_drivers.py b/nova/tests/unit/virt/test_virt_drivers.py index fdc0535d7d5b..e3e0170e911b 100644 --- a/nova/tests/unit/virt/test_virt_drivers.py +++ b/nova/tests/unit/virt/test_virt_drivers.py @@ -469,7 +469,9 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase): self.assertEqual(storage_ip, result['ip']) @catch_notimplementederror - def test_attach_detach_volume(self): + @mock.patch.object(libvirt.driver.LibvirtDriver, '_build_device_metadata', + return_value=objects.InstanceDeviceMetadata()) + def test_attach_detach_volume(self, _): instance_ref, network_info = self._get_running_instance() connection_info = { "driver_volume_type": "fake", @@ -484,7 +486,9 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase): '/dev/sda')) @catch_notimplementederror - def test_swap_volume(self): + @mock.patch.object(libvirt.driver.LibvirtDriver, '_build_device_metadata', + return_value=objects.InstanceDeviceMetadata()) + def test_swap_volume(self, _): instance_ref, network_info = self._get_running_instance() self.assertIsNone( self.connection.attach_volume(None, {'driver_volume_type': 'fake', @@ -500,7 +504,9 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase): '/dev/sda', 2)) @catch_notimplementederror - def test_attach_detach_different_power_states(self): + @mock.patch.object(libvirt.driver.LibvirtDriver, '_build_device_metadata', + return_value=objects.InstanceDeviceMetadata()) + def test_attach_detach_different_power_states(self, _): instance_ref, network_info = self._get_running_instance() connection_info = { "driver_volume_type": "fake", diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 3e5ff16accf2..07d0b941e660 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -129,6 +129,7 @@ class ComputeDriver(object): "supports_attach_interface": False, "supports_device_tagging": False, "supports_tagged_attach_interface": False, + "supports_tagged_attach_volume": False, } def __init__(self, virtapi): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index a8e8a81552eb..67b4bf5f76af 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -302,6 +302,7 @@ class LibvirtDriver(driver.ComputeDriver): "supports_attach_interface": True, "supports_device_tagging": True, "supports_tagged_attach_interface": True, + "supports_tagged_attach_volume": True, } def __init__(self, virtapi, read_only=False): @@ -1234,6 +1235,17 @@ class LibvirtDriver(driver.ComputeDriver): encryptor.attach_volume(context, **encryption) guest.attach_device(conf, persistent=True, live=live) + # NOTE(artom) If we're attaching with a device role tag, we need to + # rebuild device_metadata. If we're attaching without a role + # tag, we're rebuilding it here needlessly anyways. This isn't a + # massive deal, and it helps reduce code complexity by not having + # to indicate to the virt driver that the attach is tagged. The + # really important optimization of not calling the database unless + # device_metadata has actually changed is done for us by + # instance.save(). + instance.device_metadata = self._build_device_metadata( + context, instance) + instance.save() except Exception as ex: LOG.exception(_LE('Failed to attach volume at mountpoint: %s'), mountpoint, instance=instance)