[virt-tools-list] [PATCH virt-viewer v3 3/3] spice: hook into QMP port

marcandre.lureau at redhat.com marcandre.lureau at redhat.com
Fri Jan 18 09:12:15 UTC 2019


From: Marc-André Lureau <marcandre.lureau at redhat.com>

If the "org.qemu.monitor.qmp.0" port is available:
- enable the VM UI
- get and follow the VM state
- send the requested VM actions

This requires spice-gtk version 0.36 with SpiceQmpPort helper.

Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>
Acked-by: Victor Toso <victortoso at redhat.com>
---
 configure.ac                    |   2 +-
 src/virt-viewer-session-spice.c | 105 +++++++++++++++++++++++++++++++-
 2 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 5598c61..50cd91a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,7 +24,7 @@ LIBXML2_REQUIRED="2.6.0"
 LIBVIRT_REQUIRED="0.10.0"
 LIBVIRT_GLIB_REQUIRED="0.1.8"
 GTK_VNC_REQUIRED="0.4.0"
-SPICE_GTK_REQUIRED="0.35"
+SPICE_GTK_REQUIRED="0.36"
 SPICE_PROTOCOL_REQUIRED="0.12.7"
 GOVIRT_REQUIRED="0.3.3"
 REST_REQUIRED="0.8"
diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c
index 49a7775..31447dc 100644
--- a/src/virt-viewer-session-spice.c
+++ b/src/virt-viewer-session-spice.c
@@ -52,6 +52,7 @@ struct _VirtViewerSessionSpicePrivate {
     gboolean did_auto_conf;
     VirtViewerFileTransferDialog *file_transfer_dialog;
     GError *disconnect_error;
+    SpiceQmpPort *qmp;
 };
 
 #define VIRT_VIEWER_SESSION_SPICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_SESSION_SPICE, VirtViewerSessionSpicePrivate))
@@ -82,6 +83,7 @@ static void virt_viewer_session_spice_smartcard_insert(VirtViewerSession *sessio
 static void virt_viewer_session_spice_smartcard_remove(VirtViewerSession *session);
 static gboolean virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self);
 static void virt_viewer_session_spice_apply_monitor_geometry(VirtViewerSession *self, GHashTable *monitors);
