[virt-tools-list] [virt-viewer] Add oVirt support

Christophe Fergeau cfergeau at redhat.com
Thu Jan 24 15:57:10 UTC 2013


This commit adds support for ovirt:// URIs. It does so by using
libgovirt to get the spice/vnc connection information through
oVirt xmlrpc API.
---
 configure.ac        |  20 ++++-
 src/Makefile.am     |  13 +++
 src/remote-viewer.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 261 insertions(+), 5 deletions(-)

diff --git a/configure.ac b/configure.ac
index 251b134..d832769 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,7 +19,7 @@ GTK2_REQUIRED="2.18.0"
 GTK3_REQUIRED="3.0"
 GTK_VNC1_REQUIRED="0.3.8"
 GTK_VNC2_REQUIRED="0.4.0"
-SPICE_GTK_REQUIRED="0.12.101"
+SPICE_GTK_REQUIRED="0.15"
 SPICE_PROTOCOL_REQUIRED="0.10.1"
 
 AC_MSG_CHECKING([for native Win32])
@@ -165,6 +165,22 @@ AS_IF([test "x$have_spice_gtk" = "xyes"],
 ])
 AM_CONDITIONAL([HAVE_SPICE_GTK], [test "x$have_spice_gtk" = "xyes"])
 
+AC_ARG_WITH([ovirt],
+    AS_HELP_STRING([--without-ovirt], [Ignore presence of librest and disable oVirt support]))
+
+AS_IF([test "x$with_ovirt" != "xno"],
+      [PKG_CHECK_MODULES([OVIRT], [govirt-1.0],
+                         [have_ovirt=yes], [have_ovirt=no])],
+      [have_ovirt=no])
+
+AS_IF([test "x$have_ovirt" = "xyes"],
+      [AC_DEFINE([HAVE_OVIRT], 1, [Have libgovirt?])],
+      [AS_IF([test "x$with_ovirt" = "xyes"],
+             [AC_MSG_ERROR([oVirt support requested but libgovirt not found])
+      ])
+])
+AM_CONDITIONAL([HAVE_OVIRT], [test "x$have_ovirt" = "xyes"])
+
 dnl Decide if this platform can support the SSH tunnel feature.
 AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h])
 AC_CHECK_FUNCS([fork socketpair])
@@ -240,3 +256,5 @@ AC_MSG_NOTICE([     LIBXML2: $LIBXML2_CFLAGS $LIBXML2_LIBS])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([     LIBVIRT: $LIBVIRT_CFLAGS $LIBVIRT_LIBS])
 AC_MSG_NOTICE([])
+AC_MSG_NOTICE([     LIBREST: $OVIRT_CFLAGS $OVIRT_LIBS])
+AC_MSG_NOTICE([])
diff --git a/src/Makefile.am b/src/Makefile.am
index 05e20b2..7bb03cb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -59,6 +59,11 @@ COMMON_SOURCES +=						\
 	$(NULL)
 endif
 
+if HAVE_OVIRT
+COMMON_SOURCES +=						\
+	$(NULL)
+endif
+
 if HAVE_SPICE_GTK
 COMMON_SOURCES +=						\
 	virt-viewer-session-spice.h virt-viewer-session-spice.c	\
@@ -96,6 +101,10 @@ if HAVE_GTK_VNC
 virt_viewer_LDFLAGS += $(GTK_VNC_LIBS)
 virt_viewer_CFLAGS += $(GTK_VNC_CFLAGS)
 endif
+if HAVE_OVIRT
+virt_viewer_LDFLAGS += $(OVIRT_LIBS)
+virt_viewer_CFLAGS += $(OVIRT_CFLAGS)
+endif
 if HAVE_SPICE_GTK
 virt_viewer_LDFLAGS += $(SPICE_GTK_LIBS)
 virt_viewer_CFLAGS += $(SPICE_GTK_CFLAGS)
@@ -128,6 +137,10 @@ if HAVE_GTK_VNC
 remote_viewer_LDFLAGS += $(GTK_VNC_LIBS)
 remote_viewer_CFLAGS += $(GTK_VNC_CFLAGS)
 endif
+if HAVE_OVIRT
+remote_viewer_LDFLAGS += $(OVIRT_LIBS)
+remote_viewer_CFLAGS += $(OVIRT_CFLAGS)
+endif
 if HAVE_SPICE_GTK
 remote_viewer_LDFLAGS += $(SPICE_GTK_LIBS) $(SPICE_CONTROLLER_LIBS)
 remote_viewer_CFLAGS += $(SPICE_GTK_CFLAGS) $(SPICE_CONTROLLER_CFLAGS)
