[virt-tools-list] [virt-manager PATCH v2 2/6] virtManager: object: domain: Refactor guest time setting

Michael Weiser michael.weiser at gmx.de
Fri Jan 3 20:12:32 UTC 2020


Sleeping in a loop waiting for the qemu guest agent to come online
leaves an annoying progress dialog while the domain may actually be
fully useable already. Additionally, multiple progress dialogs can
actually accumulate on screen if the user manages to suspend/resume fast
enough or the timeout is just long enough.

To avoid these, we want to defer retries into a separate thread to allow
the progress dialog to disappear immediately after the actual action
completed.

In preparation for that, add a new class _vmmDomainSetTimeThread that
will eventually manage that separate thread for guest time setting
operations. Move the current code for waiting for the qemu guest agent
into it without any semantic changes.

Make set_time() and agent_read() of vmmDomain accessible from the
outside so that _vmmDomainSetTimeThread can call back into them. Add
has_agent() to be able to find out if the domain has an agent configured
without leaking the actual agent config.

Signed-off-by: Michael Weiser <michael.weiser at gmx.de>
Suggested-by: Cole Robinson <crobinso at redhat.com>
---
 virtManager/object/domain.py | 87 +++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 30 deletions(-)

diff --git a/virtManager/object/domain.py b/virtManager/object/domain.py
index 4a1c7587..355fca97 100644
--- a/virtManager/object/domain.py
+++ b/virtManager/object/domain.py
@@ -17,6 +17,7 @@ from virtinst import Guest
 from virtinst import log
 
 from .libvirtobject import vmmLibvirtObject
+from ..baseclass import vmmGObject
 from ..lib.libvirtenummap import LibvirtEnumMap
 
 
@@ -179,6 +180,42 @@ class vmmDomainSnapshot(vmmLibvirtObject):
         return False
 
 
+class _vmmDomainSetTimeThread(vmmGObject):
+    def __init__(self, domain):
+        vmmGObject.__init__(self)
+        self._domain = domain
+
+    def start(self):
+        # Only run the API for qemu and test drivers, they are the only ones
+        # that support it. This will save spamming logs with error output.
+        if not self._domain.conn.is_qemu() and not self._domain.conn.is_test():
+            return
+
+        if self._domain.conn.is_qemu():
+            # For qemu, only run the API if the VM has the qemu guest agent in
+            # the XML.
+            if not self._domain.has_agent():
+                return
+
+            # wait for agent to come online
+            maxwait = 5
+            sleep = 0.5
+            for _ in range(0, int(maxwait / sleep)):
+                if self._domain.agent_ready():
+                    break
+                log.debug("Waiting for qemu guest agent to come online...")
+                time.sleep(sleep)
+            else:
+                if not self._domain.agent_ready():
+                    log.debug("Giving up on qemu guest agent for time sync")
+                    return
+
+        self._domain.set_time()
+
+    def _cleanup(self):
+        pass
+
+
 class vmmDomain(vmmLibvirtObject):
     """
     Class wrapping virDomain libvirt objects. Is also extended to be
@@ -208,6 +245,7 @@ class vmmDomain(vmmLibvirtObject):
         self._domain_state_supported = False
 
         self.inspection = vmmInspectionData()
+        self._set_time_thread = _vmmDomainSetTimeThread(self)
 
     def _cleanup(self):
         for snap in self._snapshot_list or []:
@@ -1062,7 +1100,7 @@ class vmmDomain(vmmLibvirtObject):
         # looking at the domain state after revert will always come back as
         # paused, so look at the snapshot state instead
         if will_be_running:
-            self._set_time()
+            self._async_set_time()
 
     def create_snapshot(self, xml, redefine=False):
         flags = 0
@@ -1082,7 +1120,13 @@ class vmmDomain(vmmLibvirtObject):
                 return dev
         return None
 
-    def _agent_ready(self):
+    def has_agent(self):
+        """
+        Return True if domain has a guest agent defined.
+        """
+        return self._get_agent() is not None
+
+    def agent_ready(self):
         """
         Return connected state of an agent.
         """
@@ -1100,7 +1144,7 @@ class vmmDomain(vmmLibvirtObject):
         if not self.is_active():
             return
 
-        if self._agent_ready():
+        if self.agent_ready():
             self._ip_cache["qemuga"] = self._get_interface_addresses(
                 libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT)
 
@@ -1166,7 +1210,7 @@ class vmmDomain(vmmLibvirtObject):
     def refresh_snapshots(self):
         self._snapshot_list = None
 
-    def _set_time(self):
+    def set_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
@@ -1178,30 +1222,6 @@ class vmmDomain(vmmLibvirtObject):
         Heavily based on
         https://github.com/openstack/nova/commit/414df1e56ea9df700756a1732125e06c5d97d792.
         """
-        # Only run the API for qemu and test drivers, they are the only ones
-        # that support it. This will save spamming logs with error output.
-        if not self.conn.is_qemu() and not self.conn.is_test():
-            return
-
-        if self.conn.is_qemu():
-            # For qemu, only run the API if the VM has the qemu guest agent in
-            # the XML.
-            if not self._get_agent():
-                return
-
-            # wait for agent to come online
-            maxwait = 5
-            sleep = 0.5
-            for _ in range(0, int(maxwait / sleep)):
-                if self._agent_ready():
-                    break
-                log.debug("Waiting for qemu guest agent to come online...")
-                time.sleep(sleep)
-            else:
-                if not self._agent_ready():
-                    log.debug("Giving up on qemu guest agent for time sync")
-                    return
-
         t = time.time()
         seconds = int(t)
         nseconds = int((t - seconds) * 10 ** 9)
@@ -1212,6 +1232,13 @@ class vmmDomain(vmmLibvirtObject):
         except Exception as e:
             log.debug("Failed to set time: %s", e)
 
+    def _async_set_time(self):
+        """
+        Asynchronously try to set guest time and maybe wait for a guest agent
+        to come online using a separate thread.
+        """
+        self._set_time_thread.start()
+
 
     ########################
     # XML Parsing routines #
@@ -1352,7 +1379,7 @@ class vmmDomain(vmmLibvirtObject):
         sync_time = self.has_managed_save()
         self._backend.create()
         if sync_time:
-            self._set_time()
+            self._async_set_time()
 
     @vmmLibvirtObject.lifecycle_action
     def suspend(self):
@@ -1385,7 +1412,7 @@ class vmmDomain(vmmLibvirtObject):
     @vmmLibvirtObject.lifecycle_action
     def resume(self):
         self._backend.resume()
-        self._set_time()
+        self._async_set_time()
 
     @vmmLibvirtObject.lifecycle_action
     def save(self, meter=None):
-- 
2.24.1





More information about the virt-tools-list mailing list