Skip to content

Commit

Permalink
Merge "libvirt: update guest time after suspend"
Browse files Browse the repository at this point in the history
  • Loading branch information
Jenkins authored and openstack-gerrit committed Jul 22, 2016
2 parents f5b43ce + 0376da0 commit 414df1e
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 1 deletion.
6 changes: 5 additions & 1 deletion nova/tests/unit/virt/libvirt/fakelibvirt.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ def _reset():
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

Expand Down Expand Up @@ -563,6 +564,9 @@ def interfaceStats(self, device):
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

Expand Down
8 changes: 8 additions & 0 deletions nova/tests/unit/virt/libvirt/test_guest.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ def test_resume(self):
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)])
Expand Down
43 changes: 43 additions & 0 deletions nova/virt/libvirt/guest.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@
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
Expand Down Expand Up @@ -145,13 +147,54 @@ def poweroff(self):
"""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()

def resume(self):
"""Resumes a suspended guest."""
self._domain.resume()
self._sync_guest_time()

def enable_hairpin(self):
"""Enables hairpin mode for this guest."""
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/set_guest_time-736939fe725cbdab.yaml
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 414df1e

Please sign in to comment.