console: Add option to disable autoconnect

As part of making virt-manager cooperate better with external viewers,
add an option to disable console autoconnect. When opening a VM window
for a running VM, you'll see a 'Connect to console' button in place
of the spice/vnc viewer. Click that and things proceed like normal.

This is useful to prevent virt-manager from disconnecting a virt-viewer
instance that's already attached to a VM

https://bugzilla.redhat.com/show_bug.cgi?id=1793876

Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
Cole Robinson 2020-09-09 19:04:44 -04:00
parent bbbfd4b7c8
commit ac8591192f
11 changed files with 152 additions and 12 deletions

View File

@ -25,6 +25,12 @@
<summary>Automatically resize guest when window size changes</summary>
<description>Automatically change guest resolution along with virt-manager window. Only works with spice with a vdagent set up. -1 = global default, 0 = off, 1 = on.</description>
</key>
<key name="autoconnect" type="i">
<default>-1</default>
<summary>Autoconnect to the default VM console when the VM window is opened</summary>
<description>Autoconnect to the default VM console when the VM window is opened. Users may want to turn this off if they prefer to use another viewer app for their VMs, and don't want virt-manager to interfere, but they still want to use virt-manager's details. -1 = global default, 0 = off, 1 = on</description>
</key>
</schema>
@ -222,6 +228,12 @@
<summary>Enable SPICE Auto USB redirection in console window</summary>
<description>Whether to enable SPICE Auto USB redirection while connected to the guest console.</description>
</key>
<key name="autoconnect" type="b">
<default>true</default>
<summary>Autoconnect to the default VM console when the VM window is opened</summary>
<description>Autoconnect to the default VM console when the VM window is opened. Users may want to turn this off if they prefer to use another viewer app for their VMs, and don't want virt-manager to interfere, but they still want to use virt-manager's details.</description>
</key>
</schema>
<schema id="org.virt-manager.virt-manager.details"

View File

@ -255,6 +255,24 @@ class Console(uiutils.UITestCase):
_click_textconsole_menu("Graphical Console")
uiutils.check(lambda: con.showing)
@_vm_wrapper("uitests-spice-standard")
def testConsoleAutoconnect(self, dom):
ignore = dom
win = self.app.topwin
con = win.find("console-gfx-viewport")
uiutils.check(lambda: con.showing)
# Disable autoconnect
vmenu = win.find("^View$", "menu")
vmenu.click()
vmenu.find("Autoconnect").click()
dom.destroy()
self.sleep(1)
dom.create()
uiutils.check(lambda: not con.showing)
win.find("Connect to console", "push button").click()
uiutils.check(lambda: con.showing)
@_vm_wrapper("uitests-lxc-serial", uri="lxc:///")
def testConsoleLXCSerial(self, dom):
"""

View File

@ -57,6 +57,7 @@ class VMMPrefs(uiutils.UITestCase):
tab.combo_select("SPICE USB", "Manual redirect")
tab.combo_select("Resize guest", "On")
tab.combo_select("Graphical console scaling", "Always")
tab.find("Console autoconnect", "check box").click()
tab.find("Change...", "push button").click()
keyframe = self.app.root.find_fuzzy("Configure grab", "dialog")

View File

@ -2,6 +2,11 @@
<!-- Generated with glade 3.36.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkImage" id="image70">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
<object class="GtkNotebook" id="console-pages">
<property name="visible">True</property>
<property name="can_focus">True</property>
@ -282,6 +287,32 @@
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkButton" id="console-connect-button">
<property name="label" translatable="yes">_Connect to console</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_console_connect_button_clicked" swapped="no"/>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">Connect</property>
</object>
<packing>
<property name="position">3</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="position">2</property>
@ -304,9 +335,4 @@
</object>
</child>
</object>
<object class="GtkImage" id="image70">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
</interface>

View File

@ -745,6 +745,34 @@ Redirection:</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">If disabled, the VM window will not automatically connect to the running VM graphical console.</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Console autoconnec_t:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">prefs-console-autoconnect</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="prefs-console-autoconnect">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_prefs_console_autoconnect_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
</object>
</child>
</object>

View File

@ -246,6 +246,15 @@
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkCheckMenuItem" id="details-menu-view-autoconnect">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Autoconnect</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_details_menu_view_autoconnect_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separator7">
<property name="visible">True</property>

View File

@ -487,6 +487,11 @@ class vmmConfig(object):
def set_auto_usbredir(self, state):
self.conf.set("/console/auto-redirect", state)
def get_console_autoconnect(self):
return bool(self.conf.get("/console/autoconnect"))
def set_console_autoconnect(self, val):
return self.conf.set("/console/autoconnect", val)
# Show VM details toolbar
def get_details_show_toolbar(self):
res = self.conf.get("/details/show-toolbar")

View File

@ -25,7 +25,8 @@ from ..lib.keyring import vmmKeyring
# console-gfx-pages IDs
(_GFX_PAGE_VIEWER,
_GFX_PAGE_AUTH,
_GFX_PAGE_UNAVAILABLE) = range(3)
_GFX_PAGE_UNAVAILABLE,
_GFX_PAGE_CONNECT) = range(4)
class _TimedRevealer(vmmGObject):
@ -317,6 +318,7 @@ class vmmConsolePages(vmmGObjectUI):
# Initialize display widget
self._viewer = None
self._viewer_connect_clicked = False
self._in_fullscreen = False
# Fullscreen toolbar
@ -350,6 +352,7 @@ class vmmConsolePages(vmmGObjectUI):
"on_console_pages_switch_page": self._page_changed_cb,
"on_console_auth_password_activate": self._auth_login_cb,
"on_console_auth_login_clicked": self._auth_login_cb,
"on_console_connect_button_clicked": self._connect_button_clicked_cb,
})
self.widget("console-gfx-scroll").connect("size-allocate",
@ -372,12 +375,6 @@ class vmmConsolePages(vmmGObjectUI):
self._serial_consoles = []
##########################
# Initialization helpers #
##########################
#################
# Internal APIs #
#################
@ -596,6 +593,7 @@ class vmmConsolePages(vmmGObjectUI):
def _close_viewer(self):
self._leave_fullscreen()
self._viewer_connect_clicked = False
for serial in self._serial_consoles:
serial.close()
@ -679,6 +677,9 @@ class vmmConsolePages(vmmGObjectUI):
if self._viewer:
self._viewer.console_grab_focus()
def _activate_gfx_connect_page(self):
self.widget("console-gfx-pages").set_current_page(_GFX_PAGE_CONNECT)
def _viewer_is_visible(self):
is_visible = self.widget("console-pages").is_visible()
cpage = self.widget("console-pages").get_current_page()
@ -733,6 +734,11 @@ class vmmConsolePages(vmmGObjectUI):
self._activate_gfx_unavailable_page(msg)
return
if (not self.vm.get_console_autoconnect() and
not self._viewer_connect_clicked):
self._activate_gfx_connect_page()
return
self._activate_gfx_unavailable_page(
_("Connecting to graphical console for guest"))
@ -942,6 +948,10 @@ class vmmConsolePages(vmmGObjectUI):
def _auth_login_cb(self, src):
self._set_credentials()
def _connect_button_clicked_cb(self, src):
self._viewer_connect_clicked = True
self._init_viewer()
def _page_changed_cb(self, src, origpage, newpage):
# Hide the contents of all other pages, so they don't screw
# up window sizing

View File

@ -1558,6 +1558,17 @@ class vmmDomain(vmmLibvirtObject):
return self.config.get_console_resizeguest()
return ret
def on_console_autoconnect_changed(self, *args, **kwargs):
return self.config.listen_pervm(self.get_uuid(), "/resize-guest",
*args, **kwargs)
def set_console_autoconnect(self, value):
self.config.set_pervm(self.get_uuid(), "/autoconnect", value)
def get_console_autoconnect(self):
ret = self.config.get_pervm(self.get_uuid(), "/autoconnect")
if ret == -1:
return self.config.get_console_autoconnect()
return ret
def set_details_window_size(self, w, h):
self.config.set_pervm(self.get_uuid(), "/vm-window-size", (w, h))
def get_details_window_size(self):

View File

@ -42,6 +42,7 @@ class vmmPreferences(vmmGObjectUI):
self.refresh_console_scaling()
self.refresh_console_resizeguest()
self.refresh_console_autoredir()
self.refresh_console_autoconnect()
self.refresh_new_vm_sound()
self.refresh_graphics_type()
self.refresh_add_spice_usbredir()
@ -70,6 +71,7 @@ class vmmPreferences(vmmGObjectUI):
"on_prefs_console_scaling_changed": self.change_console_scaling,
"on_prefs_console_resizeguest_changed": self.change_console_resizeguest,
"on_prefs_console_autoredir_changed": self.change_console_autoredir,
"on_prefs_console_autoconnect_toggled": self.change_console_autoconnect,
"on_prefs_new_vm_sound_toggled": self.change_new_vm_sound,
"on_prefs_graphics_type_changed": self.change_graphics_type,
"on_prefs_add_spice_usbredir_changed": self.change_add_spice_usbredir,
@ -230,6 +232,9 @@ class vmmPreferences(vmmGObjectUI):
combo = self.widget("prefs-console-autoredir")
val = self.config.get_auto_usbredir()
uiutil.set_list_selection(combo, val)
def refresh_console_autoconnect(self):
val = self.config.get_console_autoconnect()
self.widget("prefs-console-autoconnect").set_active(val)
def refresh_new_vm_sound(self):
self.widget("prefs-new-vm-sound").set_active(
@ -378,6 +383,8 @@ class vmmPreferences(vmmGObjectUI):
def change_console_autoredir(self, box):
val = uiutil.get_list_selection(box)
self.config.set_auto_usbredir(val)
def change_console_autoconnect(self, src):
self.config.set_console_autoconnect(bool(src.get_active()))
def change_new_vm_sound(self, src):
self.config.set_new_vm_sound(src.get_active())

View File

@ -128,6 +128,7 @@ class vmmVMWindow(vmmGObjectUI):
"on_details_menu_view_scale_fullscreen_toggled": self._scaling_ui_changed_cb,
"on_details_menu_view_scale_never_toggled": self._scaling_ui_changed_cb,
"on_details_menu_view_resizeguest_toggled": self._resizeguest_ui_changed_cb,
"on_details_menu_view_autoconnect_activate": self._autoconnect_ui_changed_cb,
})
# Deliberately keep all this after signal connection
@ -146,6 +147,10 @@ class vmmVMWindow(vmmGObjectUI):
self.vm.on_console_resizeguest_changed(
self._console_refresh_resizeguest_from_settings))
self._console_refresh_autoconnect_from_settings()
self.add_gsettings_handle(
self.vm.on_console_autoconnect_changed(
self._console_refresh_autoconnect_from_settings))
self.refresh_vm_state()
self.activate_default_page()
@ -671,6 +676,14 @@ class vmmVMWindow(vmmGObjectUI):
self._console.vmwindow_sync_resizeguest_with_display()
def _autoconnect_ui_changed_cb(self, src):
val = int(self.widget("details-menu-view-autoconnect").get_active())
self.vm.set_console_autoconnect(val)
def _console_refresh_autoconnect_from_settings(self):
val = self.vm.get_console_autoconnect()
self.widget("details-menu-view-autoconnect").set_active(val)
def _size_to_vm_cb(self, src):
self._console.vmwindow_set_size_to_vm()