diff --git a/src/remote-viewer.c b/src/remote-viewer.c
index 0cf9f1f..04930f7 100644
--- a/src/remote-viewer.c
+++ b/src/remote-viewer.c
@@ -27,6 +27,10 @@
 #include <glib/gprintf.h>
 #include <glib/gi18n.h>
 
+#ifdef HAVE_OVIRT
+#include <govirt/govirt.h>
+#endif
+
 #ifdef HAVE_SPICE_GTK
 #include <spice-controller.h>
 #endif
@@ -35,6 +39,7 @@
 #include "virt-viewer-session-spice.h"
 #endif
 #include "virt-viewer-app.h"
+#include "virt-viewer-auth.h"
 #include "virt-viewer-file.h"
 #include "virt-viewer-session.h"
 #include "remote-viewer.h"
@@ -585,6 +590,217 @@ remote_viewer_window_added(VirtViewerApp *app G_GNUC_UNUSED,
 }
 #endif
 
+#ifdef HAVE_OVIRT
+static gboolean
+parse_uri(const gchar *uri, char **rest_uri, char **name)
+{
+    char *pos;
+    char *vm_name;
+    char *tmp_uri;
+
+    g_return_val_if_fail(uri != NULL, FALSE);
+    g_return_val_if_fail(rest_uri != NULL, FALSE);
+    g_return_val_if_fail(name != NULL, FALSE);
+
+    /* extract VM name from URI */
+    pos = strrchr(uri, '/');
+    if (pos == NULL)
+        return FALSE;
+
+    pos++;
+    if (*pos == '\0')
+        return FALSE;
+    vm_name = pos;
+
+    /* remove vm_name and trailing / from uri */
+    pos = pos - 1;
+    g_assert(*pos == '/');
+
+    while ((pos != uri) && (*pos == '/'))
+        pos--;
+    if (pos == uri)
+        return FALSE;
+    if (pos - uri + 1 < strlen("ovirt://")) {
+        /* we trimmed too much */
+        return FALSE;
+    }
+
+    tmp_uri = g_strndup(uri, pos - uri + 1);
+    g_assert(g_str_has_prefix(tmp_uri, "ovirt://"));
+    /* FIXME: how to decide between http and https? */
+    *rest_uri = g_strdup_printf("https://%s/api/",
+                                tmp_uri + strlen("ovirt://"));
+    *name = g_strdup(vm_name);
+    g_free(tmp_uri);
+
+    g_message("oVirt base URI: %s", *rest_uri);
+    g_message("oVirt VM name: %s", *name);
+
+    return TRUE;
+}
+
+static gboolean
+authenticate_cb(RestProxy *proxy, G_GNUC_UNUSED RestProxyAuth *auth,
+                G_GNUC_UNUSED gboolean retrying, gpointer user_data)
+{
+    gchar *username;
+    gchar *password;
+    VirtViewerWindow *window;
+
+    window = virt_viewer_app_get_main_window(VIRT_VIEWER_APP(user_data));
+    int ret = virt_viewer_auth_collect_credentials(virt_viewer_window_get_window(window),
+                                                   "oVirt",
+                                                   NULL,
+                                                   &username, &password);
+    if (ret < 0) {
+        return FALSE;
+    } else {
+        g_object_set(G_OBJECT(proxy),
+                     "username", username,
+                     "password", password,
+                     NULL);
+        g_free(username);
+        g_free(password);
+        return TRUE;
+    }
+}
+
+
+static gboolean
+create_ovirt_session(VirtViewerApp *app, const char *uri)
+{
+    OvirtProxy *proxy = NULL;
+    OvirtVm *vm = NULL;
+    OvirtVmDisplay *display = NULL;
+    OvirtVmState state;
+    GError *error = NULL;
+    char *rest_uri = NULL;
+    char *vm_name = NULL;
+    gboolean success = FALSE;
+    guint port;
+    guint secure_port;
+    OvirtVmDisplayType type;
+    const char *session_type;
+
+    gchar *gport = NULL;
+    gchar *gtlsport = NULL;
+    gchar *ghost = NULL;
+    gchar *ticket = NULL;
+
+    g_return_val_if_fail(VIRT_VIEWER_IS_APP(app), FALSE);
+
+    if (!parse_uri(uri, &rest_uri, &vm_name))
+        goto error;
+    proxy = ovirt_proxy_new (rest_uri);
+    if (proxy == NULL)
+        goto error;
+    g_signal_connect(G_OBJECT(proxy), "authenticate",
+                     G_CALLBACK(authenticate_cb), app);
+
+    ovirt_proxy_fetch_ca_certificate(proxy, &error);
+    if (error != NULL) {
+        g_debug("failed to get CA certificate: %s", error->message);
+        goto error;
+    }
+
+    ovirt_proxy_fetch_vms(proxy, &error);
+    if (error != NULL) {
+        g_debug("failed to lookup %s: %s", vm_name, error->message);
+        goto error;
+    }
+
+    vm = ovirt_proxy_lookup_vm(proxy, vm_name);
+    g_return_val_if_fail(vm != NULL, FALSE);
+    g_object_get(G_OBJECT(vm), "state", &state, NULL);
+    if (state != OVIRT_VM_STATE_UP) {
+        g_debug("oVirt VM %s is not running", vm_name);
+        goto error;
+    }
+
+    if (!ovirt_vm_get_ticket(vm, proxy, &error)) {
+        g_debug("failed to get ticket for %s: %s", vm_name, error->message);
+        goto error;
+    }
+
+    g_object_get(G_OBJECT(vm), "display", &display, NULL);
+    if (display == NULL) {
+        goto error;
+    }
+
+    g_object_get(G_OBJECT(display),
+                 "type", &type,
+                 "address", &ghost,
+                 "port", &port,
+                 "secure-port", &secure_port,
+                 "ticket", &ticket,
+                 NULL);
+    gport = g_strdup_printf("%d", port);
+    gtlsport = g_strdup_printf("%d", secure_port);
+
+    if (type == OVIRT_VM_DISPLAY_SPICE) {
+#if HAVE_SPICE_GTK
+        session_type = "spice";
+#else
+        g_debug("This binary was compiled without SPICE support");
+        goto error;
+#endif
+    } else if (type == OVIRT_VM_DISPLAY_VNC) {
+#if HAVE_GTK_VNC
+        session_type = "vnc";
+#else
+        g_debug("This binary was compiled without VNC support");
+        goto error;
+#endif
+    } else {
+        g_debug("Unknown display type: %d", type);
+        goto error;
+    }
+
+    virt_viewer_app_set_connect_info(app, NULL, ghost, gport, gtlsport,
+                                     session_type, NULL, NULL, 0, NULL);
+
+    if (virt_viewer_app_create_session(app, session_type) < 0)
+        goto error;
+
+#if HAVE_SPICE_GTK
+    if (type == OVIRT_VM_DISPLAY_SPICE) {
+        SpiceSession *session;
+        GByteArray *ca_cert;
+
+        g_object_get(G_OBJECT(proxy), "ca-cert", &ca_cert, NULL);
+        session = remote_viewer_get_spice_session(REMOTE_VIEWER(app));
+        g_object_set(G_OBJECT(session),
+                     "ca", ca_cert,
+                     "password", ticket,
+                     NULL);
+        g_byte_array_unref(ca_cert);
+    }
+#endif
+
+    success = TRUE;
+
+error:
+    g_free(rest_uri);
+    g_free(vm_name);
+    g_free(ticket);
+    g_free(gport);
+    g_free(gtlsport);
+    g_free(ghost);
+
+    if (error != NULL)
+        g_error_free(error);
+    if (display != NULL)
+        g_object_unref(display);
+    if (vm != NULL)
+        g_object_unref(vm);
+    if (proxy != NULL)
+        g_object_unref(proxy);
+
+    return success;
+}
+
+#endif
+
 static gboolean
 remote_viewer_start(VirtViewerApp *app)
 {
@@ -646,10 +862,19 @@ remote_viewer_start(VirtViewerApp *app)
             virt_viewer_app_simple_message_dialog(app, _("Cannot determine the connection type from URI"));
             goto cleanup;
         }
-
-        if (virt_viewer_app_create_session(app, type) < 0) {
-            virt_viewer_app_simple_message_dialog(app, _("Couldn't create a session for this type: %s"), type);
-            goto cleanup;
+#if HAVE_OVIRT
+        if (g_strcmp0(type, "ovirt") == 0) {
+            if (!create_ovirt_session(app, guri)) {
+                virt_viewer_app_simple_message_dialog(app, _("Couldn't open oVirt session"));
+                goto cleanup;
+            }
+        } else
+#endif
+        {
+            if (virt_viewer_app_create_session(app, type) < 0) {
+                virt_viewer_app_simple_message_dialog(app, _("Couldn't create a session for this type: %s"), type);
+                goto cleanup;
+            }
         }
 
         virt_viewer_session_set_file(virt_viewer_app_get_session(app), vvfile);
-- 
1.8.1




More information about the virt-tools-list mailing list