libvirt: sync time on resumed from suspend instances

Time is not being synchronized for migrated or resumed from suspend instances
as guest.resume() method is not being called on these operations.

Calling sync_guest_time directly in the resume method as well as in
finish_migration.

Resolves-Bug: #1636565

Change-Id: Ie140bc0912e6b312d3fcbee7e9650a81076eda4d
This commit is contained in:
Vladik Romanovsky 2016-10-19 12:21:40 -04:00
parent f23646d2cb
commit cd1af7abdd
4 changed files with 29 additions and 9 deletions

View File

@ -11617,9 +11617,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
return_value='fake_pci_devs'),
mock.patch.object(utils, 'get_image_from_system_metadata'),
mock.patch.object(blockinfo, 'get_disk_info'),
mock.patch.object(guest, 'sync_guest_time'),
mock.patch.object(drvr, '_wait_for_running',
side_effect=loopingcall.LoopingCallDone()),
) as (_get_existing_domain_xml, _create_domain_and_network,
_attach_pci_devices, get_instance_pci_devs, get_image_metadata,
get_disk_info):
get_disk_info, mock_sync_time, mock_wait):
get_image_metadata.return_value = {'bar': 234}
disk_info = {'foo': 123}
@ -11634,6 +11637,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
instance, network_info, disk_info,
block_device_info=block_device_info,
vifs_already_plugged=True)])
self.assertTrue(mock_sync_time.called)
_attach_pci_devices.assert_has_calls([mock.call(guest,
'fake_pci_devs')])
@ -15603,6 +15607,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
self.fake_create_domain_called = True
self.assertEqual(powered_on, power_on)
self.assertTrue(vifs_already_plugged)
return libvirt_guest.Guest('fake_dom')
def fake_enable_hairpin():
pass
@ -15678,10 +15683,16 @@ class LibvirtDriverTestCase(test.NoDBTestCase):
resize_instance, self.fake_disk_resize_called)
def test_finish_migration_resize(self):
self._test_finish_migration(True, resize_instance=True)
with mock.patch('nova.virt.libvirt.guest.Guest.sync_guest_time'
) as mock_guest_time:
self._test_finish_migration(True, resize_instance=True)
self.assertTrue(mock_guest_time.called)
def test_finish_migration_power_on(self):
self._test_finish_migration(True)
with mock.patch('nova.virt.libvirt.guest.Guest.sync_guest_time'
) as mock_guest_time:
self._test_finish_migration(True)
self.assertTrue(mock_guest_time.called)
def test_finish_migration_power_off(self):
self._test_finish_migration(False)

View File

@ -139,7 +139,7 @@ class GuestTestCase(test.NoDBTestCase):
@mock.patch('time.time', return_value=1234567890.125)
def test_time_sync_no_errors(self, time_mock):
self.domain.setTime.side_effect = fakelibvirt.libvirtError('error')
self.guest.resume()
self.guest.sync_guest_time()
self.domain.setTime.assert_called_once_with(time={
'nseconds': 125000000,
'seconds': 1234567890})

View File

@ -2345,7 +2345,9 @@ class LibvirtDriver(driver.ComputeDriver):
def unpause(self, instance):
"""Unpause paused VM instance."""
self._host.get_guest(instance).resume()
guest = self._host.get_guest(instance)
guest.resume()
guest.sync_guest_time()
def _clean_shutdown(self, instance, timeout, retry_interval):
"""Attempt to shutdown the instance gracefully.
@ -2478,6 +2480,10 @@ class LibvirtDriver(driver.ComputeDriver):
self._attach_pci_devices(guest,
pci_manager.get_instance_pci_devs(instance))
self._attach_sriov_ports(context, instance, guest, network_info)
timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_running,
instance)
timer.start(interval=0.5).wait()
guest.sync_guest_time()
def resume_state_on_host_boot(self, context, instance, network_info,
block_device_info=None):
@ -7264,7 +7270,8 @@ class LibvirtDriver(driver.ComputeDriver):
# and the status change in the port might go undetected by the neutron
# L2 agent (or neutron server) so neutron may not know that the VIF was
# unplugged in the first place and never send an event.
self._create_domain_and_network(context, xml, instance, network_info,
guest = self._create_domain_and_network(context, xml, instance,
network_info,
block_disk_info,
block_device_info=block_device_info,
power_on=power_on,
@ -7276,6 +7283,9 @@ class LibvirtDriver(driver.ComputeDriver):
instance)
timer.start(interval=0.5).wait()
# Sync guest time after migration.
guest.sync_guest_time()
LOG.debug("finish_migration finished successfully.", instance=instance)
def _cleanup_failed_migration(self, inst_base):

View File

@ -145,7 +145,7 @@ class Guest(object):
"""Stops a running guest."""
self._domain.destroy()
def _sync_guest_time(self):
def sync_guest_time(self):
"""Try to set VM time to the current value. This is typically useful
when clock wasn't running on the VM for some time (e.g. during
suspension or migration), especially if the time delay exceeds NTP
@ -190,9 +190,8 @@ class Guest(object):
self._domain.injectNMI()
def resume(self):
"""Resumes a suspended guest."""
"""Resumes a paused guest."""
self._domain.resume()
self._sync_guest_time()
def enable_hairpin(self):
"""Enables hairpin mode for this guest."""