libvirt: Save device_path in connection_info when booting from volume

If you boot an instance from a volume and later terminate it, the
libvirt volume driver disconnect_volume method does not have the
'device_path' key in connection_info['data'].  However, if you
attach a volume to an existing instance and then detach it,
the disconnect_volume method would have the 'device_path' key in
connection_info['data'].  Having the 'device_path' key would be
useful for some volume drivers to determine the device path of the
volume.  This patch saves the 'device_path' in connection_info['data']
when _create_domain_and_network is called, so it could be later used.

Change-Id: I8ebb5f3c2e7a81b11d776f8c0a15f3491ed273be
Closes-Bug: #1291007
This commit is contained in:
Thang Pham 2014-06-05 11:43:18 -04:00
parent 83041380c8
commit d19c75c19d
2 changed files with 85 additions and 2 deletions

View File

@ -7319,6 +7319,88 @@ class LibvirtConnTestCase(test.TestCase):
def test_create_with_network_events_non_neutron(self, is_neutron):
self._test_create_with_network_events()
@mock.patch('nova.volume.encryptors.get_encryption_metadata')
@mock.patch('nova.virt.libvirt.blockinfo.get_info_from_bdm')
def test_create_with_bdm(self, get_info_from_bdm, get_encryption_metadata):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
mock_dom = mock.MagicMock()
mock_encryption_meta = mock.MagicMock()
get_encryption_metadata.return_value = mock_encryption_meta
fake_xml = """
<domain>
<name>instance-00000001</name>
<memory>1048576</memory>
<vcpu>1</vcpu>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='raw' cache='none'/>
<source file='/path/fake-volume1'/>
<target dev='vda' bus='virtio'/>
</disk>
</devices>
</domain>
"""
fake_volume_id = "fake-volume-id"
connection_info = {"driver_volume_type": "fake",
"data": {"access_mode": "rw",
"volume_id": fake_volume_id}}
def fake_getitem(*args, **kwargs):
fake_bdm = {'connection_info': connection_info,
'mount_device': '/dev/vda'}
return fake_bdm.get(args[0])
mock_volume = mock.MagicMock()
mock_volume.__getitem__.side_effect = fake_getitem
bdi = {'block_device_mapping': [mock_volume]}
network_info = [network_model.VIF(id='1'),
network_model.VIF(id='2', active=True)]
disk_info = {'bus': 'virtio', 'type': 'file',
'dev': 'vda'}
get_info_from_bdm.return_value = disk_info
with contextlib.nested(
mock.patch.object(conn, '_connect_volume'),
mock.patch.object(conn, '_get_volume_encryptor'),
mock.patch.object(conn, 'plug_vifs'),
mock.patch.object(conn.firewall_driver, 'setup_basic_filtering'),
mock.patch.object(conn.firewall_driver,
'prepare_instance_filter'),
mock.patch.object(conn, '_create_domain'),
mock.patch.object(conn.firewall_driver, 'apply_instance_filter'),
) as (connect_volume, get_volume_encryptor, plug_vifs,
setup_basic_filtering, prepare_instance_filter, create_domain,
apply_instance_filter):
connect_volume.return_value = mock.MagicMock(
source_path='/path/fake-volume1')
create_domain.return_value = mock_dom
domain = conn._create_domain_and_network(self.context, fake_xml,
instance, network_info,
block_device_info=bdi)
get_info_from_bdm.assert_called_once_with(CONF.libvirt.virt_type,
mock_volume)
connect_volume.assert_called_once_with(connection_info, disk_info)
self.assertEqual(connection_info['data']['device_path'],
'/path/fake-volume1')
mock_volume.save.assert_called_once_with(self.context)
get_encryption_metadata.assert_called_once_with(self.context,
conn._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)
prepare_instance_filter.assert_called_once_with(instance,
network_info)
create_domain.assert_called_once_with(fake_xml, instance=instance,
launch_flags=0,
power_on=True)
self.assertEqual(mock_dom, domain)
def test_get_neutron_events(self):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
network_info = [network_model.VIF(id='1'),

View File

@ -3604,12 +3604,13 @@ class LibvirtDriver(driver.ComputeDriver):
conf = self._connect_volume(connection_info, disk_info)
# cache device_path in connection_info -- required by encryptors
if (not reboot and 'data' in connection_info and
'volume_id' in connection_info['data']):
if 'data' in connection_info:
connection_info['data']['device_path'] = conf.source_path
vol['connection_info'] = connection_info
vol.save(context)
if (not reboot and '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)