From 4445d421ed0ffaf76a5c589170f731afbf9071f3 Mon Sep 17 00:00:00 2001
From: Nikos Skalkotos <skalkoto@grnet.gr>
Date: Tue, 9 Sep 2014 18:11:50 +0300
Subject: [PATCH] windows: Fix a bug in the VirtIO installation code

Make sure the guestfs VM is killed before we launch the VM that
installs the VirtIO drivers.
---
 image_creator/os_type/windows/__init__.py | 79 ++++++++++++++---------
 1 file changed, 47 insertions(+), 32 deletions(-)

diff --git a/image_creator/os_type/windows/__init__.py b/image_creator/os_type/windows/__init__.py
index a664c46..791c0f2 100644
--- a/image_creator/os_type/windows/__init__.py
+++ b/image_creator/os_type/windows/__init__.py
@@ -721,6 +721,7 @@ class Windows(OSBase):
             self.out.output("failed! See: `%s' for the full output" % log.name)
             if i < retries - 1:
                 self.out.output("retrying ...", False)
+                time.sleep(1)
 
         raise FatalError("Connection to the Windows VM failed after %d retries"
                          % retries)
@@ -866,8 +867,17 @@ class Windows(OSBase):
 
             tmp = uuid.uuid4().hex
             self.image.g.mkdir_p("%s/%s" % (self.systemroot, tmp))
-            self._add_cleanup('virtio', self.image.g.rm_rf,
-                              "%s/%s" % (self.systemroot, tmp))
+
+            # This is a hack. We create a function here and pass it to
+            # _add_cleanup because self.image.g may change and the _add_cleanup
+            # will cache it which is wrong. For older versions of the guestfs
+            # library we recreate the g handler in enable_guestfs() and the
+            # program will crash if cleanup retains an older value for the
+            # guestfs handler.
+            def remove_tmp():
+                self.image.g.rm_rf("%s/%s" % (self.systemroot, tmp))
+
+            self._add_cleanup('virtio', remove_tmp)
 
             for fname in os.listdir(dirname):
                 full_path = os.path.join(dirname, fname)
@@ -929,38 +939,43 @@ class Windows(OSBase):
     def _boot_virtio_vm(self):
         """Boot the media and install the VirtIO drivers"""
 
-        timeout = self.sysprep_params['boot_timeout'].value
-        shutdown_timeout = self.sysprep_params['shutdown_timeout'].value
-        virtio_timeout = self.sysprep_params['virtio_timeout'].value
-        self.out.output("Starting Windows VM ...", False)
-        booted = False
+        old_windows = self.check_version(6, 1) <= 0
+        self.image.disable_guestfs()
         try:
-            if self.check_version(6, 1) <= 0:
-                self.vm.start()
-            else:
-                self.vm.interface = 'ide'
-                self.vm.start(extra_disk=('/dev/null', 'virtio'))
-                self.vm.interface = 'virtio'
-
-            self.out.success("started (console on VNC display: %d)" %
-                             self.vm.display)
-            self.out.output("Waiting for Windows to boot ...", False)
-            if not self.vm.wait_on_serial(timeout):
-                raise FatalError("Windows VM booting timed out!")
-            self.out.success('done')
-            booted = True
-            self.out.output("Installing new drivers ...", False)
-            if not self.vm.wait_on_serial(virtio_timeout):
-                raise FatalError("Windows VirtIO installation timed out!")
-            self.out.success('done')
-            self.out.output('Shutting down ...', False)
-            (_, stderr, rc) = self.vm.wait(shutdown_timeout)
-            if rc != 0 or "terminating on signal" in stderr:
-                raise FatalError("Windows VM died unexpectedly!\n\n"
-                                 "(rc=%d)\n%s" % (rc, stderr))
-            self.out.success('done')
+            timeout = self.sysprep_params['boot_timeout'].value
+            shutdown_timeout = self.sysprep_params['shutdown_timeout'].value
+            virtio_timeout = self.sysprep_params['virtio_timeout'].value
+            self.out.output("Starting Windows VM ...", False)
+            booted = False
+            try:
+                if old_windows:
+                    self.vm.start()
+                else:
+                    self.vm.interface = 'ide'
+                    self.vm.start(extra_disk=('/dev/null', 'virtio'))
+                    self.vm.interface = 'virtio'
+
+                self.out.success("started (console on VNC display: %d)" %
+                                 self.vm.display)
+                self.out.output("Waiting for Windows to boot ...", False)
+                if not self.vm.wait_on_serial(timeout):
+                    raise FatalError("Windows VM booting timed out!")
+                self.out.success('done')
+                booted = True
+                self.out.output("Installing new drivers ...", False)
+                if not self.vm.wait_on_serial(virtio_timeout):
+                    raise FatalError("Windows VirtIO installation timed out!")
+                self.out.success('done')
+                self.out.output('Shutting down ...', False)
+                (_, stderr, rc) = self.vm.wait(shutdown_timeout)
+                if rc != 0 or "terminating on signal" in stderr:
+                    raise FatalError("Windows VM died unexpectedly!\n\n"
+                                     "(rc=%d)\n%s" % (rc, stderr))
+                self.out.success('done')
+            finally:
+                self.vm.stop(shutdown_timeout if booted else 1, fatal=False)
         finally:
-            self.vm.stop(shutdown_timeout if booted else 1, fatal=False)
+            self.image.enable_guestfs()
 
         with self.mount(readonly=True, silent=True):
             self.virtio_state = self.compute_virtio_state()
-- 
GitLab