Skip to content

Commit f99f667

Browse files
committed
libvirt: Simplify device_path check in _detach_encryptor
Introduced by Id670f13a7f197e71c77dc91276fc2fba2fc5f314 to resolve bug #1821696 this check was put in place to ensure _detach_encryptor did not attempt to use the os-brick encryptors with an unsupported volume type after libvirt secrets had been removed outside the control of Nova. With the introduction of the [workarounds]disable_native_luksv1 via Ia500eb614cf575ab846f64f4b69c9068274c8c1f however the use of _allow_native_luksv1 as part of this check is no longer valid. As this helper was updated to return False when the workaround is enabled, regardless of the underlying volume being attached natively or not. If an admin had enabled the workaround after users had launched instances with natively attached encrypted volumes *and* the libvirt secrets had gone missing _detach_encryptor would attempt to use the os-brick encryptors. This would fail when the underlying volume type is unsupported, for example rbd. See bug #1917619 for an example. This change resolves this corner case by dropping the use of _allow_native_luksv1 from the check and just asserting that a device_path is present for an encrypted volume before allowing the use of the os-brick encryptors. As noted this is safe as calls to the encryptors are idempotent, ignoring failures to detach when the underlying volume type is supported. Closes-Bug: #1917619 Change-Id: Iba40c2df72228b461767d5734d5a62403d9f2cfa (cherry picked from commit 4908dae)
1 parent 68af588 commit f99f667

File tree

2 files changed

+37
-24
lines changed

2 files changed

+37
-24
lines changed

nova/tests/unit/virt/libvirt/test_driver.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10005,9 +10005,9 @@ def test_detach_encryptor_unencrypted_volume_meta_provided(self,
1000510005

1000610006
@mock.patch('os_brick.encryptors.get_encryption_metadata')
1000710007
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
10008-
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._allow_native_luksv1')
10009-
def test_detach_encryptor_encrypted_volume_meta_missing(self,
10010-
mock_allow_native_luksv1, mock_get_encryptor, mock_get_metadata):
10008+
def test_detach_encryptor_encrypted_volume_meta_missing(
10009+
self, mock_get_encryptor, mock_get_metadata
10010+
):
1001110011
"""Assert that if missing the encryption metadata of an encrypted
1001210012
volume is fetched and then used to detach the encryptor for the volume.
1001310013
"""
@@ -10016,8 +10016,12 @@ def test_detach_encryptor_encrypted_volume_meta_missing(self,
1001610016
mock_get_encryptor.return_value = mock_encryptor
1001710017
encryption = {'provider': 'luks', 'control_location': 'front-end'}
1001810018
mock_get_metadata.return_value = encryption
10019-
connection_info = {'data': {'volume_id': uuids.volume_id}}
10020-
mock_allow_native_luksv1.return_value = False
10019+
connection_info = {
10020+
'data': {
10021+
'device_path': '/dev/foo',
10022+
'volume_id': uuids.volume_id
10023+
}
10024+
}
1002110025

1002210026
drvr._detach_encryptor(self.context, connection_info, None)
1002310027

@@ -10029,9 +10033,11 @@ def test_detach_encryptor_encrypted_volume_meta_missing(self,
1002910033

1003010034
@mock.patch('os_brick.encryptors.get_encryption_metadata')
1003110035
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
10032-
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._allow_native_luksv1')
10033-
def test_detach_encryptor_encrypted_volume_meta_provided(self,
10034-
mock_allow_native_luksv1, mock_get_encryptor, mock_get_metadata):
10036+
def test_detach_encryptor_encrypted_volume_meta_provided(
10037+
self,
10038+
mock_get_encryptor,
10039+
mock_get_metadata
10040+
):
1003510041
"""Assert that when provided there are no further attempts to fetch the
1003610042
encryption metadata for the volume and that the provided metadata is
1003710043
then used to detach the volume.
@@ -10040,8 +10046,12 @@ def test_detach_encryptor_encrypted_volume_meta_provided(self,
1004010046
mock_encryptor = mock.MagicMock()
1004110047
mock_get_encryptor.return_value = mock_encryptor
1004210048
encryption = {'provider': 'luks', 'control_location': 'front-end'}
10043-
connection_info = {'data': {'volume_id': uuids.volume_id}}
10044-
mock_allow_native_luksv1.return_value = False
10049+
connection_info = {
10050+
'data': {
10051+
'device_path': '/dev/foo',
10052+
'volume_id': uuids.volume_id
10053+
}
10054+
}
1004510055

1004610056
drvr._detach_encryptor(self.context, connection_info, encryption)
1004710057

@@ -10051,20 +10061,19 @@ def test_detach_encryptor_encrypted_volume_meta_provided(self,
1005110061
mock_encryptor.detach_volume.assert_called_once_with(**encryption)
1005210062

1005310063
@mock.patch('nova.virt.libvirt.host.Host.find_secret')
10054-
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._allow_native_luksv1')
1005510064
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
10056-
def test_detach_encryptor_native_luks_device_path_secret_missing(self,
10057-
mock_get_encryptor, mock_allow_native_luksv1, mock_find_secret):
10058-
"""Assert that the encryptor is not built when native LUKS is
10059-
available, the associated volume secret is missing and device_path is
10060-
also missing from the connection_info.
10065+
def test_detach_encryptor_native_luks_device_path_secret_missing(
10066+
self, mock_get_encryptor, mock_find_secret
10067+
):
10068+
"""Assert that the encryptor is not built when the associated volume
10069+
secret is missing and device_path is also missing from the
10070+
connection_info.
1006110071
"""
1006210072
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
1006310073
encryption = {'provider': 'luks', 'control_location': 'front-end',
1006410074
'encryption_key_id': uuids.encryption_key_id}
1006510075
connection_info = {'data': {'volume_id': uuids.volume_id}}
1006610076
mock_find_secret.return_value = False
10067-
mock_allow_native_luksv1.return_value = True
1006810077

1006910078
drvr._detach_encryptor(self.context, connection_info, encryption)
1007010079

nova/virt/libvirt/driver.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,14 +1964,18 @@ def _detach_encryptor(self, context, connection_info, encryption):
19641964
return self._host.delete_secret('volume', volume_id)
19651965
if encryption is None:
19661966
encryption = self._get_volume_encryption(context, connection_info)
1967-
# NOTE(lyarwood): Handle bug #1821696 where volume secrets have been
1968-
# removed manually by returning if a LUKS provider is being used
1969-
# and device_path is not present in the connection_info. This avoids
1970-
# VolumeEncryptionNotSupported being thrown when we incorrectly build
1971-
# the encryptor below due to the secrets not being present above.
1972-
if (encryption and self._allow_native_luksv1(encryption=encryption) and
1973-
not connection_info['data'].get('device_path')):
1967+
1968+
# NOTE(lyarwood): Handle bugs #1821696 and #1917619 by avoiding the use
1969+
# of the os-brick encryptors if we don't have a device_path. The lack
1970+
# of a device_path here suggests the volume was natively attached to
1971+
# QEMU anyway as volumes without a device_path are not supported by
1972+
# os-brick encryptors. For volumes with a device_path the calls to
1973+
# the os-brick encryptors are safe as they are actually idempotent,
1974+
# ignoring any failures caused by the volumes actually being natively
1975+
# attached previously.
1976+
if (encryption and connection_info['data'].get('device_path') is None):
19741977
return
1978+
19751979
if encryption:
19761980
encryptor = self._get_volume_encryptor(connection_info,
19771981
encryption)

0 commit comments

Comments
 (0)