diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 3868742e87..6328d11458 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -7507,6 +7507,66 @@ class LibvirtConnTestCase(test.NoDBTestCase, _set_cache_mode.assert_called_once_with(config) self.assertEqual(config_guest_disk.to_xml(), config.to_xml()) + @mock.patch.object(libvirt_driver.LibvirtDriver, '_get_volume_driver') + @mock.patch.object(libvirt_driver.LibvirtDriver, '_attach_encryptor') + def test_connect_volume_encryption_success( + self, mock_attach_encryptor, mock_get_volume_driver): + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + mock_volume_driver = mock.MagicMock( + spec=volume_drivers.LibvirtBaseVolumeDriver) + mock_get_volume_driver.return_value = mock_volume_driver + + connection_info = {'driver_volume_type': 'fake', + 'data': {'device_path': '/fake', + 'access_mode': 'rw', + 'volume_id': uuids.volume_id}} + encryption = {'provider': encryptors.LUKS, + 'encryption_key_id': uuids.encryption_key_id} + instance = mock.sentinel.instance + + drvr._connect_volume(self.context, connection_info, instance, + encryption=encryption) + + mock_get_volume_driver.assert_called_once_with(connection_info) + mock_volume_driver.connect_volume.assert_called_once_with( + connection_info, instance) + mock_attach_encryptor.assert_called_once_with( + self.context, connection_info, encryption, True) + mock_volume_driver.disconnect_volume.assert_not_called() + + @mock.patch.object(libvirt_driver.LibvirtDriver, '_get_volume_driver') + @mock.patch.object(libvirt_driver.LibvirtDriver, '_attach_encryptor') + def test_connect_volume_encryption_fail( + self, mock_attach_encryptor, mock_get_volume_driver): + + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + mock_volume_driver = mock.MagicMock( + spec=volume_drivers.LibvirtBaseVolumeDriver) + mock_get_volume_driver.return_value = mock_volume_driver + + connection_info = {'driver_volume_type': 'fake', + 'data': {'device_path': '/fake', + 'access_mode': 'rw', + 'volume_id': uuids.volume_id}} + encryption = {'provider': encryptors.LUKS, + 'encryption_key_id': uuids.encryption_key_id} + instance = mock.sentinel.instance + mock_attach_encryptor.side_effect = processutils.ProcessExecutionError + + self.assertRaises(processutils.ProcessExecutionError, + drvr._connect_volume, + self.context, connection_info, instance, + encryption=encryption) + + mock_get_volume_driver.assert_called_once_with(connection_info) + mock_volume_driver.connect_volume.assert_called_once_with( + connection_info, instance) + mock_attach_encryptor.assert_called_once_with( + self.context, connection_info, encryption, True) + mock_volume_driver.disconnect_volume.assert_called_once_with( + connection_info, instance) + @mock.patch.object(key_manager, 'API') @mock.patch.object(libvirt_driver.LibvirtDriver, '_get_volume_encryption') @mock.patch.object(libvirt_driver.LibvirtDriver, '_use_native_luks') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index d775ee695d..a7d5f05ebc 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -1256,8 +1256,15 @@ class LibvirtDriver(driver.ComputeDriver): encryption=None, allow_native_luks=True): vol_driver = self._get_volume_driver(connection_info) vol_driver.connect_volume(connection_info, instance) - self._attach_encryptor(context, connection_info, encryption, - allow_native_luks) + try: + self._attach_encryptor( + context, connection_info, encryption, allow_native_luks) + except Exception: + # Encryption failed so rollback the volume connection. + with excutils.save_and_reraise_exception(logger=LOG): + LOG.exception("Failure attaching encryptor; rolling back " + "volume connection", instance=instance) + vol_driver.disconnect_volume(connection_info, instance) def _should_disconnect_target(self, context, connection_info, instance): connection_count = 0