Merge "libvirt: Collocate encryptor and volume driver calls"

This commit is contained in:
Zuul 2018-01-22 22:21:32 +00:00 committed by Gerrit Code Review
commit b39c39017f
7 changed files with 327 additions and 121 deletions

View File

@ -5446,8 +5446,8 @@ class ComputeManager(manager.Manager):
"old: %(old_cinfo)s",
{'new_cinfo': new_cinfo, 'old_cinfo': old_cinfo},
instance=instance)
self.driver.swap_volume(old_cinfo, new_cinfo, instance, mountpoint,
resize_to)
self.driver.swap_volume(context, old_cinfo, new_cinfo, instance,
mountpoint, resize_to)
if new_attachment_id:
self.volume_api.attachment_complete(context, new_attachment_id)
LOG.debug("swap_volume: Driver volume swap returned, new "

View File

@ -1994,8 +1994,9 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
self.assertTrue(uuidutils.is_uuid_like(volume))
return {}
def _assert_swap_volume(self, old_connection_info, new_connection_info,
instance, mountpoint, resize_to):
def _assert_swap_volume(self, context, old_connection_info,
new_connection_info, instance, mountpoint,
resize_to):
self.assertEqual(2, resize_to)
@mock.patch.object(cinder.API, 'initialize_connection')
@ -2334,7 +2335,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
instance, uuids.new_attachment_id)
# Assert the expected calls.
# The new connection_info has the new_volume_id as the serial.
new_cinfo = mock_driver_swap.call_args[0][1]
new_cinfo = mock_driver_swap.call_args[0][2]
self.assertIn('serial', new_cinfo)
self.assertEqual(uuids.new_volume_id, new_cinfo['serial'])
get_bdm.assert_called_once_with(

View File

@ -6706,7 +6706,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
test.MatchType(objects.ImageMeta),
bdm)
mock_connect_volume.assert_called_with(
connection_info, instance)
self.context, connection_info, instance, encryption=None)
mock_get_volume_config.assert_called_with(
connection_info, disk_info)
mock_dom.attachDeviceFlags.assert_called_with(
@ -6761,7 +6761,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
</disk>
""", flags=flags)
mock_disconnect_volume.assert_called_with(
connection_info, instance)
None, connection_info, instance, encryption=None)
@mock.patch('nova.virt.libvirt.host.Host._get_domain')
def test_detach_volume_disk_not_found(self, mock_get_domain):
@ -6785,12 +6785,15 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_get_domain.assert_called_once_with(instance)
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_driver')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
@mock.patch('nova.virt.libvirt.host.Host.get_guest')
def test_detach_volume_order_with_encryptors(self, mock_get_guest,
mock_get_encryptor, mock_disconnect_volume):
mock_get_encryptor, mock_get_volume_driver):
mock_volume_driver = mock.MagicMock(
spec=volume_drivers.LibvirtBaseVolumeDriver)
mock_get_volume_driver.return_value = mock_volume_driver
mock_guest = mock.MagicMock(spec=libvirt_guest.Guest)
mock_guest.get_power_state.return_value = power_state.RUNNING
mock_get_guest.return_value = mock_guest
@ -6799,7 +6802,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_get_encryptor.return_value = mock_encryptor
mock_order = mock.Mock()
mock_order.attach_mock(mock_disconnect_volume, 'disconnect_volume')
mock_order.attach_mock(mock_volume_driver.disconnect_volume,
'disconnect_volume')
mock_order.attach_mock(mock_guest.detach_device_with_retry(),
'detach_volume')
mock_order.attach_mock(mock_encryptor.detach_volume,
@ -6917,6 +6921,196 @@ class LibvirtConnTestCase(test.NoDBTestCase,
drvr.extend_volume,
connection_info, instance)
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_use_encryptor_connection_info_incomplete(self,
mock_get_encryptor, mock_get_metadata):
"""Assert no attach attempt is made given incomplete connection_info.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
connection_info = {'data': {}}
drvr._attach_encryptor(self.context, connection_info, None)
mock_get_metadata.assert_not_called()
mock_get_encryptor.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_attach_encryptor_unencrypted_volume_meta_missing(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that if not provided encryption metadata is fetched even
if the volume is ultimately unencrypted and no attempt to attach
is made.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
encryption = {}
connection_info = {'data': {'volume_id': uuids.volume_id}}
mock_get_metadata.return_value = encryption
drvr._attach_encryptor(self.context, connection_info, None)
mock_get_metadata.assert_called_once_with(self.context,
drvr._volume_api, uuids.volume_id, connection_info)
mock_get_encryptor.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_attach_encryptor_unencrypted_volume_meta_provided(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that if an empty encryption metadata dict is provided that
there is no additional attempt to lookup the metadata or attach the
encryptor.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
encryption = {}
connection_info = {'data': {'volume_id': uuids.volume_id}}
drvr._attach_encryptor(self.context, connection_info,
encryption=encryption)
mock_get_metadata.assert_not_called()
mock_get_encryptor.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_attach_encryptor_encrypted_volume_meta_missing(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that if missing the encryption metadata of an encrypted
volume is fetched and then used to attach the encryptor for the volume.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_encryptor = mock.MagicMock()
mock_get_encryptor.return_value = mock_encryptor
encryption = {'provider': 'luks', 'control_location': 'front-end'}
mock_get_metadata.return_value = encryption
connection_info = {'data': {'volume_id': uuids.volume_id}}
drvr._attach_encryptor(self.context, connection_info, None)
mock_get_metadata.assert_called_once_with(self.context,
drvr._volume_api, uuids.volume_id, connection_info)
mock_get_encryptor.assert_called_once_with(connection_info,
encryption)
mock_encryptor.attach_volume.assert_called_once_with(self.context,
**encryption)
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_attach_encryptor_encrypted_volume_meta_provided(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that when provided there are no further attempts to fetch the
encryption metadata for the volume and that the provided metadata is
then used to attach the volume.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_encryptor = mock.MagicMock()
mock_get_encryptor.return_value = mock_encryptor
encryption = {'provider': 'luks', 'control_location': 'front-end'}
connection_info = {'data': {'volume_id': uuids.volume_id}}
drvr._attach_encryptor(self.context, connection_info,
encryption=encryption)
mock_get_metadata.assert_not_called()
mock_get_encryptor.assert_called_once_with(connection_info,
encryption)
mock_encryptor.attach_volume.assert_called_once_with(self.context,
**encryption)
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_detach_encryptor_connection_info_incomplete(self,
mock_get_encryptor, mock_get_metadata):
"""Assert no detach attempt is made given incomplete connection_info.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
connection_info = {'data': {}}
drvr._detach_encryptor(self.context, connection_info, None)
mock_get_metadata.assert_not_called()
mock_get_encryptor.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_detach_encryptor_unencrypted_volume_meta_missing(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that if not provided encryption metadata is fetched even
if the volume is ultimately unencrypted and no attempt to detach
is made.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
encryption = {}
connection_info = {'data': {'volume_id': uuids.volume_id}}
mock_get_metadata.return_value = encryption
drvr._detach_encryptor(self.context, connection_info, None)
mock_get_metadata.assert_called_once_with(self.context,
drvr._volume_api, uuids.volume_id, connection_info)
mock_get_encryptor.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_detach_encryptor_unencrypted_volume_meta_provided(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that if an empty encryption metadata dict is provided that
there is no additional attempt to lookup the metadata or detach the
encryptor.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
encryption = {}
connection_info = {'data': {'volume_id': uuids.volume_id}}
drvr._detach_encryptor(self.context, connection_info, encryption)
mock_get_metadata.assert_not_called()
mock_get_encryptor.assert_not_called()
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_detach_encryptor_encrypted_volume_meta_missing(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that if missing the encryption metadata of an encrypted
volume is fetched and then used to detach the encryptor for the volume.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_encryptor = mock.MagicMock()
mock_get_encryptor.return_value = mock_encryptor
encryption = {'provider': 'luks', 'control_location': 'front-end'}
mock_get_metadata.return_value = encryption
connection_info = {'data': {'volume_id': uuids.volume_id}}
drvr._detach_encryptor(self.context, connection_info, None)
mock_get_metadata.assert_called_once_with(self.context,
drvr._volume_api, uuids.volume_id, connection_info)
mock_get_encryptor.assert_called_once_with(connection_info,
encryption)
mock_encryptor.detach_volume.assert_called_once_with(**encryption)
@mock.patch('os_brick.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor')
def test_detach_encryptor_encrypted_volume_meta_provided(self,
mock_get_encryptor, mock_get_metadata):
"""Assert that when provided there are no further attempts to fetch the
encryption metadata for the volume and that the provided metadata is
then used to detach the volume.
"""
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_encryptor = mock.MagicMock()
mock_get_encryptor.return_value = mock_encryptor
encryption = {'provider': 'luks', 'control_location': 'front-end'}
connection_info = {'data': {'volume_id': uuids.volume_id}}
drvr._detach_encryptor(self.context, connection_info, encryption)
mock_get_metadata.assert_not_called()
mock_get_encryptor.assert_called_once_with(connection_info,
encryption)
mock_encryptor.detach_volume.assert_called_once_with(**encryption)
def test_multi_nic(self):
network_info = _fake_network_info(self, 2)
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
@ -10146,7 +10340,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
).AndReturn(vol['block_device_mapping'])
self.mox.StubOutWithMock(drvr, "_connect_volume")
for v in vol['block_device_mapping']:
drvr._connect_volume(v['connection_info'], instance)
drvr._connect_volume(c, v['connection_info'], instance)
self.mox.StubOutWithMock(drvr, 'plug_vifs')
drvr.plug_vifs(mox.IsA(instance), nw_info)
@ -10278,7 +10472,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
# Creating mocks
self.mox.StubOutWithMock(drvr, "_connect_volume")
for v in vol['block_device_mapping']:
drvr._connect_volume(v['connection_info'], inst_ref)
drvr._connect_volume(c, v['connection_info'], inst_ref)
self.mox.StubOutWithMock(drvr, 'plug_vifs')
drvr.plug_vifs(mox.IsA(inst_ref), nw_info)
self.mox.ReplayAll()
@ -10627,8 +10821,9 @@ class LibvirtConnTestCase(test.NoDBTestCase,
get_volume_connector.assert_has_calls([
mock.call(inst_ref)])
_disconnect_volume.assert_has_calls([
mock.call({'data': {'multipath_id': 'dummy1'}}, inst_ref),
mock.call({'data': {}}, inst_ref)])
mock.call(cntx, {'data': {'multipath_id': 'dummy1'}},
inst_ref),
mock.call(cntx, {'data': {}}, inst_ref)])
def test_post_live_migration_cinder_v3(self):
cntx = context.get_admin_context()
@ -10666,7 +10861,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock_attachment_get.assert_called_once_with(cntx,
old_attachment_id)
mock_disconnect.assert_called_once_with(connection_info, instance)
mock_disconnect.assert_called_once_with(cntx, connection_info,
instance)
_test()
def test_get_instance_disk_info_excludes_volumes(self):
@ -11024,7 +11220,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
'delete_on_termination': False
}
def _connect_volume_side_effect(connection_info, instance):
def _connect_volume_side_effect(ctxt, connection_info, instance):
bdm['connection_info']['data']['device_path'] = '/dev/path/to/dev'
def _get(key, opt=None):
@ -14563,8 +14759,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
connection_info = {'driver_volume_type': 'fake'}
drvr.detach_volume(connection_info, instance, '/dev/sda')
_get_domain.assert_called_once_with(instance)
_disconnect_volume.assert_called_once_with(connection_info,
instance)
_disconnect_volume.assert_called_once_with(None, connection_info,
instance, encryption=None)
def _test_attach_detach_interface_get_config(self, method_name):
"""Tests that the get_config() method is properly called in
@ -15047,25 +15243,20 @@ class LibvirtConnTestCase(test.NoDBTestCase,
network_model.VIF(id='2', active=True)]
with test.nested(
mock.patch.object(drvr, '_get_volume_encryptor'),
mock.patch.object(drvr, 'plug_vifs'),
mock.patch.object(drvr.firewall_driver, 'setup_basic_filtering'),
mock.patch.object(drvr.firewall_driver,
'prepare_instance_filter'),
mock.patch.object(drvr, '_create_domain'),
mock.patch.object(drvr.firewall_driver, 'apply_instance_filter'),
) as (get_volume_encryptor, plug_vifs, setup_basic_filtering,
prepare_instance_filter, create_domain, apply_instance_filter):
) as (plug_vifs, setup_basic_filtering, prepare_instance_filter,
create_domain, apply_instance_filter):
create_domain.return_value = libvirt_guest.Guest(mock_dom)
guest = drvr._create_domain_and_network(
self.context, fake_xml, instance, network_info,
block_device_info=block_device_info)
get_encryption_metadata.assert_called_once_with(self.context,
drvr._volume_api, fake_volume_id, connection_info)
get_volume_encryptor.assert_called_once_with(connection_info,
mock_encryption_meta)
plug_vifs.assert_called_once_with(instance, network_info)
setup_basic_filtering.assert_called_once_with(instance,
network_info)
@ -15109,13 +15300,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
mock.patch.object(drvr, '_get_volume_config',
return_value=mock_conf)
) as (volume_save, connect_volume, get_volume_config):
devices = drvr._get_guest_storage_config(instance, image_meta,
disk_info, False, bdi, flavor, "hvm")
devices = drvr._get_guest_storage_config(self.context, instance,
image_meta, disk_info, False, bdi, flavor, "hvm")
self.assertEqual(3, len(devices))
self.assertEqual('/dev/vdb', instance.default_ephemeral_device)
self.assertIsNone(instance.default_swap_device)
connect_volume.assert_called_with(bdm['connection_info'], instance)
connect_volume.assert_called_with(self.context,
bdm['connection_info'], instance)
get_volume_config.assert_called_with(bdm['connection_info'],
{'bus': 'virtio', 'type': 'disk', 'dev': 'vdc'})
volume_save.assert_called_once_with()
@ -15325,14 +15517,16 @@ class LibvirtConnTestCase(test.NoDBTestCase,
conf = mock.MagicMock(source_path='/fake-new-volume')
get_volume_config.return_value = conf
conn.swap_volume(old_connection_info, new_connection_info, instance,
'/dev/vdb', 1)
conn.swap_volume(self.context, old_connection_info,
new_connection_info, instance, '/dev/vdb', 1)
get_guest.assert_called_once_with(instance)
connect_volume.assert_called_once_with(new_connection_info, instance)
connect_volume.assert_called_once_with(self.context,
new_connection_info, instance)
swap_volume.assert_called_once_with(guest, 'vdb', conf, 1)
disconnect_volume.assert_called_once_with(old_connection_info,
disconnect_volume.assert_called_once_with(self.context,
old_connection_info,
instance)
def test_swap_volume_driver_source_is_volume(self):
@ -15366,12 +15560,12 @@ class LibvirtConnTestCase(test.NoDBTestCase,
rebase.side_effect = exc
self.assertRaises(exception.VolumeRebaseFailed, conn.swap_volume,
mock.sentinel.old_connection_info,
self.context, mock.sentinel.old_connection_info,
mock.sentinel.new_connection_info,
instance, '/dev/vdb', 0)
connect_volume.assert_called_once_with(
connect_volume.assert_called_once_with(self.context,
mock.sentinel.new_connection_info, instance)
disconnect_volume.assert_called_once_with(
disconnect_volume.assert_called_once_with(self.context,
mock.sentinel.new_connection_info, instance)
@mock.patch('nova.virt.libvirt.guest.BlockDevice.is_job_complete')
@ -15398,12 +15592,12 @@ class LibvirtConnTestCase(test.NoDBTestCase,
abort_job.side_effect = [None, exc]
self.assertRaises(exception.VolumeRebaseFailed, conn.swap_volume,
mock.sentinel.old_connection_info,
self.context, mock.sentinel.old_connection_info,
mock.sentinel.new_connection_info,
instance, '/dev/vdb', 0)
connect_volume.assert_called_once_with(
connect_volume.assert_called_once_with(self.context,
mock.sentinel.new_connection_info, instance)
disconnect_volume.assert_called_once_with(
disconnect_volume.assert_called_once_with(self.context,
mock.sentinel.new_connection_info, instance)
@mock.patch('nova.virt.libvirt.guest.BlockDevice.is_job_complete')
@ -16189,7 +16383,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
context.get_admin_context(), ins_ref, '10.0.0.2',
flavor_obj, None)
def _test_migrate_disk_and_power_off(self, flavor_obj,
def _test_migrate_disk_and_power_off(self, ctxt, flavor_obj,
block_device_info=None,
params_for_instance=None):
"""Test for nova.virt.libvirt.libvirt_driver.LivirtConnection
@ -16228,21 +16422,20 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
# dest is different host case
out = self.drvr.migrate_disk_and_power_off(
context.get_admin_context(), instance, '10.0.0.2',
flavor_obj, None, block_device_info=block_device_info)
ctxt, instance, '10.0.0.2', flavor_obj, None,
block_device_info=block_device_info)
self.assertEqual(out, disk_info_text)
# dest is same host case
out = self.drvr.migrate_disk_and_power_off(
context.get_admin_context(), instance, '10.0.0.1',
flavor_obj, None, block_device_info=block_device_info)
ctxt, instance, '10.0.0.1', flavor_obj, None,
block_device_info=block_device_info)
self.assertEqual(out, disk_info_text)
def test_migrate_disk_and_power_off(self):
flavor = {'root_gb': 10, 'ephemeral_gb': 20}
flavor_obj = objects.Flavor(**flavor)
self._test_migrate_disk_and_power_off(flavor_obj)
self._test_migrate_disk_and_power_off(self.context, flavor_obj)
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume')
def test_migrate_disk_and_power_off_boot_from_volume(self,
@ -16258,14 +16451,14 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
flavor = {'root_gb': 1, 'ephemeral_gb': 0}
flavor_obj = objects.Flavor(**flavor)
# Note(Mike_D): The size of instance's ephemeral_gb is 0 gb.
self._test_migrate_disk_and_power_off(
self._test_migrate_disk_and_power_off(self.context,
flavor_obj, block_device_info=info,
params_for_instance={'image_ref': None,
'root_gb': 10,
'ephemeral_gb': 0,
'flavor': {'root_gb': 10,
'ephemeral_gb': 0}})
disconnect_volume.assert_called_with(
disconnect_volume.assert_called_with(self.context,
mock.sentinel.conn_info_vda, mock.ANY)
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._disconnect_volume')
@ -16283,7 +16476,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
'connection_info': mock.sentinel.conn_info_vda}]}
flavor = {'root_gb': 1, 'ephemeral_gb': 0}
flavor_obj = objects.Flavor(**flavor)
self._test_migrate_disk_and_power_off(
self._test_migrate_disk_and_power_off(self.context,
flavor_obj, block_device_info=info,
params_for_instance={
'image_ref': uuids.fake_volume_backed_image_ref,
@ -16291,7 +16484,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
'ephemeral_gb': 0,
'flavor': {'root_gb': 10,
'ephemeral_gb': 0}})
disconnect_volume.assert_called_with(
disconnect_volume.assert_called_with(self.context,
mock.sentinel.conn_info_vda, mock.ANY)
@mock.patch('nova.utils.execute')
@ -16558,7 +16751,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
# Old flavor, eph is 20, real disk is 3, target is 4
flavor = {'root_gb': 10, 'ephemeral_gb': 4}
flavor_obj = objects.Flavor(**flavor)
self._test_migrate_disk_and_power_off(flavor_obj)
self._test_migrate_disk_and_power_off(self.context, flavor_obj)
@mock.patch('nova.utils.execute')
@mock.patch('nova.virt.libvirt.utils.copy_image')

View File

@ -494,7 +494,7 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase):
instance_ref,
'/dev/sda'))
self.assertIsNone(
self.connection.swap_volume({'driver_volume_type': 'fake',
self.connection.swap_volume(None, {'driver_volume_type': 'fake',
'data': {}},
{'driver_volume_type': 'fake',
'data': {}},

View File

@ -471,10 +471,11 @@ class ComputeDriver(object):
"""Detach the disk attached to the instance."""
raise NotImplementedError()
def swap_volume(self, old_connection_info, new_connection_info,
def swap_volume(self, context, old_connection_info, new_connection_info,
instance, mountpoint, resize_to):
"""Replace the volume attached to the given `instance`.
:param context: The request context.
:param dict old_connection_info:
The volume for this connection gets detached from the given
`instance`.

View File

@ -317,7 +317,7 @@ class FakeDriver(driver.ComputeDriver):
except KeyError:
pass
def swap_volume(self, old_connection_info, new_connection_info,
def swap_volume(self, context, old_connection_info, new_connection_info,
instance, mountpoint, resize_to):
"""Replace the disk attached to the instance."""
instance_name = instance.name

View File

@ -1011,23 +1011,8 @@ class LibvirtDriver(driver.ComputeDriver):
disk_dev = vol['mount_device']
if disk_dev is not None:
disk_dev = disk_dev.rpartition("/")[2]
if ('data' in connection_info and
'volume_id' in connection_info['data']):
volume_id = connection_info['data']['volume_id']
encryption = encryptors.get_encryption_metadata(
context, self._volume_api, volume_id, connection_info)
if encryption:
# The volume must be detached from the VM before
# disconnecting it from its encryptor. Otherwise, the
# encryptor may report that the volume is still in use.
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.detach_volume(**encryption)
try:
self._disconnect_volume(connection_info, instance)
self._disconnect_volume(context, connection_info, instance)
except Exception as exc:
with excutils.save_and_reraise_exception() as ctxt:
if destroy_disks:
@ -1210,11 +1195,15 @@ class LibvirtDriver(driver.ComputeDriver):
raise exception.VolumeDriverNotFound(driver_type=driver_type)
return self.volume_drivers[driver_type]
def _connect_volume(self, connection_info, instance):
def _connect_volume(self, context, connection_info, instance,
encryption=None):
vol_driver = self._get_volume_driver(connection_info)
vol_driver.connect_volume(connection_info, instance)
self._attach_encryptor(context, connection_info, encryption=encryption)
def _disconnect_volume(self, connection_info, instance):
def _disconnect_volume(self, context, connection_info, instance,
encryption=None):
self._detach_encryptor(context, connection_info, encryption=encryption)
vol_driver = self._get_volume_driver(connection_info)
vol_driver.disconnect_volume(connection_info, instance)
@ -1235,6 +1224,44 @@ class LibvirtDriver(driver.ComputeDriver):
connection_info=connection_info,
**encryption)
def _get_volume_encryption(self, context, connection_info):
"""Get the encryption metadata dict if it is not provided
"""
encryption = {}
if connection_info.get('data', {}).get('volume_id'):
volume_id = connection_info['data']['volume_id']
encryption = encryptors.get_encryption_metadata(context,
self._volume_api, volume_id, connection_info)
return encryption
def _attach_encryptor(self, context, connection_info, encryption):
"""Attach the frontend encryptor if one is required by the volume.
The request context is only used when an encryption metadata dict is
not provided. The encryption metadata dict being populated is then used
to determine if an attempt to attach the encryptor should be made.
"""
if encryption is None:
encryption = self._get_volume_encryption(context, connection_info)
if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.attach_volume(context, **encryption)
def _detach_encryptor(self, context, connection_info, encryption):
"""Detach the frontend encryptor if one is required by the volume.
The request context is only used when an encryption metadata dict is
not provided. The encryption metadata dict being populated is then used
to determine if an attempt to detach the encryptor should be made.
"""
if encryption is None:
encryption = self._get_volume_encryption(context, connection_info)
if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.detach_volume(**encryption)
def _check_discard_for_attach_volume(self, conf, instance):
"""Perform some checks for volumes configured for discard support.
@ -1277,7 +1304,8 @@ class LibvirtDriver(driver.ComputeDriver):
"block size") % CONF.libvirt.virt_type
raise exception.InvalidHypervisorType(msg)
self._connect_volume(connection_info, instance)
self._connect_volume(context, connection_info, instance,
encryption=encryption)
disk_info = blockinfo.get_info_from_bdm(
instance, CONF.libvirt.virt_type, instance.image_meta, bdm)
if disk_info['bus'] == 'scsi':
@ -1291,11 +1319,6 @@ class LibvirtDriver(driver.ComputeDriver):
state = guest.get_power_state(self._host)
live = state in (power_state.RUNNING, power_state.PAUSED)
if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
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
@ -1312,7 +1335,8 @@ class LibvirtDriver(driver.ComputeDriver):
LOG.exception(_('Failed to attach volume at mountpoint: %s'),
mountpoint, instance=instance)
with excutils.save_and_reraise_exception():
self._disconnect_volume(connection_info, instance)
self._disconnect_volume(context, connection_info, instance,
encryption=encryption)
def _swap_volume(self, guest, disk_path, conf, resize_to):
"""Swap existing disk with a new block device."""
@ -1370,7 +1394,7 @@ class LibvirtDriver(driver.ComputeDriver):
finally:
self._host.write_instance_config(xml)
def swap_volume(self, old_connection_info,
def swap_volume(self, context, old_connection_info,
new_connection_info, instance, mountpoint, resize_to):
guest = self._host.get_guest(instance)
@ -1391,19 +1415,19 @@ class LibvirtDriver(driver.ComputeDriver):
# LibvirtConfigGuestDisk object it returns. We do not explicitly save
# this to the BDM here as the upper compute swap_volume method will
# eventually do this for us.
self._connect_volume(new_connection_info, instance)
self._connect_volume(context, new_connection_info, instance)
conf = self._get_volume_config(new_connection_info, disk_info)
if not conf.source_path:
self._disconnect_volume(new_connection_info, instance)
self._disconnect_volume(context, new_connection_info, instance)
raise NotImplementedError(_("Swap only supports host devices"))
try:
self._swap_volume(guest, disk_dev, conf, resize_to)
except exception.VolumeRebaseFailed:
with excutils.save_and_reraise_exception():
self._disconnect_volume(new_connection_info, instance)
self._disconnect_volume(context, new_connection_info, instance)
self._disconnect_volume(old_connection_info, instance)
self._disconnect_volume(context, old_connection_info, instance)
def _get_existing_domain_xml(self, instance, network_info,
block_device_info=None):
@ -1429,20 +1453,15 @@ class LibvirtDriver(driver.ComputeDriver):
state = guest.get_power_state(self._host)
live = state in (power_state.RUNNING, power_state.PAUSED)
# The volume must be detached from the VM before disconnecting it
# from its encryptor. Otherwise, the encryptor may report that the
# volume is still in use.
# NOTE(lyarwood): The volume must be detached from the VM before
# detaching any attached encryptors or disconnecting the underlying
# volume in _disconnect_volume. Otherwise, the encryptor or volume
# driver may report that the volume is still in use.
wait_for_detach = guest.detach_device_with_retry(guest.get_disk,
disk_dev,
live=live)
wait_for_detach()
if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.detach_volume(**encryption)
except exception.InstanceNotFound:
# NOTE(zhaoqin): If the instance does not exist, _lookup_by_name()
# will throw InstanceNotFound exception. Need to
@ -1463,7 +1482,12 @@ class LibvirtDriver(driver.ComputeDriver):
else:
raise
self._disconnect_volume(connection_info, instance)
# NOTE(lyarwood): We can provide None as the request context here as we
# already have the encryption metadata dict from the compute layer.
# This avoids the need to add the request context to the signature of
# detach_volume requiring changes across all drivers.
self._disconnect_volume(None, connection_info, instance,
encryption=encryption)
def extend_volume(self, connection_info, instance):
try:
@ -3689,7 +3713,7 @@ class LibvirtDriver(driver.ComputeDriver):
disk = self.image_backend.by_name(instance, name, image_type)
return disk.libvirt_fs_info("/", "ploop")
def _get_guest_storage_config(self, instance, image_meta,
def _get_guest_storage_config(self, context, instance, image_meta,
disk_info,
rescue, block_device_info,
inst_type, os_type):
@ -3800,7 +3824,7 @@ class LibvirtDriver(driver.ComputeDriver):
connection_info = vol['connection_info']
vol_dev = block_device.prepend_dev(vol['mount_device'])
info = disk_mapping[vol_dev]
self._connect_volume(connection_info, instance)
self._connect_volume(context, connection_info, instance)
if scsi_controller and scsi_controller.model == 'virtio-scsi':
info['unit'] = disk_mapping['unit']
disk_mapping['unit'] += 1
@ -4890,7 +4914,7 @@ class LibvirtDriver(driver.ComputeDriver):
image_meta)
self._set_clock(guest, instance.os_type, image_meta, virt_type)
storage_configs = self._get_guest_storage_config(
storage_configs = self._get_guest_storage_config(context,
instance, image_meta, disk_info, rescue, block_device_info,
flavor, guest.os_type)
for config in storage_configs:
@ -5116,14 +5140,15 @@ class LibvirtDriver(driver.ComputeDriver):
# workaround, see libvirt/compat.py
return guest.get_info(self._host)
def _create_domain_setup_lxc(self, instance, image_meta,
def _create_domain_setup_lxc(self, context, instance, image_meta,
block_device_info):
inst_path = libvirt_utils.get_instance_path(instance)
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
root_disk = block_device.get_root_bdm(block_device_mapping)
if root_disk:
self._connect_volume(root_disk['connection_info'], instance)
self._connect_volume(context, root_disk['connection_info'],
instance)
disk_path = root_disk['connection_info']['data']['device_path']
# NOTE(apmelton) - Even though the instance is being booted from a
@ -5172,7 +5197,8 @@ class LibvirtDriver(driver.ComputeDriver):
disk_api.teardown_container(container_dir=container_dir)
@contextlib.contextmanager
def _lxc_disk_handler(self, instance, image_meta, block_device_info):
def _lxc_disk_handler(self, context, instance, image_meta,
block_device_info):
"""Context manager to handle the pre and post instance boot,
LXC specific disk operations.
@ -5186,7 +5212,8 @@ class LibvirtDriver(driver.ComputeDriver):
yield
return
self._create_domain_setup_lxc(instance, image_meta, block_device_info)
self._create_domain_setup_lxc(context, instance, image_meta,
block_device_info)
try:
yield
@ -5252,23 +5279,6 @@ class LibvirtDriver(driver.ComputeDriver):
destroy_disks_on_failure=False):
"""Do required network setup and create domain."""
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
for vol in block_device_mapping:
connection_info = vol['connection_info']
if ('data' in connection_info and
'volume_id' in connection_info['data']):
volume_id = connection_info['data']['volume_id']
encryption = encryptors.get_encryption_metadata(
context, self._volume_api, volume_id, connection_info)
if encryption:
encryptor = self._get_volume_encryptor(connection_info,
encryption)
encryptor.attach_volume(context, **encryption)
timeout = CONF.vif_plugging_timeout
if (self._conn_supports_start_paused and
utils.is_neutron() and not
@ -5288,7 +5298,8 @@ class LibvirtDriver(driver.ComputeDriver):
network_info)
self.firewall_driver.prepare_instance_filter(instance,
network_info)
with self._lxc_disk_handler(instance, instance.image_meta,
with self._lxc_disk_handler(context, instance,
instance.image_meta,
block_device_info):
guest = self._create_domain(
xml, pause=pause, power_on=power_on,
@ -7208,7 +7219,7 @@ class LibvirtDriver(driver.ComputeDriver):
for bdm in block_device_mapping:
connection_info = bdm['connection_info']
self._connect_volume(connection_info, instance)
self._connect_volume(context, connection_info, instance)
# We call plug_vifs before the compute manager calls
# ensure_filtering_rules_for_instance, to ensure bridge is set up
@ -7407,7 +7418,7 @@ class LibvirtDriver(driver.ComputeDriver):
multipath_id = vol['connection_info']['data']['multipath_id']
connection_info['data']['multipath_id'] = multipath_id
self._disconnect_volume(connection_info, instance)
self._disconnect_volume(context, connection_info, instance)
def post_live_migration_at_source(self, context, instance, network_info):
"""Unplug VIFs from networks at source.
@ -7763,7 +7774,7 @@ class LibvirtDriver(driver.ComputeDriver):
block_device_info)
for vol in block_device_mapping:
connection_info = vol['connection_info']
self._disconnect_volume(connection_info, instance)
self._disconnect_volume(context, connection_info, instance)
disk_info = self._get_instance_disk_info(instance, block_device_info)