libvirt: Avoid Glance.show on hard_reboot

When a Libvirt host is rebooted, we can optionally choose to automatically
spin back up the instances using the `resume_state_on_host_boot` call. This,
in turn, uses `_hard_reboot` to bring back the instances.

The problem is that `_get_guest_xml` which `_hard_reboot` is using is always
making a call to Glance.show since `image_meta` isn't being passed into it. In
addition to this being an extra latency-heavy call, this is big problem
because the request is *server-generated* not *user-generated* so we won't
have the necessary user-request context to make the Glance call.

In the absense of a general user-impersonation mechanism, the current
workaround is to use cached image-metadata, which works in this case as well.

So the fix is to pass that `image_meta` that we already pull from instance
metadata in `_hard_reboot` and pass it into `_get_guest_xml` and thus avoid
the extra request to Glance.

Change-Id: I2203ac709405ee784ee5ec017aa475575a46a0df
Closes-Bug: 1339386
This commit is contained in:
Rick Harris 2014-07-08 17:31:27 -05:00
parent 54d0f898f6
commit 65341b2547
2 changed files with 54 additions and 7 deletions

View File

@ -5664,7 +5664,12 @@ class LibvirtConnTestCase(test.TestCase,
conn._destroy(instance)
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance, block_device_info)
system_meta = utils.instance_sys_meta(instance)
image_meta = utils.get_image_from_system_metadata(system_meta)
conn._get_guest_xml(self.context, instance, network_info, disk_info,
image_meta=image_meta,
block_device_info=block_device_info,
write_to_disk=True).AndReturn(dummyxml)
disk_info_json = '[{"virt_disk_size": 2}]'
@ -5681,6 +5686,50 @@ class LibvirtConnTestCase(test.TestCase,
conn._hard_reboot(self.context, instance, network_info,
block_device_info)
@mock.patch('nova.openstack.common.loopingcall.FixedIntervalLoopingCall')
@mock.patch('nova.pci.pci_manager.get_instance_pci_devs')
@mock.patch('nova.virt.libvirt.LibvirtDriver._prepare_pci_devices_for_use')
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_domain_and_network')
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_images_and_backing')
@mock.patch('nova.virt.libvirt.LibvirtDriver._get_instance_disk_info')
@mock.patch('nova.virt.libvirt.utils.write_to_file')
@mock.patch('nova.virt.libvirt.utils.get_instance_path')
@mock.patch('nova.virt.libvirt.LibvirtDriver._get_guest_config')
@mock.patch('nova.virt.libvirt.blockinfo.get_disk_info')
@mock.patch('nova.virt.libvirt.LibvirtDriver._destroy')
def test_hard_reboot_doesnt_call_glance_show(self,
mock_destroy, mock_get_disk_info, mock_get_guest_config,
mock_get_instance_path, mock_write_to_file,
mock_get_instance_disk_info, mock_create_images_and_backing,
mock_create_domand_and_network, mock_prepare_pci_devices_for_use,
mock_get_instance_pci_devs, mock_looping_call):
"""For a hard reboot, we shouldn't need an additional call to glance
to get the image metadata.
This is important for automatically spinning up instances on a
host-reboot, since we won't have a user request context that'll allow
the Glance request to go through. We have to rely on the cached image
metadata, instead.
https://bugs.launchpad.net/nova/+bug/1339386
"""
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = db.instance_create(self.context, self.test_instance)
network_info = mock.MagicMock()
block_device_info = mock.MagicMock()
mock_get_disk_info.return_value = {}
mock_get_guest_config.return_value = mock.MagicMock()
mock_get_instance_path.return_value = '/foo'
mock_looping_call.return_value = mock.MagicMock()
conn._image_api = mock.MagicMock()
conn._hard_reboot(self.context, instance, network_info,
block_device_info)
self.assertFalse(conn._image_api.get.called)
def test_power_on(self):
def _check_xml_bus(name, xml, block_info):
@ -5733,12 +5782,9 @@ class LibvirtConnTestCase(test.TestCase,
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
with contextlib.nested(
mock.patch.object(conn, '_destroy', return_value=None),
mock.patch.object(conn, '_create_images_and_backing'),
mock.patch.object(conn, '_create_domain_and_network'),
mock.patch('nova.image.glance.get_remote_image_service',
return_value=(image_service_mock,
instance['image_ref']))):
mock.patch.object(conn, '_destroy', return_value=None),
mock.patch.object(conn, '_create_images_and_backing'),
mock.patch.object(conn, '_create_domain_and_network')):
conn.get_info = fake_get_info
conn._get_instance_disk_info = _check_xml_bus
conn._hard_reboot(self.context, instance, network_info,

View File

@ -2057,6 +2057,7 @@ class LibvirtDriver(driver.ComputeDriver):
# does we need to (re)generate the xml after the images
# are in place.
xml = self._get_guest_xml(context, instance, network_info, disk_info,
image_meta=image_meta,
block_device_info=block_device_info,
write_to_disk=True)
@ -3433,7 +3434,7 @@ class LibvirtDriver(driver.ComputeDriver):
def _get_guest_xml(self, context, instance, network_info, disk_info,
image_meta=None, rescue=None,
block_device_info=None, write_to_disk=False):
# We should get image metadata every time for generating xml
if image_meta is None:
image_ref = instance['image_ref']
image_meta = compute_utils.get_image_metadata(