+static void virt_viewer_session_spice_vm_action(VirtViewerSession *self, gint action);
 
 static void virt_viewer_session_spice_clear_displays(VirtViewerSessionSpice *self)
 {
@@ -262,6 +264,7 @@ virt_viewer_session_spice_class_init(VirtViewerSessionSpiceClass *klass)
     dclass->apply_monitor_geometry = virt_viewer_session_spice_apply_monitor_geometry;
     dclass->can_share_folder = virt_viewer_session_spice_can_share_folder;
     dclass->can_retry_auth = virt_viewer_session_spice_can_retry_auth;
+    dclass->vm_action = virt_viewer_session_spice_vm_action;
 
     g_type_class_add_private(klass, sizeof(VirtViewerSessionSpicePrivate));
 
@@ -461,6 +464,8 @@ virt_viewer_session_spice_close(VirtViewerSession *session)
 
     g_object_add_weak_pointer(G_OBJECT(self), (gpointer*)&self);
 
+    g_clear_object(&self->priv->qmp);
+
     virt_viewer_session_spice_clear_displays(self);
 
     if (self->priv->session) {
@@ -1010,6 +1015,85 @@ port_name_to_vte_name(const char *name)
     return NULL;
 }
 
+static void
+virt_viewer_session_spice_vm_action(VirtViewerSession *sess, gint action)
+{
+    VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(sess);
+
+    switch (action) {
+    case VIRT_VIEWER_SESSION_VM_ACTION_QUIT:
+        action = SPICE_QMP_PORT_VM_ACTION_QUIT;
+        break;
+    case VIRT_VIEWER_SESSION_VM_ACTION_RESET:
+        action = SPICE_QMP_PORT_VM_ACTION_RESET;
+        break;
+    case VIRT_VIEWER_SESSION_VM_ACTION_POWER_DOWN:
+        action = SPICE_QMP_PORT_VM_ACTION_POWER_DOWN;
+        break;
+    case VIRT_VIEWER_SESSION_VM_ACTION_PAUSE:
+        action = SPICE_QMP_PORT_VM_ACTION_PAUSE;
+        break;
+    case VIRT_VIEWER_SESSION_VM_ACTION_CONTINUE:
+        action = SPICE_QMP_PORT_VM_ACTION_CONTINUE;
+        break;
+    default:
+        g_return_if_reached();
+    }
+
+    spice_qmp_port_vm_action_async(self->priv->qmp, action, NULL, NULL, NULL);
+}
+
+static void
+set_vm_running(VirtViewerSessionSpice *self, gboolean running)
+{
+    g_object_set(virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)),
+                 "vm-running", running, NULL);
+}
+
+static void
+query_status_cb(GObject *source_object G_GNUC_UNUSED,
+                GAsyncResult *res, gpointer user_data)
+{
+    VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(user_data);
+    SpiceQmpStatus *status;
+    gboolean running = TRUE;
+    GError *error = NULL;
+
+    status = spice_qmp_port_query_status_finish(self->priv->qmp, res, &error);
+    if (!status) {
+        g_warning("failed to query VM status: %s", error->message);
+        g_error_free(error);
+        return;
+    }
+
+    if (g_str_equal(status->status, "paused")) {
+        running = FALSE;
+    }
+
+    set_vm_running(self, running);
+
+    spice_qmp_status_unref(status);
+}
+
+static void qmp_ready_cb(VirtViewerSessionSpice *self,
+                         GParamSpec *pspec G_GNUC_UNUSED,
+                         GObject *object G_GNUC_UNUSED)
+{
+    spice_qmp_port_query_status_async(self->priv->qmp, NULL, query_status_cb, self);
+}
+
+static void qmp_event_cb(VirtViewerSessionSpice *self, const gchar *event,
+                         void *data G_GNUC_UNUSED, GObject *object G_GNUC_UNUSED)
+{
+    g_debug("QMP event %s", event);
+
+    if (g_str_equal(event, "STOP")) {
+        set_vm_running(self, FALSE);
+    } else if (g_str_equal(event, "RESUME")) {
+        set_vm_running(self, TRUE);
+    }
+}
+
 static void
 spice_port_opened(SpiceChannel *channel, GParamSpec *pspec G_GNUC_UNUSED,
                   VirtViewerSessionSpice *self)
@@ -1030,8 +1114,27 @@ spice_port_opened(SpiceChannel *channel, GParamSpec *pspec G_GNUC_UNUSED,
     g_return_if_fail(name != NULL);
     g_debug("port#%d %s: %s", id, name, opened ? "opened" : "closed");
     vte_name = port_name_to_vte_name(name);
-    g_free(name);
 
+    if (g_str_equal(name, "org.qemu.monitor.qmp.0")) {
+        if (opened) {
+            g_return_if_fail(!self->priv->qmp);
+
+            g_object_set(virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self)),
+                         "vm-ui", TRUE, NULL);
+
+            self->priv->qmp = spice_qmp_port_get(port);
+            virt_viewer_signal_connect_object(self->priv->qmp, "notify::ready",
+                                              G_CALLBACK(qmp_ready_cb), self, G_CONNECT_SWAPPED);
+            virt_viewer_signal_connect_object(self->priv->qmp, "event",
+                                              G_CALLBACK(qmp_event_cb), self, G_CONNECT_SWAPPED);
+        } else {
+            g_clear_object(&self->priv->qmp);
+        }
+        g_free(name);
+        return;
+    }
+
+    g_free(name);
     vte = g_object_get_data(G_OBJECT(port), "virt-viewer-vte");
     if (vte) {
         if (opened)
-- 
2.20.1.98.gecbdaf0899




More information about the virt-tools-list mailing list