Fix create encrypted volume from image

If we run two create encrypted volume from image serially (waiting for
one operation to complete before the making the next request) the first
operation succeeds while the second one will fail during the attach
phase.

The failure we see in the logs indicate that OS-Brick is unable to get
the WWN from the connected volume.

In reality the failure to attach the volume on the second operation is
caused by a failed cleanup of the first create, even if there's no error
in the logs.

The reason why OS-Brick didn't correctly do the cleanup of the first
volume is because didn't know that it was attaching an encrypted volume
and returned a real path (ie: /dev/sdf) that then go overwritten by the
unencrypted device mapper.

The solution is letting OS-Brick know that it's an encrypted volume
during the attachment phase so it will return a symlink to the real
device instead of the real device itself.

The manager's "initialize_connection" does this correctly, but the
method creating the volume from an image doesn't use the method of that
class and calls the driver's "initialize_connection" method instead,
which is missing the "encrypted" field.

Closes-Bug: #1703954
Change-Id: I35db18f36f86683f2ab16694c9787c908251a382
(cherry picked from commit 3b01eb78ce)
This commit is contained in:
Gorka Eguileor 2017-12-15 12:09:41 +01:00
parent d810928406
commit cfe0cf93d7
2 changed files with 45 additions and 0 deletions

View File

@ -343,6 +343,46 @@ class GenericVolumeDriverTestCase(BaseDriverTestCase):
db.volume_destroy(self.context, src_vol['id'])
db.volume_destroy(self.context, dest_vol['id'])
@mock.patch(driver_name + '.initialize_connection')
@mock.patch(driver_name + '.create_export', return_value=None)
@mock.patch(driver_name + '._connect_device')
def test__attach_volume_encrypted(self, connect_mock, export_mock,
initialize_mock):
properties = {'host': 'myhost', 'ip': '192.168.1.43',
'initiator': u'iqn.1994-05.com.redhat:d9be887375',
'multipath': False, 'os_type': 'linux2',
'platform': 'x86_64'}
data = {'target_discovered': True,
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000001',
'target_portal': '127.0.0.0.1:3260',
'volume_id': 1,
'discard': False}
passed_conn = {'driver_volume_type': 'iscsi', 'data': data.copy()}
initialize_mock.return_value = passed_conn
# _attach_volume adds the encrypted value based on the volume
expected_conn = {'driver_volume_type': 'iscsi', 'data': data.copy()}
expected_conn['data']['encrypted'] = True
volume = tests_utils.create_volume(
self.context, status='available',
size=2,
encryption_key_id=fake.ENCRYPTION_KEY_ID)
attach_info, vol = self.volume.driver._attach_volume(self.context,
volume,
properties)
export_mock.assert_called_once_with(self.context, volume, properties)
initialize_mock.assert_called_once_with(volume, properties)
connect_mock.assert_called_once_with(expected_conn)
self.assertEqual(connect_mock.return_value, attach_info)
self.assertEqual(volume, vol)
@mock.patch.object(os_brick.initiator.connector,
'get_connector_properties')
@mock.patch.object(image_utils, 'fetch_to_raw')

View File

@ -991,6 +991,11 @@ class BaseVD(object):
raise exception.VolumeBackendAPIException(data=ex_msg)
raise exception.VolumeBackendAPIException(data=err_msg)
# Add encrypted flag to connection_info if not set in the driver.
if conn['data'].get('encrypted') is None:
encrypted = bool(volume.encryption_key_id)
conn['data']['encrypted'] = encrypted
try:
attach_info = self._connect_device(conn)
except Exception as exc: