libvirt: add support for hyperv timer source with windows guests

The hyperv timer source enables Windows guests to keep accurate
time, much like kvmclock does for Linux guests. It should be
enabled for all windows guests, as it doesn't harm older windows
versions which don't know about it.

Related-bug: #1400315
Change-Id: I6af05b4e8e0b2145733c0f301c04555da23b7da8
This commit is contained in:
Daniel P. Berrange 2014-11-20 12:24:55 +00:00
parent b6a5b25335
commit 989eac8b74
2 changed files with 56 additions and 3 deletions

View File

@ -1540,8 +1540,10 @@ class LibvirtConnTestCase(test.NoDBTestCase):
else:
self.assertEqual(2, len(cfg.clock.timers))
@mock.patch.object(host.Host, 'has_min_version')
@mock.patch.object(objects.Flavor, 'get_by_id')
def test_get_guest_config_windows(self, mock_flavor):
def test_get_guest_config_windows(self, mock_flavor, mock_version):
mock_version.return_value = False
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance_ref = objects.Instance(**self.test_instance)
instance_ref['os_type'] = 'windows'
@ -1559,6 +1561,41 @@ class LibvirtConnTestCase(test.NoDBTestCase):
vconfig.LibvirtConfigGuestClock)
self.assertEqual(cfg.clock.offset, "localtime")
self.assertEqual(3, len(cfg.clock.timers), cfg.clock.timers)
self.assertEqual("pit", cfg.clock.timers[0].name)
self.assertEqual("rtc", cfg.clock.timers[1].name)
self.assertEqual("hpet", cfg.clock.timers[2].name)
self.assertFalse(cfg.clock.timers[2].present)
@mock.patch.object(host.Host, 'has_min_version')
@mock.patch.object(objects.Flavor, 'get_by_id')
def test_get_guest_config_windows_timer(self, mock_flavor, mock_version):
mock_version.return_value = True
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
instance_ref = objects.Instance(**self.test_instance)
instance_ref['os_type'] = 'windows'
flavor = instance_ref.get_flavor()
flavor.extra_specs = {}
mock_flavor.return_value = flavor
disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type,
instance_ref)
cfg = conn._get_guest_config(instance_ref,
_fake_network_info(self.stubs, 1),
{}, disk_info)
self.assertIsInstance(cfg.clock,
vconfig.LibvirtConfigGuestClock)
self.assertEqual(cfg.clock.offset, "localtime")
self.assertEqual(4, len(cfg.clock.timers), cfg.clock.timers)
self.assertEqual("pit", cfg.clock.timers[0].name)
self.assertEqual("rtc", cfg.clock.timers[1].name)
self.assertEqual("hpet", cfg.clock.timers[2].name)
self.assertFalse(cfg.clock.timers[2].present)
self.assertEqual("hypervclock", cfg.clock.timers[3].name)
self.assertTrue(cfg.clock.timers[3].present)
@mock.patch.object(objects.Flavor, 'get_by_id')
def test_get_guest_config_with_two_nics(self, mock_flavor):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)

View File

@ -361,6 +361,10 @@ MIN_LIBVIRT_NUMA_TOPOLOGY_VERSION = (1, 0, 4)
# fsFreeze/fsThaw requirement
MIN_LIBVIRT_FSFREEZE_VERSION = (1, 2, 5)
# Hyper-V paravirtualized time source
MIN_LIBVIRT_HYPERV_TIMER_VERSION = (1, 2, 2)
MIN_QEMU_HYPERV_TIMER_VERSION = (2, 0, 0)
class LibvirtDriver(driver.ComputeDriver):
@ -3624,9 +3628,9 @@ class LibvirtDriver(driver.ComputeDriver):
guest.set_clock(clk)
if virt_type == "kvm":
self._set_kvm_timers(clk, image_meta)
self._set_kvm_timers(clk, os_type, image_meta)
def _set_kvm_timers(self, clk, image_meta):
def _set_kvm_timers(self, clk, os_type, image_meta):
# TODO(berrange) One day this should be per-guest
# OS type configurable
tmpit = vconfig.LibvirtConfigGuestTimer()
@ -3649,6 +3653,18 @@ class LibvirtDriver(driver.ComputeDriver):
tmhpet.present = False
clk.add_timer(tmhpet)
# With new enough QEMU we can provide Windows guests
# with the paravirtualized hyperv timer source. This
# is the windows equiv of kvm-clock, allowing Windows
# guests to accurately keep time.
if (os_type == 'windows' and
self._host.has_min_version(MIN_LIBVIRT_HYPERV_TIMER_VERSION,
MIN_QEMU_HYPERV_TIMER_VERSION)):
tmhyperv = vconfig.LibvirtConfigGuestTimer()
tmhyperv.name = "hypervclock"
tmhyperv.present = True
clk.add_timer(tmhyperv)
def _create_serial_console_devices(self, guest, instance, flavor,
image_meta):
if CONF.serial_console.enabled: