diff --git a/SOURCES/0003-Spice-listen-for-new-SpiceSession-disconnected-signa.patch b/SOURCES/0003-Spice-listen-for-new-SpiceSession-disconnected-signa.patch new file mode 100644 index 0000000..25cb699 --- /dev/null +++ b/SOURCES/0003-Spice-listen-for-new-SpiceSession-disconnected-signa.patch @@ -0,0 +1,94 @@ +From c4378d5bcf534756cd1372fa0fb9c08e2380be50 Mon Sep 17 00:00:00 2001 +From: Jonathon Jongsma +Date: Thu, 31 May 2018 13:30:33 -0500 +Subject: [PATCH 3/4] Spice: listen for new 'SpiceSession::disconnected' signal + +Previously we were emitting the VirtViewerSession::session-disconnected +when we got the Spice::session::channel-destroy signal for the last +channel. However, since the channels are still valid at this point, and +because VirtViewerApp quits the application in response to the +session-disconnected signal, that means that the channels were never +being properly freed. This was particularly problematic for the usbredir +channel, which must disconnect any connected USB devices as part of its +destruction. By using the new SpiceSession::disconnected signal instead, +we can ensure that all channels have been disconnected and properly +destroyed before quitting the application. + +(cherry picked from commit 65ef66e42a6db2a9826fffef0db49920a02d358f) +--- + src/virt-viewer-session-spice.c | 24 +++++++++++++++++++----- + 1 file changed, 19 insertions(+), 5 deletions(-) + +diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c +index fdc7004..cb06af2 100644 +--- a/src/virt-viewer-session-spice.c ++++ b/src/virt-viewer-session-spice.c +@@ -50,7 +50,7 @@ struct _VirtViewerSessionSpicePrivate { + guint pass_try; + gboolean did_auto_conf; + VirtViewerFileTransferDialog *file_transfer_dialog; +- ++ GError *disconnect_error; + }; + + #define VIRT_VIEWER_SESSION_SPICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_SESSION_SPICE, VirtViewerSessionSpicePrivate)) +@@ -75,6 +75,8 @@ static void virt_viewer_session_spice_channel_new(SpiceSession *s, + static void virt_viewer_session_spice_channel_destroy(SpiceSession *s, + SpiceChannel *channel, + VirtViewerSession *session); ++static void virt_viewer_session_spice_session_disconnected(SpiceSession *s, ++ VirtViewerSessionSpice *session); + static void virt_viewer_session_spice_smartcard_insert(VirtViewerSession *session); + static void virt_viewer_session_spice_smartcard_remove(VirtViewerSession *session); + static gboolean virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self); +@@ -152,6 +154,7 @@ virt_viewer_session_spice_dispose(GObject *obj) + gtk_widget_destroy(GTK_WIDGET(spice->priv->file_transfer_dialog)); + spice->priv->file_transfer_dialog = NULL; + } ++ g_clear_error(&spice->priv->disconnect_error); + + G_OBJECT_CLASS(virt_viewer_session_spice_parent_class)->dispose(obj); + } +@@ -398,6 +401,8 @@ create_spice_session(VirtViewerSessionSpice *self) + G_CALLBACK(virt_viewer_session_spice_channel_new), self, 0); + virt_viewer_signal_connect_object(self->priv->session, "channel-destroy", + G_CALLBACK(virt_viewer_session_spice_channel_destroy), self, 0); ++ virt_viewer_signal_connect_object(self->priv->session, "disconnected", ++ G_CALLBACK(virt_viewer_session_spice_session_disconnected), self, 0); + + usb_manager = spice_usb_device_manager_get(self->priv->session, NULL); + if (usb_manager) { +@@ -1091,6 +1096,13 @@ virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self) + return TRUE; + } + ++static void ++virt_viewer_session_spice_session_disconnected(G_GNUC_UNUSED SpiceSession *s, ++ VirtViewerSessionSpice *self) ++{ ++ g_signal_emit_by_name(self, "session-disconnected", self->priv->disconnect_error); ++} ++ + static void + virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s, + SpiceChannel *channel, +@@ -1129,10 +1141,12 @@ virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s, + if (self->priv->usbredir_channel_count == 0) + virt_viewer_session_set_has_usbredir(session, FALSE); + } +- +- self->priv->channel_count--; +- if (self->priv->channel_count == 0) +- g_signal_emit_by_name(self, "session-disconnected", error ? error->message : NULL); ++ if (error) { ++ g_warning("Channel error: %s", error->message); ++ if (self->priv->disconnect_error == NULL) { ++ self->priv->disconnect_error = g_error_copy(error); ++ } ++ } + } + + VirtViewerSession * +-- +2.21.0 + diff --git a/SOURCES/0004-Fix-a-regression-when-initial-connection-fails.patch b/SOURCES/0004-Fix-a-regression-when-initial-connection-fails.patch new file mode 100644 index 0000000..f0a7449 --- /dev/null +++ b/SOURCES/0004-Fix-a-regression-when-initial-connection-fails.patch @@ -0,0 +1,108 @@ +From a12916d1e4811be08f8ed18d8e9abdc8416db61f Mon Sep 17 00:00:00 2001 +From: Jonathon Jongsma +Date: Tue, 29 Jan 2019 14:47:51 -0600 +Subject: [PATCH 4/4] Fix a regression when initial connection fails + +Due to changes in commit 65ef66e4, when the initial connection fails, +virt-viewer just sat quietly and didn't indicate what was wrong. It also +did not exit as it did before. This is because we were using +virt_viewer_session_spice_channel_destroy() incorrectly. This function +was intended to be a callback that is called to clean up the VV session +when the SpiceSession tells us that a channel has been destroyed. It +does not actually destroy the channel, it only cleans up references to +that channel within virt-viewer. After calling this function, the +channel is not affected in any way. If the channel object was valid +before calling the function, it will be valid and unchanged after +calling the function as well. + +The problem is that before commit 65ef66e4, this function +(_channel_destroy()) also had a side-effect of emitting a signal that +made us think that the SpiceSession was disconnected when it was not. +The application responded to this signal by exiting even though the +session was not properly disconnected and cleaned up. + +We now no longer exit the application until the SpiceSession is properly +disconnected and cleaned up. So we need to make sure that this happens +when our initial connection fails. Therefore, when the main channel +receives an error channel-event, we should not call +virt_viewer_session_spice_channel_destroy(). This function should only +be called when a channel has actually been destroyed, and the channel is +not destroyed at this point. We should instead explicitly disconnect +the session, which will result in the channels being destroyed properly. +After the session destroys all of the channels, the 'channel-destroy' signal +will be emitted by SpiceSession, so the _channel_destroy() function will +eventually get called by the signal handler. + +To make the proper use of the function more obvious, I also changed the +function name from _channel_destroy() to _channel_destroyed() and added +a comment. + +Fixes: rhbz#1666869 +Signed-off-by: Jonathon Jongsma +Acked-by: Christophe Fergeau +(cherry picked from commit c2dabf0730e1601745d2cdfc28f59e65e17cdab1) +--- + src/virt-viewer-session-spice.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c +index cb06af2..4386ac0 100644 +--- a/src/virt-viewer-session-spice.c ++++ b/src/virt-viewer-session-spice.c +@@ -72,9 +72,9 @@ static void virt_viewer_session_spice_usb_device_selection(VirtViewerSession *se + static void virt_viewer_session_spice_channel_new(SpiceSession *s, + SpiceChannel *channel, + VirtViewerSession *session); +-static void virt_viewer_session_spice_channel_destroy(SpiceSession *s, +- SpiceChannel *channel, +- VirtViewerSession *session); ++static void virt_viewer_session_spice_channel_destroyed(SpiceSession *s, ++ SpiceChannel *channel, ++ VirtViewerSession *session); + static void virt_viewer_session_spice_session_disconnected(SpiceSession *s, + VirtViewerSessionSpice *session); + static void virt_viewer_session_spice_smartcard_insert(VirtViewerSession *session); +@@ -400,7 +400,7 @@ create_spice_session(VirtViewerSessionSpice *self) + virt_viewer_signal_connect_object(self->priv->session, "channel-new", + G_CALLBACK(virt_viewer_session_spice_channel_new), self, 0); + virt_viewer_signal_connect_object(self->priv->session, "channel-destroy", +- G_CALLBACK(virt_viewer_session_spice_channel_destroy), self, 0); ++ G_CALLBACK(virt_viewer_session_spice_channel_destroyed), self, 0); + virt_viewer_signal_connect_object(self->priv->session, "disconnected", + G_CALLBACK(virt_viewer_session_spice_session_disconnected), self, 0); + +@@ -769,14 +769,14 @@ virt_viewer_session_spice_main_channel_event(SpiceChannel *channel, + spice_session_connect(self->priv->session); + } + } else { +- virt_viewer_session_spice_channel_destroy(NULL, channel, session); ++ spice_session_disconnect(self->priv->session); + } + break; + } + case SPICE_CHANNEL_ERROR_IO: + case SPICE_CHANNEL_ERROR_LINK: + case SPICE_CHANNEL_ERROR_TLS: +- virt_viewer_session_spice_channel_destroy(NULL, channel, session); ++ spice_session_disconnect(self->priv->session); + break; + default: + g_warning("unhandled spice main channel event: %d", event); +@@ -1103,10 +1103,11 @@ virt_viewer_session_spice_session_disconnected(G_GNUC_UNUSED SpiceSession *s, + g_signal_emit_by_name(self, "session-disconnected", self->priv->disconnect_error); + } + ++/* called when the spice session indicates that a session has been destroyed */ + static void +-virt_viewer_session_spice_channel_destroy(G_GNUC_UNUSED SpiceSession *s, +- SpiceChannel *channel, +- VirtViewerSession *session) ++virt_viewer_session_spice_channel_destroyed(G_GNUC_UNUSED SpiceSession *s, ++ SpiceChannel *channel, ++ VirtViewerSession *session) + { + VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(session); + int id; +-- +2.21.0 + diff --git a/SOURCES/0005-configure-Fix-check-for-govirt-functions.patch b/SOURCES/0005-configure-Fix-check-for-govirt-functions.patch new file mode 100644 index 0000000..f368cd0 --- /dev/null +++ b/SOURCES/0005-configure-Fix-check-for-govirt-functions.patch @@ -0,0 +1,30 @@ +From 39a27ec97fa61c602154c500965ba8b83b2b570c Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 31 May 2019 12:10:20 -0300 +Subject: [PATCH virt-viewer] configure: Fix check for govirt functions + +Use saved CFLAGS and LIBS to avoid errors in the check programs. + +Signed-off-by: Eduardo Lima (Etrunko) +--- + configure.ac | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index e2d3e2b..a555b46 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -182,8 +182,8 @@ AS_IF([test "x$with_ovirt" = "xyes"], + [AC_DEFINE([HAVE_OVIRT], 1, [Have libgovirt?])] + [SAVED_CFLAGS="$CFLAGS" + SAVED_LIBS="$LIBS" +- CFLAGS="$OVIRT_CFLAGS" +- LIBS="$OVIRT_LIBS" ++ CFLAGS="$SAVED_CFLAGS $OVIRT_CFLAGS" ++ LIBS="$SAVED_LIBS $OVIRT_LIBS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [static int err = OVIRT_REST_CALL_ERROR_CANCELLED; + void *fun = rest_proxy_auth_cancel;])], +-- +2.21.0 + diff --git a/SOURCES/0006-ovirt-foreign-menu-New-function-storage_domain_valid.patch b/SOURCES/0006-ovirt-foreign-menu-New-function-storage_domain_valid.patch new file mode 100644 index 0000000..a6e6586 --- /dev/null +++ b/SOURCES/0006-ovirt-foreign-menu-New-function-storage_domain_valid.patch @@ -0,0 +1,85 @@ +From 6f3f17ab8e49fedded6df46d703dc0a5087a630c Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Wed, 4 Jul 2018 12:29:42 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: New function + storage_domain_validate() + +It may be useful to know why the storage domain has not been listed, +given that there are different reasons for that. To make it easier to +provide more detailed debug messages, we move code from the callback +function to this new one. + +Acked-by: Christophe Fergeau +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 45 ++++++++++++++++++++++++++-------------- + 1 file changed, 30 insertions(+), 15 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index cd1b8bd..b482401 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -640,6 +640,35 @@ static gboolean storage_domain_attached_to_data_center(OvirtStorageDomain *domai + } + #endif + ++static gboolean storage_domain_validate(OvirtForeignMenu *menu G_GNUC_UNUSED, ++ OvirtStorageDomain *domain) ++{ ++ char *name; ++ int type, state; ++ gboolean ret = TRUE; ++ ++ g_object_get(domain, "name", &name, "type", &type, "state", &state, NULL); ++ ++ if (type != OVIRT_STORAGE_DOMAIN_TYPE_ISO) { ++ g_debug("Storage domain '%s' type is not ISO", name); ++ ret = FALSE; ++ } ++ ++ if (state != OVIRT_STORAGE_DOMAIN_STATE_ACTIVE) { ++ g_debug("Storage domain '%s' state is not active", name); ++ ret = FALSE; ++ } ++ ++#ifdef HAVE_OVIRT_DATA_CENTER ++ if (!storage_domain_attached_to_data_center(domain, menu->priv->data_center)) { ++ g_debug("Storage domain '%s' is not attached to data center", name); ++ ret = FALSE; ++ } ++#endif ++ ++ g_free(name); ++ return ret; ++} + + static void storage_domains_fetched_cb(GObject *source_object, + GAsyncResult *result, +@@ -663,23 +692,9 @@ static void storage_domains_fetched_cb(GObject *source_object, + g_hash_table_iter_init(&iter, ovirt_collection_get_resources(collection)); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&domain)) { + OvirtCollection *file_collection; +- int type; +- int state; +- +- g_object_get(domain, "type", &type, "state", &state, NULL); +- if (type != OVIRT_STORAGE_DOMAIN_TYPE_ISO) { +- continue; +- } +- +- if (state != OVIRT_STORAGE_DOMAIN_STATE_ACTIVE) { +- continue; +- } + +-#ifdef HAVE_OVIRT_DATA_CENTER +- if (!storage_domain_attached_to_data_center(domain, menu->priv->data_center)) { ++ if (!storage_domain_validate(menu, domain)) + continue; +- } +-#endif + + file_collection = ovirt_storage_domain_get_files(domain); + if (file_collection != NULL) { +-- +2.21.0 + diff --git a/SOURCES/0007-ovirt-foreign-menu-Fix-endpoint-for-storage-domains-.patch b/SOURCES/0007-ovirt-foreign-menu-Fix-endpoint-for-storage-domains-.patch new file mode 100644 index 0000000..682627c --- /dev/null +++ b/SOURCES/0007-ovirt-foreign-menu-Fix-endpoint-for-storage-domains-.patch @@ -0,0 +1,80 @@ +From 1486be8472a30a2a7766465a03b8f9b3631a52f5 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 9 Aug 2019 16:26:13 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Fix endpoint for storage + domains query + +Instead of fetching toplevel REST API query, we use the one relative +from the data center, which returns more detailed information, +especially the status of the storage domain. + +This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1427467 + +Signed-off-by: Eduardo Lima (Etrunko) +Acked-by: Victor Toso +--- + src/ovirt-foreign-menu.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index b482401..cbb0e88 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -680,6 +680,7 @@ static void storage_domains_fetched_cb(GObject *source_object, + OvirtCollection *collection = OVIRT_COLLECTION(source_object); + GHashTableIter iter; + OvirtStorageDomain *domain; ++ gboolean domain_valid = FALSE; + + ovirt_collection_fetch_finish(collection, result, &error); + if (error != NULL) { +@@ -693,7 +694,8 @@ static void storage_domains_fetched_cb(GObject *source_object, + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&domain)) { + OvirtCollection *file_collection; + +- if (!storage_domain_validate(menu, domain)) ++ domain_valid = storage_domain_validate(menu, domain); ++ if (!domain_valid) + continue; + + file_collection = ovirt_storage_domain_get_files(domain); +@@ -710,9 +712,11 @@ static void storage_domains_fetched_cb(GObject *source_object, + if (menu->priv->files != NULL) { + ovirt_foreign_menu_next_async_step(menu, task, STATE_STORAGE_DOMAIN); + } else { +- g_debug("Could not find iso file collection"); +- g_task_return_new_error(task, OVIRT_ERROR, OVIRT_ERROR_FAILED, +- "Could not find ISO file collection"); ++ const char *msg = domain_valid ? "Could not find ISO file collection" ++ : "Could not find valid ISO storage domain"; ++ ++ g_debug(msg); ++ g_task_return_new_error(task, OVIRT_ERROR, OVIRT_ERROR_FAILED, msg); + g_object_unref(task); + } + } +@@ -721,9 +725,19 @@ static void storage_domains_fetched_cb(GObject *source_object, + static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu, + GTask *task) + { +- OvirtCollection *collection = ovirt_api_get_storage_domains(menu->priv->api); ++ OvirtCollection *collection = NULL; ++ ++#ifdef HAVE_OVIRT_DATA_CENTER ++ g_return_if_fail(OVIRT_IS_FOREIGN_MENU(menu)); ++ g_return_if_fail(OVIRT_IS_PROXY(menu->priv->proxy)); ++ g_return_if_fail(OVIRT_IS_DATA_CENTER(menu->priv->data_center)); ++ ++ collection = ovirt_data_center_get_storage_domains(menu->priv->data_center); ++#else ++ collection = ovirt_api_get_storage_domains(menu->priv->api); ++#endif + +- g_debug("Start fetching oVirt REST collection"); ++ g_debug("Start fetching iso file collection"); + ovirt_collection_fetch_async(collection, menu->priv->proxy, + g_task_get_cancellable(task), + storage_domains_fetched_cb, task); +-- +2.21.0 + diff --git a/SOURCES/0008-ovirt-foreign-menu-Fix-warnings-on-Rawhide.patch b/SOURCES/0008-ovirt-foreign-menu-Fix-warnings-on-Rawhide.patch new file mode 100644 index 0000000..71818b5 --- /dev/null +++ b/SOURCES/0008-ovirt-foreign-menu-Fix-warnings-on-Rawhide.patch @@ -0,0 +1,48 @@ +From bb3859b9e76b31a71c74c88791abc5ccb1776a01 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 15 Aug 2019 17:03:37 +0200 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Fix warnings on Rawhide +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +gmaovirt-foreign-menu.c: In function 'storage_domains_fetched_cb': +ovirt-foreign-menu.c:721:9: error: format not a string literal and no format arguments [-Werror=format-security] + 721 | g_debug(msg); + | ^~~~~~~ +ovirt-foreign-menu.c:722:9: error: format not a string literal and no format arguments [-Werror=format-security] + 722 | g_task_return_new_error(task, OVIRT_ERROR, OVIRT_ERROR_FAILED, msg); + | ^~~~~~~~~~~~~~~~~~~~~~~ +cc1: some warnings being treated as errors +gmake[3]: *** [Makefile:963: libvirt_viewer_la-ovirt-foreign-menu.lo] Error 1 +gmake[2]: *** [Makefile:647: all] Error 2 +gmake[1]: *** [Makefile:482: all-recursive] Error 1 +make: *** [Makefile:410: all] Error 2 +error: Bad exit status from /var/tmp/rpm-tmp.f14Lmj (%build) + +Errors have been caught by https://ci.centos.org/job/virt-viewer-rpm/systems=libvirt-fedora-rawhide/589/ + +Signed-off-by: Fabiano FidĂȘncio +Acked-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index cbb0e88..cdf9879 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -715,8 +715,8 @@ static void storage_domains_fetched_cb(GObject *source_object, + const char *msg = domain_valid ? "Could not find ISO file collection" + : "Could not find valid ISO storage domain"; + +- g_debug(msg); +- g_task_return_new_error(task, OVIRT_ERROR, OVIRT_ERROR_FAILED, msg); ++ g_debug("%s", msg); ++ g_task_return_new_error(task, OVIRT_ERROR, OVIRT_ERROR_FAILED, "%s", msg); + g_object_unref(task); + } + } +-- +2.21.0 + diff --git a/SOURCES/0009-ovirt-foreign-menu-Only-set-domain_valid-once.patch b/SOURCES/0009-ovirt-foreign-menu-Only-set-domain_valid-once.patch new file mode 100644 index 0000000..3540342 --- /dev/null +++ b/SOURCES/0009-ovirt-foreign-menu-Only-set-domain_valid-once.patch @@ -0,0 +1,44 @@ +From 1733830d33c071d0c35d307426384f01d0f42f1d Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 16 Aug 2019 14:40:23 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Only set domain_valid once + +In the case of having a valid storage domain without any ISO files, this +variable can be reset to FALSE again in the next iteration of the loop, +resulting in a misleading error message presented to the user. + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index cdf9879..648ce55 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -666,6 +666,7 @@ static gboolean storage_domain_validate(OvirtForeignMenu *menu G_GNUC_UNUSED, + } + #endif + ++ g_debug ("Storage domain '%s' is %s", name, ret ? "valid" : "not valid"); + g_free(name); + return ret; + } +@@ -694,10 +695,12 @@ static void storage_domains_fetched_cb(GObject *source_object, + while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&domain)) { + OvirtCollection *file_collection; + +- domain_valid = storage_domain_validate(menu, domain); +- if (!domain_valid) ++ if (!storage_domain_validate(menu, domain)) + continue; + ++ if (!domain_valid) ++ domain_valid = TRUE; ++ + file_collection = ovirt_storage_domain_get_files(domain); + if (file_collection != NULL) { + if (menu->priv->files) { +-- +2.21.0 + diff --git a/SOURCES/0010-ovirt-foreign-menu-Bypass-errors-from-Host-Cluster-D.patch b/SOURCES/0010-ovirt-foreign-menu-Bypass-errors-from-Host-Cluster-D.patch new file mode 100644 index 0000000..63e9fe8 --- /dev/null +++ b/SOURCES/0010-ovirt-foreign-menu-Bypass-errors-from-Host-Cluster-D.patch @@ -0,0 +1,146 @@ +From f36ca9f983c2d3400dff3736dd76df4c1938fea0 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 6 Jul 2018 09:12:18 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Bypass errors from + Host/Cluster/Data Center + +When accessing ovirt as a regular user, it may happen that queries to +Hosts, Clusters and Data Centers return errors due to insufficient +permissions, while they will work fine if access is done by admin user. +In this case, we skip the errors and fallback to the old method. + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 60 ++++++++++++++++++++++++++++++---------- + 1 file changed, 46 insertions(+), 14 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index 648ce55..a729934 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -624,12 +624,21 @@ static void ovirt_foreign_menu_fetch_vm_cdrom_async(OvirtForeignMenu *menu, + + #ifdef HAVE_OVIRT_DATA_CENTER + static gboolean storage_domain_attached_to_data_center(OvirtStorageDomain *domain, +- OvirtDataCenter *data_center) ++ OvirtDataCenter *data_center) + { + GStrv data_center_ids; + char *data_center_guid; + gboolean match; + ++ /* For some reason we did not get data center information, so just return ++ * TRUE as it will work like a fallback to old method, where we did not ++ * check relationship between data center and storage domain. ++ */ ++ if (data_center == NULL) { ++ g_debug("Could not get data center info, considering storage domain is attached to it"); ++ return TRUE; ++ } ++ + g_object_get(domain, "data-center-ids", &data_center_ids, NULL); + g_object_get(data_center, "guid", &data_center_guid, NULL); + match = g_strv_contains((const gchar * const *) data_center_ids, data_center_guid); +@@ -733,9 +742,11 @@ static void ovirt_foreign_menu_fetch_storage_domain_async(OvirtForeignMenu *menu + #ifdef HAVE_OVIRT_DATA_CENTER + g_return_if_fail(OVIRT_IS_FOREIGN_MENU(menu)); + g_return_if_fail(OVIRT_IS_PROXY(menu->priv->proxy)); +- g_return_if_fail(OVIRT_IS_DATA_CENTER(menu->priv->data_center)); + +- collection = ovirt_data_center_get_storage_domains(menu->priv->data_center); ++ if (menu->priv->data_center != NULL) ++ collection = ovirt_data_center_get_storage_domains(menu->priv->data_center); ++ else ++ collection = ovirt_api_get_storage_domains(menu->priv->api); + #else + collection = ovirt_api_get_storage_domains(menu->priv->api); + #endif +@@ -760,9 +771,7 @@ static void data_center_fetched_cb(GObject *source_object, + ovirt_resource_refresh_finish(resource, result, &error); + if (error != NULL) { + g_debug("failed to fetch Data Center: %s", error->message); +- g_task_return_error(task, error); +- g_object_unref(task); +- return; ++ g_clear_error(&error); + } + + ovirt_foreign_menu_next_async_step(menu, task, STATE_DATA_CENTER); +@@ -777,6 +786,12 @@ static void ovirt_foreign_menu_fetch_data_center_async(OvirtForeignMenu *menu, + g_return_if_fail(OVIRT_IS_CLUSTER(menu->priv->cluster)); + + menu->priv->data_center = ovirt_cluster_get_data_center(menu->priv->cluster); ++ ++ if (menu->priv->data_center == NULL) { ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_DATA_CENTER); ++ return; ++ } ++ + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->data_center), + menu->priv->proxy, + g_task_get_cancellable(task), +@@ -797,9 +812,7 @@ static void cluster_fetched_cb(GObject *source_object, + ovirt_resource_refresh_finish(resource, result, &error); + if (error != NULL) { + g_debug("failed to fetch Cluster: %s", error->message); +- g_task_return_error(task, error); +- g_object_unref(task); +- return; ++ g_clear_error(&error); + } + + ovirt_foreign_menu_next_async_step(menu, task, STATE_CLUSTER); +@@ -811,9 +824,21 @@ static void ovirt_foreign_menu_fetch_cluster_async(OvirtForeignMenu *menu, + { + g_return_if_fail(OVIRT_IS_FOREIGN_MENU(menu)); + g_return_if_fail(OVIRT_IS_PROXY(menu->priv->proxy)); +- g_return_if_fail(OVIRT_IS_HOST(menu->priv->host)); + +- menu->priv->cluster = ovirt_host_get_cluster(menu->priv->host); ++ /* If there is no host information, we get cluster from the VM */ ++ if (menu->priv->host == NULL) { ++ g_return_if_fail(OVIRT_IS_VM(menu->priv->vm)); ++ menu->priv->cluster = ovirt_vm_get_cluster(menu->priv->vm); ++ } else { ++ g_return_if_fail(OVIRT_IS_HOST(menu->priv->host)); ++ menu->priv->cluster = ovirt_host_get_cluster(menu->priv->host); ++ } ++ ++ if (menu->priv->cluster == NULL) { ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_CLUSTER); ++ return; ++ } ++ + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->cluster), + menu->priv->proxy, + g_task_get_cancellable(task), +@@ -834,9 +859,7 @@ static void host_fetched_cb(GObject *source_object, + ovirt_resource_refresh_finish(resource, result, &error); + if (error != NULL) { + g_debug("failed to fetch Host: %s", error->message); +- g_task_return_error(task, error); +- g_object_unref(task); +- return; ++ g_clear_error(&error); + } + + ovirt_foreign_menu_next_async_step(menu, task, STATE_HOST); +@@ -851,6 +874,15 @@ static void ovirt_foreign_menu_fetch_host_async(OvirtForeignMenu *menu, + g_return_if_fail(OVIRT_IS_VM(menu->priv->vm)); + + menu->priv->host = ovirt_vm_get_host(menu->priv->vm); ++ ++ /* In some cases the VM XML does not include host information, so we just ++ * skip to the next step ++ */ ++ if (menu->priv->host == NULL) { ++ ovirt_foreign_menu_next_async_step(menu, task, STATE_HOST); ++ return; ++ } ++ + ovirt_resource_refresh_async(OVIRT_RESOURCE(menu->priv->host), + menu->priv->proxy, + g_task_get_cancellable(task), +-- +2.21.0 + diff --git a/SOURCES/0011-virt-viewer-file-transfer-dialog-improve-error-messa.patch b/SOURCES/0011-virt-viewer-file-transfer-dialog-improve-error-messa.patch new file mode 100644 index 0000000..dfa146a --- /dev/null +++ b/SOURCES/0011-virt-viewer-file-transfer-dialog-improve-error-messa.patch @@ -0,0 +1,79 @@ +From 33877df2a2162818ae240db54e38083918c8089d Mon Sep 17 00:00:00 2001 +From: Kevin Pouget +Date: Thu, 1 Aug 2019 17:31:20 +0200 +Subject: [PATCH] virt-viewer-file-transfer-dialog: improve error message + +This patch improves the error shown to the user when a file transfer +fails. + +The previous behavior was to create a simple message dialog box, with +the error description and the full list of the files that failed to be +transferred. When the list of files was long, the dialog box would +grow bigger than the screen. + +Now, the file list is inserted inside a scrollable widget, whose +height is limited to 170px. + +NB: these two calls would be more adapted, but they require GTK >= +3.22: + +> gtk_scrolled_window_set_max_content_height(GTK_SCROLLED_WINDOW(scrolled_window), 170); +> gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrolled_window), TRUE); + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1496356 + +Signed-off-by: Kevin Pouget +Acked-by: Victor Toso +--- + src/virt-viewer-file-transfer-dialog.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/src/virt-viewer-file-transfer-dialog.c b/src/virt-viewer-file-transfer-dialog.c +index dcf99a3..eae5961 100644 +--- a/src/virt-viewer-file-transfer-dialog.c ++++ b/src/virt-viewer-file-transfer-dialog.c +@@ -204,7 +204,8 @@ static gboolean hide_transfer_dialog(gpointer data) + if (self->priv->failed) { + GSList *sl; + GString *msg = g_string_new(""); +- GtkWidget *dialog; ++ GtkWidget *dialog, *files_label, *scrolled_window, *area; ++ GtkRequisition files_label_sz; + + for (sl = self->priv->failed; sl != NULL; sl = g_slist_next(sl)) { + SpiceFileTransferTask *failed_task = sl->data; +@@ -225,11 +226,28 @@ static gboolean hide_transfer_dialog(gpointer data) + + dialog = gtk_message_dialog_new(GTK_WINDOW(self), 0, GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, +- _("An error caused the following file transfers to fail:%s"), +- msg->str); ++ _("An error caused the following file transfers to fail:")); ++ gtk_window_set_title(GTK_WINDOW(dialog), "Transfer error"); ++ ++ scrolled_window = gtk_scrolled_window_new(NULL, NULL); ++ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), ++ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); ++ ++ area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); ++ gtk_container_add(GTK_CONTAINER(area), scrolled_window); ++ ++ files_label = gtk_label_new(msg->str + 1); /* skip the initial '\n' */ ++ gtk_label_set_selectable(GTK_LABEL(files_label), TRUE); ++ gtk_container_add(GTK_CONTAINER(scrolled_window), files_label); ++ + g_string_free(msg, TRUE); + g_signal_connect(dialog, "response", G_CALLBACK(error_dialog_response), NULL); +- gtk_widget_show(dialog); ++ gtk_widget_show_all(dialog); ++ ++ /* adjust panel to file_label height */ ++ gtk_widget_get_preferred_size(files_label, NULL, &files_label_sz); ++ gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled_window), ++ MIN(files_label_sz.height, 170)); + } + + return G_SOURCE_REMOVE; +-- +2.21.0 + diff --git a/SOURCES/0012-ovirt-foreign-menu-Factor-out-code-to-set-file-colle.patch b/SOURCES/0012-ovirt-foreign-menu-Factor-out-code-to-set-file-colle.patch new file mode 100644 index 0000000..57d5594 --- /dev/null +++ b/SOURCES/0012-ovirt-foreign-menu-Factor-out-code-to-set-file-colle.patch @@ -0,0 +1,58 @@ +From ae35866aa4ff8b880b87d7a8c5ad82f539bb0770 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Tue, 31 Jul 2018 11:01:55 -0300 +Subject: [PATCH virt-viewer] ovirt-foreign-menu: Factor out code to set file + collection + +Signed-off-by: Eduardo Lima (Etrunko) +Acked-by: Victor Toso +--- + src/ovirt-foreign-menu.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index a729934..4c1ea06 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -680,6 +680,18 @@ static gboolean storage_domain_validate(OvirtForeignMenu *menu G_GNUC_UNUSED, + return ret; + } + ++static gboolean ovirt_foreign_menu_set_file_collection(OvirtForeignMenu *menu, OvirtCollection *file_collection) ++{ ++ g_return_val_if_fail(file_collection != NULL, FALSE); ++ ++ if (menu->priv->files) { ++ g_object_unref(G_OBJECT(menu->priv->files)); ++ } ++ menu->priv->files = g_object_ref(G_OBJECT(file_collection)); ++ g_debug("Set VM files to %p", menu->priv->files); ++ return TRUE; ++} ++ + static void storage_domains_fetched_cb(GObject *source_object, + GAsyncResult *result, + gpointer user_data) +@@ -711,14 +723,11 @@ static void storage_domains_fetched_cb(GObject *source_object, + domain_valid = TRUE; + + file_collection = ovirt_storage_domain_get_files(domain); +- if (file_collection != NULL) { +- if (menu->priv->files) { +- g_object_unref(G_OBJECT(menu->priv->files)); +- } +- menu->priv->files = g_object_ref(G_OBJECT(file_collection)); +- g_debug("Set VM files to %p", menu->priv->files); +- break; +- } ++ if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) ++ continue; ++ ++ break; /* There can only be one valid storage domain at a time, ++ no need to iterate more on the list */ + } + + if (menu->priv->files != NULL) { +-- +2.21.0 + diff --git a/SOURCES/0013-Workaround-inconsistency-with-REST-API.patch b/SOURCES/0013-Workaround-inconsistency-with-REST-API.patch new file mode 100644 index 0000000..b167645 --- /dev/null +++ b/SOURCES/0013-Workaround-inconsistency-with-REST-API.patch @@ -0,0 +1,79 @@ +From 905b37a562b94b60511396823e83ff718e2d8fcd Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Fri, 23 Aug 2019 11:30:32 -0300 +Subject: [PATCH virt-viewer] Workaround inconsistency with REST API + +The storage domain object returned in this stage does not provide a link +to the files subcollection. To workaround this problem, we use the id of +the given storage domain to create a new object but referencing the +toplevel api, which in turn provides the file collection. + +This is meant to be a donwnstream patch only, while this issue is not +addressed by RHV. + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1717900 + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/ovirt-foreign-menu.c | 38 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 36 insertions(+), 2 deletions(-) + +diff --git a/src/ovirt-foreign-menu.c b/src/ovirt-foreign-menu.c +index 4c1ea06..d4cc06a 100644 +--- a/src/ovirt-foreign-menu.c ++++ b/src/ovirt-foreign-menu.c +@@ -692,6 +692,37 @@ static gboolean ovirt_foreign_menu_set_file_collection(OvirtForeignMenu *menu, O + return TRUE; + } + ++static gboolean set_file_collection_from_toplevel_storage_domain(OvirtForeignMenu *menu, OvirtStorageDomain *domain) ++{ ++ gboolean ret = FALSE; ++ GError *error = NULL; ++ OvirtResource *resource = NULL; ++ gchar *href = NULL, *id = NULL; ++ ++ g_object_get(domain, "guid", &id, NULL); ++ href = g_strdup_printf("/ovirt-engine/api/storagedomains/%s", id); ++ resource = g_initable_new(OVIRT_TYPE_STORAGE_DOMAIN, NULL, &error, "guid", id, "href", href, NULL); ++ if (error != NULL) { ++ g_warning("Failed to create storage domain with href %s: %s", href, error->message); ++ goto end; ++ } ++ ++ ovirt_resource_refresh(resource, menu->priv->proxy, &error); ++ if (error != NULL) { ++ g_warning("Failed to refresh storage domain: %s", error->message); ++ goto end; ++ } ++ ++ ret = ovirt_foreign_menu_set_file_collection(menu, ovirt_storage_domain_get_files(OVIRT_STORAGE_DOMAIN(resource))); ++ ++end: ++ g_clear_error(&error); ++ g_clear_object(&resource); ++ g_free(id); ++ g_free(href); ++ return ret; ++} ++ + static void storage_domains_fetched_cb(GObject *source_object, + GAsyncResult *result, + gpointer user_data) +@@ -723,8 +754,11 @@ static void storage_domains_fetched_cb(GObject *source_object, + domain_valid = TRUE; + + file_collection = ovirt_storage_domain_get_files(domain); +- if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) +- continue; ++ if (!ovirt_foreign_menu_set_file_collection(menu, file_collection)) { ++ /* Retry with toplevel storage domain */ ++ if (!set_file_collection_from_toplevel_storage_domain(menu, domain)) ++ continue; ++ } + + break; /* There can only be one valid storage domain at a time, + no need to iterate more on the list */ +-- +2.21.0 + diff --git a/SOURCES/0014-remote-viewer-Set-admin-privileges-when-connecting-t.patch b/SOURCES/0014-remote-viewer-Set-admin-privileges-when-connecting-t.patch new file mode 100644 index 0000000..fb300a0 --- /dev/null +++ b/SOURCES/0014-remote-viewer-Set-admin-privileges-when-connecting-t.patch @@ -0,0 +1,34 @@ +From 8259e99be597b78ce0acfe7a2708de7b4239d2a3 Mon Sep 17 00:00:00 2001 +From: "Eduardo Lima (Etrunko)" +Date: Mon, 26 Aug 2019 10:18:20 -0300 +Subject: [PATCH virt-viewer] remote-viewer: Set admin privileges when + connecting to ovirt + +Signed-off-by: Eduardo Lima (Etrunko) +--- + src/remote-viewer.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/remote-viewer.c b/src/remote-viewer.c +index c9562f6..fe6a71b 100644 +--- a/src/remote-viewer.c ++++ b/src/remote-viewer.c +@@ -344,6 +344,7 @@ authenticate_cb(RestProxy *proxy, G_GNUC_UNUSED RestProxyAuth *auth, + g_object_set(G_OBJECT(proxy), + "username", username, + "password", password, ++ "admin", g_str_has_prefix(username, "admin"), + NULL); + #ifdef HAVE_OVIRT_CANCEL + } else { +@@ -439,6 +440,7 @@ create_ovirt_session(VirtViewerApp *app, const char *uri, GError **err) + proxy = ovirt_proxy_new(rest_uri); + g_object_set(proxy, + "username", username, ++ "admin", g_str_has_prefix(username, "admin"), + NULL); + ovirt_set_proxy_options(proxy); + g_signal_connect(G_OBJECT(proxy), "authenticate", +-- +2.21.0 + diff --git a/SPECS/virt-viewer.spec b/SPECS/virt-viewer.spec index edbcb5d..b446213 100644 --- a/SPECS/virt-viewer.spec +++ b/SPECS/virt-viewer.spec @@ -19,7 +19,7 @@ Name: virt-viewer Version: 7.0 -Release: 3%{?dist}%{?extra_release}.1 +Release: 8%{?dist}%{?extra_release} Summary: Virtual Machine Viewer Group: Applications/System License: GPLv2+ @@ -28,6 +28,19 @@ Source0: https://releases.pagure.org/%{name}/%{name}-%{version}.tar.gz Patch001: 0001-Fullscreen-displays-on-wrong-monitors-in-Wayland.patch Patch002: 0002-ovirt-Fix-initial-connection.patch +Patch003: 0003-Spice-listen-for-new-SpiceSession-disconnected-signa.patch +Patch004: 0004-Fix-a-regression-when-initial-connection-fails.patch +Patch005: 0005-configure-Fix-check-for-govirt-functions.patch +Patch006: 0006-ovirt-foreign-menu-New-function-storage_domain_valid.patch +Patch007: 0007-ovirt-foreign-menu-Fix-endpoint-for-storage-domains-.patch +Patch008: 0008-ovirt-foreign-menu-Fix-warnings-on-Rawhide.patch +Patch009: 0009-ovirt-foreign-menu-Only-set-domain_valid-once.patch +Patch010: 0010-ovirt-foreign-menu-Bypass-errors-from-Host-Cluster-D.patch +Patch011: 0011-virt-viewer-file-transfer-dialog-improve-error-messa.patch +Patch012: 0012-ovirt-foreign-menu-Factor-out-code-to-set-file-colle.patch +Patch013: 0013-Workaround-inconsistency-with-REST-API.patch +Patch014: 0014-remote-viewer-Set-admin-privileges-when-connecting-t.patch + Requires: openssh-clients Requires(post): %{_sbindir}/update-alternatives @@ -74,6 +87,18 @@ the display, and libvirt for looking up VNC/SPICE server details. %patch001 -p1 %patch002 -p1 +%patch003 -p1 +%patch004 -p1 +%patch005 -p1 +%patch006 -p1 +%patch007 -p1 +%patch008 -p1 +%patch009 -p1 +%patch010 -p1 +%patch011 -p1 +%patch012 -p1 +%patch013 -p1 +%patch014 -p1 %build @@ -113,13 +138,25 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/remote-viewer.1* %changelog -* Wed May 29 2019 Victor Toso - 7.0-3.1 -- Fix build for z-stream. - Related: rhbz#1714742 +* Tue Aug 27 2019 Eduardo Lima (Etrunko) - 7.0-8 +- Request tolplevel storage domain API object + Related: rhbz#1717900 + +* Mon Aug 19 2019 Kevin Pouget - 7.0-7 +- Improve the error shown to the user when a file transfer fails. + Resolves: rhbz#1496356 + +* Fri Aug 16 2019 Eduardo Lima (Etrunko) - 7.0-6 +- Bypass errors from oVirt foreign menu queries + Resolves: rhbz#1717900 + +* Mon Jul 22 2019 Victor Toso - 7.0-5 +- Listen to SpiceSession::disconnected + Resolves: rhbz#1655957 * Wed Mar 20 2019 Victor Toso - 7.0-4 - Some .spec file changes missed by rebase from F28 on RHEL-8.0 - Resolves: rhbz#1714742 + Resolves: rhbz#1660060 * Tue Dec 18 2018 Victor Toso - 7.0-3 - Fix connection with ovirt