Merge "libvirt: update guest time after suspend"
This commit is contained in:
commit
414df1e56e
|
@ -124,7 +124,8 @@ VIR_ERR_INTERNAL_ERROR = 950
|
|||
VIR_ERR_CONFIG_UNSUPPORTED = 951
|
||||
VIR_ERR_NO_NODE_DEVICE = 667
|
||||
VIR_ERR_NO_SECRET = 66
|
||||
|
||||
VIR_ERR_AGENT_UNRESPONSIVE = 86
|
||||
VIR_ERR_ARGUMENT_UNSUPPORTED = 74
|
||||
# Readonly
|
||||
VIR_CONNECT_RO = 1
|
||||
|
||||
|
@ -563,6 +564,9 @@ class Domain(object):
|
|||
def blockStats(self, device):
|
||||
return [2, 10000242400, 234, 2343424234, 34]
|
||||
|
||||
def setTime(self, time=None, flags=0):
|
||||
pass
|
||||
|
||||
def suspend(self):
|
||||
self._state = VIR_DOMAIN_PAUSED
|
||||
|
||||
|
|
|
@ -139,6 +139,14 @@ class GuestTestCase(test.NoDBTestCase):
|
|||
self.guest.resume()
|
||||
self.domain.resume.assert_called_once_with()
|
||||
|
||||
@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.domain.setTime.assert_called_once_with(time={
|
||||
'nseconds': 125000000,
|
||||
'seconds': 1234567890})
|
||||
|
||||
def test_get_vcpus_info(self):
|
||||
self.domain.vcpus.return_value = ([(0, 1, int(10290000000), 2)],
|
||||
[(True, True)])
|
||||
|
|
|
@ -33,11 +33,13 @@ from oslo_service import loopingcall
|
|||
from oslo_utils import encodeutils
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
import time
|
||||
|
||||
from nova.compute import power_state
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.i18n import _LE
|
||||
from nova.i18n import _LW
|
||||
from nova import utils
|
||||
from nova.virt import hardware
|
||||
from nova.virt.libvirt import compat
|
||||
|
@ -145,6 +147,46 @@ class Guest(object):
|
|||
"""Stops a running guest."""
|
||||
self._domain.destroy()
|
||||
|
||||
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
|
||||
tolerance.
|
||||
|
||||
It is not guaranteed that the time is actually set (it depends on guest
|
||||
environment, especially QEMU agent presence) or that the set time is
|
||||
very precise (NTP in the guest should take care of it if needed).
|
||||
"""
|
||||
t = time.time()
|
||||
seconds = int(t)
|
||||
nseconds = int((t - seconds) * 10 ** 9)
|
||||
try:
|
||||
self._domain.setTime(time={'seconds': seconds,
|
||||
'nseconds': nseconds})
|
||||
except libvirt.libvirtError as e:
|
||||
code = e.get_error_code()
|
||||
if code == libvirt.VIR_ERR_AGENT_UNRESPONSIVE:
|
||||
LOG.debug('Failed to set time: QEMU agent unresponsive',
|
||||
instance_uuid=self.uuid)
|
||||
elif code == libvirt.VIR_ERR_NO_SUPPORT:
|
||||
LOG.debug('Failed to set time: not supported',
|
||||
instance_uuid=self.uuid)
|
||||
elif code == libvirt.VIR_ERR_ARGUMENT_UNSUPPORTED:
|
||||
LOG.debug('Failed to set time: agent not configured',
|
||||
instance_uuid=self.uuid)
|
||||
else:
|
||||
LOG.warning(_LW('Failed to set time: %(reason)s'),
|
||||
{'reason': e}, instance_uuid=self.uuid)
|
||||
except Exception as ex:
|
||||
# The highest priority is not to let this method crash and thus
|
||||
# disrupt its caller in any way. So we swallow this error here,
|
||||
# to be absolutely safe.
|
||||
LOG.debug('Failed to set time: %(reason)s',
|
||||
{'reason': ex}, instance_uuid=self.uuid)
|
||||
else:
|
||||
LOG.debug('Time updated to: %d.%09d', seconds, nseconds,
|
||||
instance_uuid=self.uuid)
|
||||
|
||||
def inject_nmi(self):
|
||||
"""Injects an NMI to a guest."""
|
||||
self._domain.injectNMI()
|
||||
|
@ -152,6 +194,7 @@ class Guest(object):
|
|||
def resume(self):
|
||||
"""Resumes a suspended guest."""
|
||||
self._domain.resume()
|
||||
self._sync_guest_time()
|
||||
|
||||
def enable_hairpin(self):
|
||||
"""Enables hairpin mode for this guest."""
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
features:
|
||||
- Libvirt driver will attempt to update the time of a suspended and/or
|
||||
a migrated guest in order to keep the guest clock in sync.
|
||||
This operation will require the guest agent to be
|
||||
configured and running in order to be able to run. However, this operation
|
||||
will not be disruptive.
|
Loading…
Reference in New Issue