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 | 18 ++++ src/Makefile.am | 8 ++ src/remote-viewer.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++- virt-viewer.spec.in | 11 ++- 4 files changed, 262 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 30c2042..bbd9114 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) @@ -241,3 +257,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([ OVIRT: $OVIRT_CFLAGS $OVIRT_LIBS]) +AC_MSG_NOTICE([]) diff --git a/src/Makefile.am b/src/Makefile.am index 05e20b2..f929aa5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -96,6 +96,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 +132,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 fa17edd..f2a5648 100644 --- a/src/remote-viewer.c +++ b/src/remote-viewer.c @@ -26,6 +26,11 @@ #include <gtk/gtk.h> #include <glib/gprintf.h> #include <glib/gi18n.h> +#include <libxml/uri.h> + +#ifdef HAVE_OVIRT +#include <govirt/govirt.h> +#endif #ifdef HAVE_SPICE_GTK #include <spice-controller.h> @@ -35,6 +40,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 +591,213 @@ remote_viewer_window_added(VirtViewerApp *app G_GNUC_UNUSED, } #endif +#ifdef HAVE_OVIRT +static gboolean +parse_ovirt_uri(const gchar *uri_str, char **rest_uri, char **name) +{ + char *vm_name = NULL; + char *rel_path; + xmlURIPtr uri; + gchar **path_elements; + guint element_count; + + g_return_val_if_fail(uri_str != NULL, FALSE); + g_return_val_if_fail(rest_uri != NULL, FALSE); + g_return_val_if_fail(name != NULL, FALSE); + + uri = xmlParseURI(uri_str); + if (uri == NULL) + return FALSE; + + if (g_strcmp0(uri->scheme, "ovirt") != 0) { + xmlFreeURI(uri); + return FALSE; + } + + if (uri->path == NULL) { + xmlFreeURI(uri); + return FALSE; + } + + /* extract VM name from path */ + path_elements = g_strsplit(uri->path, "/", -1); + + element_count = g_strv_length(path_elements); + if (element_count == 0) { + g_strfreev(path_elements); + xmlFreeURI(uri); + return FALSE; + } + vm_name = path_elements[element_count-1]; + path_elements[element_count-1] = NULL; + + /* build final URI */ + rel_path = g_strjoinv("/", path_elements); + /* FIXME: how to decide between http and https? */ + *rest_uri = g_strdup_printf("https://%s/%s/api/", uri->server, rel_path); + *name = vm_name; + g_free(rel_path); + g_strfreev(path_elements); + xmlFreeURI(uri); + + g_debug("oVirt base URI: %s", *rest_uri); + g_debug("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_ovirt_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) { + session_type = "spice"; + } else if (type == OVIRT_VM_DISPLAY_VNC) { + session_type = "vnc"; + } 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 +859,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); diff --git a/virt-viewer.spec.in b/virt-viewer.spec.in index ee91b5f..122d768 100644 --- a/virt-viewer.spec.in +++ b/virt-viewer.spec.in @@ -19,6 +19,8 @@ %define with_spice 1 %endif +%define with_govirt 0 + %if 0%{?rhel} >= 6 %define with_spice 1 %endif @@ -80,6 +82,9 @@ BuildRequires: xulrunner-devel BuildRequires: firefox-devel %endif %endif +%if %{with_govirt} +BuildRequires: libgovirt-devel >= 0.0.3 +%endif %description Virtual Machine Viewer provides a graphical console client for connecting @@ -128,7 +133,11 @@ autoreconf -if %define gtk_arg --with-gtk=2.0 %endif -%configure %{spice_arg} %{plugin_arg} %{gtk_arg} +%if %{with_govirt} +%define govirt_arg --with-ovirt +%endif + +%configure %{spice_arg} %{plugin_arg} %{gtk_arg} %{govirt_arg} %__make %{?_smp_mflags} -- 1.8.1.2 _______________________________________________ virt-tools-list mailing list virt-tools-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/virt-tools-list