2006-06-29 03:50:17 +08:00
|
|
|
#
|
2014-06-26 17:51:38 +08:00
|
|
|
# Copyright (C) 2006, 2013-2014 Red Hat, Inc.
|
2006-06-29 03:50:17 +08:00
|
|
|
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
2007-11-21 00:12:20 +08:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301 USA.
|
2006-06-29 03:50:17 +08:00
|
|
|
#
|
2007-11-21 00:12:20 +08:00
|
|
|
|
2006-09-26 06:41:47 +08:00
|
|
|
import logging
|
2013-07-13 10:10:16 +08:00
|
|
|
import re
|
2017-10-11 19:35:53 +08:00
|
|
|
import queue
|
2009-07-12 09:23:16 +08:00
|
|
|
import threading
|
2014-04-16 22:32:52 +08:00
|
|
|
import traceback
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2016-06-07 23:33:21 +08:00
|
|
|
from gi.repository import Gio
|
|
|
|
from gi.repository import GLib
|
|
|
|
from gi.repository import Gtk
|
|
|
|
|
2014-09-13 04:10:45 +08:00
|
|
|
from . import packageutils
|
|
|
|
from .baseclass import vmmGObject
|
2018-03-15 01:13:22 +08:00
|
|
|
from .connmanager import vmmConnectionManager
|
2014-09-13 04:10:45 +08:00
|
|
|
from .connect import vmmConnect
|
|
|
|
from .error import vmmErrorDialog
|
2018-03-14 01:00:59 +08:00
|
|
|
from .inspection import vmmInspection
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-06-09 04:33:20 +08:00
|
|
|
DETAILS_PERF = 1
|
|
|
|
DETAILS_CONFIG = 2
|
|
|
|
DETAILS_CONSOLE = 3
|
|
|
|
|
2013-07-07 21:42:21 +08:00
|
|
|
(PRIO_HIGH,
|
|
|
|
PRIO_LOW) = range(1, 3)
|
|
|
|
|
2013-04-14 02:34:52 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
class _ConnState(object):
|
|
|
|
def __init__(self, uri, probe):
|
|
|
|
self.uri = uri
|
|
|
|
|
|
|
|
self.probeConnection = probe
|
|
|
|
|
|
|
|
self.windowDetails = {}
|
|
|
|
self.windowHost = None
|
|
|
|
|
|
|
|
|
2010-12-10 01:37:48 +08:00
|
|
|
class vmmEngine(vmmGObject):
|
2018-01-10 01:58:38 +08:00
|
|
|
CLI_SHOW_MANAGER = "manager"
|
2015-11-25 04:21:26 +08:00
|
|
|
CLI_SHOW_DOMAIN_CREATOR = "creator"
|
|
|
|
CLI_SHOW_DOMAIN_EDITOR = "editor"
|
|
|
|
CLI_SHOW_DOMAIN_PERFORMANCE = "performance"
|
|
|
|
CLI_SHOW_DOMAIN_CONSOLE = "console"
|
|
|
|
CLI_SHOW_HOST_SUMMARY = "summary"
|
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
_instance = None
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_instance(cls):
|
|
|
|
if not cls._instance:
|
|
|
|
cls._instance = cls()
|
|
|
|
return cls._instance
|
|
|
|
|
2010-12-10 01:37:48 +08:00
|
|
|
def __init__(self):
|
|
|
|
vmmGObject.__init__(self)
|
2009-11-16 04:17:03 +08:00
|
|
|
|
2006-06-15 04:20:06 +08:00
|
|
|
self.windowConnect = None
|
2006-08-09 05:02:15 +08:00
|
|
|
self.windowCreate = None
|
2007-08-10 04:19:41 +08:00
|
|
|
self.windowManager = None
|
2009-11-16 04:17:03 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
self._connstates = {}
|
2010-12-01 03:33:21 +08:00
|
|
|
self.err = vmmErrorDialog()
|
2015-04-12 02:34:38 +08:00
|
|
|
self.err.set_find_parent_cb(self._find_error_parent_cb)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
self._timer = None
|
2018-03-09 02:08:17 +08:00
|
|
|
self._systray = None
|
2015-12-04 04:54:52 +08:00
|
|
|
|
|
|
|
self._gtkapplication = None
|
|
|
|
self._init_gtk_application()
|
2009-07-28 10:30:01 +08:00
|
|
|
|
2013-07-07 08:03:42 +08:00
|
|
|
self._tick_counter = 0
|
2009-07-12 09:23:16 +08:00
|
|
|
self._tick_thread_slow = False
|
2013-07-07 08:03:42 +08:00
|
|
|
self._tick_thread = threading.Thread(name="Tick thread",
|
|
|
|
target=self._handle_tick_queue,
|
|
|
|
args=())
|
|
|
|
self._tick_thread.daemon = True
|
2017-10-11 19:35:53 +08:00
|
|
|
self._tick_queue = queue.PriorityQueue(100)
|
2009-07-12 09:23:16 +08:00
|
|
|
|
2008-06-14 00:12:37 +08:00
|
|
|
# Counter keeping track of how many manager and details windows
|
2009-10-29 23:08:40 +08:00
|
|
|
# are open. When it is decremented to 0, close the app or
|
|
|
|
# keep running in system tray if enabled
|
2008-06-14 00:12:37 +08:00
|
|
|
self.windows = 0
|
|
|
|
|
2010-03-04 05:58:50 +08:00
|
|
|
|
2018-03-14 22:29:20 +08:00
|
|
|
@property
|
2018-03-15 01:13:22 +08:00
|
|
|
def _connobjs(self):
|
|
|
|
return vmmConnectionManager.get_instance().conns
|
2018-03-14 22:29:20 +08:00
|
|
|
|
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _cleanup(self):
|
|
|
|
self.err = None
|
2015-12-04 04:54:52 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
if self._timer is not None:
|
|
|
|
GLib.source_remove(self._timer)
|
|
|
|
|
|
|
|
if self._systray:
|
|
|
|
self._systray.cleanup()
|
|
|
|
self._systray = None
|
|
|
|
|
|
|
|
self._get_manager()
|
|
|
|
if self.windowManager:
|
|
|
|
self.windowManager.cleanup()
|
|
|
|
self.windowManager = None
|
|
|
|
|
|
|
|
if self.windowConnect:
|
|
|
|
self.windowConnect.cleanup()
|
|
|
|
self.windowConnect = None
|
|
|
|
|
|
|
|
if self.windowCreate:
|
|
|
|
self.windowCreate.cleanup()
|
|
|
|
self.windowCreate = None
|
|
|
|
|
|
|
|
# Do this last, so any manually 'disconnected' signals
|
|
|
|
# take precedence over cleanup signal removal
|
|
|
|
for uri in self._connstates:
|
|
|
|
self._cleanup_connstate(uri)
|
|
|
|
self._connstates = {}
|
|
|
|
vmmConnectionManager.get_instance().cleanup()
|
|
|
|
|
|
|
|
def _find_error_parent_cb(self):
|
2015-12-04 04:54:52 +08:00
|
|
|
"""
|
2018-03-15 06:43:47 +08:00
|
|
|
Search over the toplevel windows for any that are visible or have
|
|
|
|
focus, and use that
|
2015-12-04 04:54:52 +08:00
|
|
|
"""
|
2018-03-15 06:43:47 +08:00
|
|
|
windowlist = [self.windowManager]
|
|
|
|
for connstate in self._connstates.values():
|
|
|
|
windowlist.extend(list(connstate.windowDetails.values()))
|
|
|
|
windowlist += [connstate.windowHost]
|
2015-12-04 04:54:52 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
use_win = None
|
|
|
|
for window in windowlist:
|
|
|
|
if not window:
|
|
|
|
continue
|
|
|
|
if window.topwin.has_focus():
|
|
|
|
use_win = window
|
|
|
|
break
|
|
|
|
if not use_win and window.is_visible():
|
|
|
|
use_win = window
|
2015-12-04 04:54:52 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
if use_win:
|
|
|
|
return use_win.topwin
|
|
|
|
|
|
|
|
#################
|
|
|
|
# init handling #
|
|
|
|
#################
|
2015-12-04 04:54:52 +08:00
|
|
|
|
2017-10-20 23:46:40 +08:00
|
|
|
def _default_startup(self, skip_autostart, cliuri):
|
2018-03-15 06:43:47 +08:00
|
|
|
"""
|
|
|
|
Actual startup routines if we are running a new instance of the app
|
|
|
|
"""
|
2018-03-09 02:08:17 +08:00
|
|
|
self._init_systray()
|
2018-03-15 06:43:47 +08:00
|
|
|
vmmInspection.get_instance()
|
|
|
|
|
|
|
|
self.add_gsettings_handle(
|
|
|
|
self.config.on_stats_update_interval_changed(
|
|
|
|
self._timer_changed_cb))
|
|
|
|
|
|
|
|
self._schedule_timer()
|
|
|
|
for _uri in self._connobjs:
|
|
|
|
self._add_conn(_uri, False)
|
|
|
|
|
|
|
|
self._tick_thread.start()
|
|
|
|
self._tick()
|
2018-03-09 02:08:17 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
uris = list(self._connstates.keys())
|
2015-12-04 04:54:52 +08:00
|
|
|
if not uris:
|
|
|
|
logging.debug("No stored URIs found.")
|
2013-05-30 05:43:38 +08:00
|
|
|
else:
|
2015-12-04 04:54:52 +08:00
|
|
|
logging.debug("Loading stored URIs:\n%s",
|
|
|
|
" \n".join(sorted(uris)))
|
2013-04-16 07:25:54 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
if not skip_autostart:
|
2018-03-15 06:43:47 +08:00
|
|
|
self.idle_add(self._autostart_conns)
|
2013-04-16 07:25:54 +08:00
|
|
|
|
2017-10-20 23:46:40 +08:00
|
|
|
if not self.config.get_conn_uris() and not cliuri:
|
2015-12-04 04:54:52 +08:00
|
|
|
# Only add default if no connections are currently known
|
|
|
|
self.timeout_add(1000, self._add_default_conn)
|
|
|
|
|
2018-03-09 02:08:17 +08:00
|
|
|
def _init_systray(self):
|
2018-03-15 06:58:22 +08:00
|
|
|
from .systray import vmmSystray
|
2018-03-15 01:13:22 +08:00
|
|
|
self._systray = vmmSystray()
|
2018-03-09 02:08:17 +08:00
|
|
|
self._systray.connect("action-toggle-manager", self._do_toggle_manager)
|
|
|
|
self._systray.connect("action-show-domain", self._do_show_vm)
|
|
|
|
|
|
|
|
self.add_gsettings_handle(
|
|
|
|
self.config.on_view_system_tray_changed(self._system_tray_changed))
|
2009-07-28 10:30:01 +08:00
|
|
|
|
2018-03-09 02:08:17 +08:00
|
|
|
def _system_tray_changed(self, *ignore):
|
2009-10-29 23:08:40 +08:00
|
|
|
systray_enabled = self.config.get_view_system_tray()
|
|
|
|
if self.windows == 0 and not systray_enabled:
|
|
|
|
# Show the manager so that the user can control the application
|
2015-11-25 04:21:26 +08:00
|
|
|
self._show_manager()
|
2009-10-29 23:08:40 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
def _add_default_conn(self):
|
2018-03-15 06:43:47 +08:00
|
|
|
"""
|
|
|
|
If there's no cached connections, or any requested on the command
|
|
|
|
line, try to determine a default URI and open it, possibly talking
|
|
|
|
to packagekit and other bits
|
|
|
|
"""
|
|
|
|
manager = self._get_manager()
|
2013-09-02 02:19:23 +08:00
|
|
|
|
2010-03-04 05:58:50 +08:00
|
|
|
# Manager fail message
|
|
|
|
msg = _("Could not detect a default hypervisor. Make\n"
|
|
|
|
"sure the appropriate virtualization packages\n"
|
2017-08-14 22:04:43 +08:00
|
|
|
"containing kvm, qemu, libvirt, etc. are\n"
|
|
|
|
"installed, and that libvirtd is running.\n\n"
|
2010-03-04 05:58:50 +08:00
|
|
|
"A hypervisor connection can be manually\n"
|
|
|
|
"added via File->Add Connection")
|
|
|
|
|
|
|
|
logging.debug("Determining default libvirt URI")
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
packages_verified = False
|
2010-03-04 05:58:50 +08:00
|
|
|
try:
|
2011-01-15 04:19:58 +08:00
|
|
|
libvirt_packages = self.config.libvirt_packages
|
|
|
|
packages = self.config.hv_packages + libvirt_packages
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
packages_verified = packageutils.check_packagekit(
|
|
|
|
manager, manager.err, packages)
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2010-03-04 05:58:50 +08:00
|
|
|
logging.exception("Error talking to PackageKit")
|
|
|
|
|
2017-08-08 05:26:48 +08:00
|
|
|
tryuri = None
|
2018-03-15 01:13:22 +08:00
|
|
|
if packages_verified:
|
2012-07-09 03:38:52 +08:00
|
|
|
tryuri = "qemu:///system"
|
2017-08-08 05:26:48 +08:00
|
|
|
elif not self.config.test_first_run:
|
2015-04-07 04:43:44 +08:00
|
|
|
tryuri = vmmConnect.default_uri()
|
2010-03-04 05:58:50 +08:00
|
|
|
|
|
|
|
if tryuri is None:
|
|
|
|
manager.set_startup_error(msg)
|
|
|
|
return
|
|
|
|
|
2013-06-25 00:15:28 +08:00
|
|
|
warnmsg = _("The 'libvirtd' service will need to be started.\n\n"
|
|
|
|
"After that, virt-manager will connect to libvirt on\n"
|
|
|
|
"the next application start up.")
|
2013-06-14 05:35:48 +08:00
|
|
|
|
|
|
|
# Do the initial connection in an idle callback, so the
|
|
|
|
# packagekit async dialog has a chance to go away
|
|
|
|
def idle_connect():
|
2018-03-15 01:13:22 +08:00
|
|
|
libvirtd_started = packageutils.start_libvirtd()
|
|
|
|
connected = False
|
|
|
|
try:
|
2018-03-15 06:43:47 +08:00
|
|
|
self._connect_to_uri(tryuri, autoconnect=True)
|
2018-03-15 01:13:22 +08:00
|
|
|
connected = True
|
|
|
|
except Exception:
|
|
|
|
logging.exception("Error connecting to %s", tryuri)
|
|
|
|
|
|
|
|
if not connected and not libvirtd_started:
|
2013-06-14 05:35:48 +08:00
|
|
|
manager.err.ok(_("Libvirt service must be started"), warnmsg)
|
|
|
|
|
|
|
|
self.idle_add(idle_connect)
|
2010-03-04 05:58:50 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _autostart_conns(self):
|
2014-02-01 23:44:45 +08:00
|
|
|
"""
|
|
|
|
We serialize conn autostart, so polkit/ssh-askpass doesn't spam
|
|
|
|
"""
|
2017-10-11 19:35:53 +08:00
|
|
|
connections_queue = queue.Queue()
|
2018-03-15 01:13:22 +08:00
|
|
|
auto_conns = [conn.get_uri() for conn in self._connobjs.values() if
|
|
|
|
conn.get_autoconnect()]
|
2014-02-01 23:44:45 +08:00
|
|
|
|
|
|
|
def add_next_to_queue():
|
|
|
|
if not auto_conns:
|
2017-10-11 19:35:53 +08:00
|
|
|
connections_queue.put(None)
|
2014-02-01 23:44:45 +08:00
|
|
|
else:
|
2017-10-11 19:35:53 +08:00
|
|
|
connections_queue.put(auto_conns.pop(0))
|
2014-02-01 23:44:45 +08:00
|
|
|
|
|
|
|
def state_change_cb(conn):
|
2014-09-12 06:16:21 +08:00
|
|
|
if conn.is_active():
|
2014-02-01 23:44:45 +08:00
|
|
|
add_next_to_queue()
|
|
|
|
conn.disconnect_by_func(state_change_cb)
|
|
|
|
|
|
|
|
def handle_queue():
|
|
|
|
while True:
|
2017-10-11 19:35:53 +08:00
|
|
|
uri = connections_queue.get()
|
2014-02-01 23:44:45 +08:00
|
|
|
if uri is None:
|
|
|
|
return
|
2018-03-15 01:13:22 +08:00
|
|
|
if uri not in self._connobjs:
|
2014-02-01 23:44:45 +08:00
|
|
|
add_next_to_queue()
|
|
|
|
continue
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
conn = self._connobjs[uri]
|
2014-02-01 23:44:45 +08:00
|
|
|
conn.connect("state-changed", state_change_cb)
|
2018-03-15 06:43:47 +08:00
|
|
|
self.idle_add(self._connect_to_uri, uri)
|
2014-02-01 23:44:45 +08:00
|
|
|
|
|
|
|
add_next_to_queue()
|
2014-09-12 23:28:27 +08:00
|
|
|
self._start_thread(handle_queue, "Conn autostart thread")
|
2008-03-24 23:39:19 +08:00
|
|
|
|
2006-06-15 02:36:26 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
############################
|
|
|
|
# Gtk Application handling #
|
|
|
|
############################
|
2011-04-12 06:35:21 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _on_gtk_application_activated(self, ignore):
|
|
|
|
"""
|
|
|
|
Invoked after application.run()
|
|
|
|
"""
|
|
|
|
if not self._application.get_windows():
|
|
|
|
logging.debug("Initial gtkapplication activated")
|
|
|
|
self._application.add_window(Gtk.Window())
|
2006-06-15 04:56:49 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _init_gtk_application(self):
|
|
|
|
self._application = Gtk.Application(
|
|
|
|
application_id="org.virt-manager.virt-manager", flags=0)
|
|
|
|
self._application.register(None)
|
|
|
|
self._application.connect("activate",
|
|
|
|
self._on_gtk_application_activated)
|
2015-11-04 04:56:39 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
action = Gio.SimpleAction.new("cli_command",
|
|
|
|
GLib.VariantType.new("(sss)"))
|
|
|
|
action.connect("activate", self._handle_cli_command)
|
|
|
|
self._application.add_action(action)
|
2015-11-04 04:56:39 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def start(self, uri, show_window, domain, skip_autostart):
|
|
|
|
"""
|
|
|
|
Public entrypoint from virt-manager cli. If app is already
|
|
|
|
running, connect to it and exit, otherwise run our functional
|
|
|
|
default startup.
|
|
|
|
"""
|
|
|
|
# Dispatch dbus CLI command
|
|
|
|
if uri and not show_window:
|
|
|
|
show_window = self.CLI_SHOW_MANAGER
|
|
|
|
data = GLib.Variant("(sss)",
|
|
|
|
(uri or "", show_window or "", domain or ""))
|
|
|
|
self._application.activate_action("cli_command", data)
|
|
|
|
|
|
|
|
if self._application.get_is_remote():
|
|
|
|
logging.debug("Connected to remote app instance.")
|
2007-09-27 09:04:02 +08:00
|
|
|
return
|
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
self._default_startup(skip_autostart, uri)
|
|
|
|
self._application.run(None)
|
2011-04-12 06:35:21 +08:00
|
|
|
|
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
###########################
|
|
|
|
# timer and tick handling #
|
|
|
|
###########################
|
2007-09-27 09:04:02 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _timer_changed_cb(self, *args, **kwargs):
|
2016-04-19 04:42:12 +08:00
|
|
|
ignore1 = args
|
|
|
|
ignore2 = kwargs
|
2018-03-15 06:43:47 +08:00
|
|
|
self._schedule_timer()
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _schedule_timer(self):
|
2010-12-10 03:06:00 +08:00
|
|
|
interval = self.config.get_stats_update_interval() * 1000
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
if self._timer is not None:
|
|
|
|
self.remove_gobject_timeout(self._timer)
|
|
|
|
self._timer = None
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
self._timer = self.timeout_add(interval, self._tick)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-07-07 23:06:15 +08:00
|
|
|
def _add_obj_to_tick_queue(self, obj, isprio, **kwargs):
|
2013-07-07 08:03:42 +08:00
|
|
|
if self._tick_queue.full():
|
2009-07-14 21:45:23 +08:00
|
|
|
if not self._tick_thread_slow:
|
2009-07-12 09:23:16 +08:00
|
|
|
logging.debug("Tick is slow, not running at requested rate.")
|
2009-10-02 00:04:03 +08:00
|
|
|
self._tick_thread_slow = True
|
2013-07-07 08:03:42 +08:00
|
|
|
return
|
2009-07-12 09:23:16 +08:00
|
|
|
|
2013-07-07 08:03:42 +08:00
|
|
|
self._tick_counter += 1
|
2013-07-07 21:42:21 +08:00
|
|
|
self._tick_queue.put((isprio and PRIO_HIGH or PRIO_LOW,
|
2013-07-07 23:06:15 +08:00
|
|
|
self._tick_counter,
|
|
|
|
obj, kwargs))
|
2007-03-10 05:22:43 +08:00
|
|
|
|
2013-07-07 23:06:15 +08:00
|
|
|
def _schedule_priority_tick(self, conn, kwargs):
|
|
|
|
self._add_obj_to_tick_queue(conn, True, **kwargs)
|
2013-07-07 08:03:42 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _tick(self):
|
2018-03-15 01:13:22 +08:00
|
|
|
for conn in self._connobjs.values():
|
2013-07-07 23:06:15 +08:00
|
|
|
self._add_obj_to_tick_queue(conn, False,
|
|
|
|
stats_update=True, pollvm=True)
|
2013-07-07 08:03:42 +08:00
|
|
|
return 1
|
2011-07-26 01:31:36 +08:00
|
|
|
|
2015-04-12 02:41:02 +08:00
|
|
|
def _handle_tick_error(self, msg, details):
|
|
|
|
if self.windows <= 0:
|
|
|
|
# This means the systray icon is running. Don't raise an error
|
|
|
|
# here to avoid spamming dialogs out of nowhere.
|
|
|
|
logging.debug(msg + "\n\n" + details)
|
|
|
|
return
|
|
|
|
self.err.show_err(msg, details=details)
|
|
|
|
|
2013-07-07 08:03:42 +08:00
|
|
|
def _handle_tick_queue(self):
|
|
|
|
while True:
|
2014-04-16 22:32:52 +08:00
|
|
|
ignore1, ignore2, conn, kwargs = self._tick_queue.get()
|
|
|
|
try:
|
2015-04-14 04:56:46 +08:00
|
|
|
conn.tick_from_engine(**kwargs)
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2014-04-16 22:32:52 +08:00
|
|
|
tb = "".join(traceback.format_exc())
|
|
|
|
error_msg = (_("Error polling connection '%s': %s")
|
|
|
|
% (conn.get_uri(), e))
|
2015-04-12 02:41:02 +08:00
|
|
|
self.idle_add(self._handle_tick_error, error_msg, tb)
|
2014-04-16 22:32:52 +08:00
|
|
|
|
2015-09-21 02:20:50 +08:00
|
|
|
# Need to clear reference to make leak check happy
|
|
|
|
conn = None
|
2013-07-07 08:03:42 +08:00
|
|
|
self._tick_queue.task_done()
|
2006-06-14 22:59:40 +08:00
|
|
|
return 1
|
|
|
|
|
2013-07-07 08:03:42 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
#####################################
|
|
|
|
# window counting and exit handling #
|
|
|
|
#####################################
|
|
|
|
|
2011-04-13 22:47:31 +08:00
|
|
|
def increment_window_counter(self, src):
|
|
|
|
ignore = src
|
2008-06-14 00:12:37 +08:00
|
|
|
self.windows += 1
|
2012-01-17 11:04:40 +08:00
|
|
|
logging.debug("window counter incremented to %s", self.windows)
|
2008-06-14 00:12:37 +08:00
|
|
|
|
2011-04-13 22:47:31 +08:00
|
|
|
def decrement_window_counter(self, src):
|
2008-06-14 00:12:37 +08:00
|
|
|
self.windows -= 1
|
2012-01-17 11:04:40 +08:00
|
|
|
logging.debug("window counter decremented to %s", self.windows)
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
self._exit_app_if_no_windows(src)
|
2008-06-14 00:12:37 +08:00
|
|
|
|
2013-07-13 10:10:16 +08:00
|
|
|
def _can_exit(self):
|
|
|
|
# Don't exit if system tray is enabled
|
|
|
|
return (self.windows <= 0 and
|
2018-03-09 02:08:17 +08:00
|
|
|
self._systray and
|
|
|
|
not self._systray.is_visible())
|
2013-07-13 10:10:16 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
def _exit_app_if_no_windows(self, src=None):
|
|
|
|
def cb():
|
|
|
|
if self._can_exit():
|
|
|
|
logging.debug("No windows found, requesting app exit")
|
|
|
|
self.exit_app(src or self)
|
|
|
|
self.idle_add(cb)
|
|
|
|
|
2018-03-15 06:58:22 +08:00
|
|
|
def exit_app(self):
|
|
|
|
"""
|
|
|
|
Public call, manager/details/... use this to force exit the app
|
|
|
|
"""
|
|
|
|
src = self
|
2011-04-13 21:27:02 +08:00
|
|
|
if self.err is None:
|
|
|
|
# Already in cleanup
|
|
|
|
return
|
|
|
|
|
|
|
|
self.cleanup()
|
2011-04-12 00:54:47 +08:00
|
|
|
|
2018-03-13 04:24:28 +08:00
|
|
|
if self.config.test_leak_debug:
|
2011-04-13 21:27:02 +08:00
|
|
|
objs = self.config.get_objects()
|
|
|
|
|
|
|
|
# Engine will always appear to leak
|
|
|
|
objs.remove(self.object_key)
|
|
|
|
|
2018-01-09 22:56:27 +08:00
|
|
|
if src and src.object_key in objs:
|
2011-04-14 23:26:53 +08:00
|
|
|
# UI that initiates the app exit will always appear to leak
|
|
|
|
objs.remove(src.object_key)
|
|
|
|
|
2011-04-13 21:27:02 +08:00
|
|
|
for name in objs:
|
2018-03-13 04:31:13 +08:00
|
|
|
logging.debug("LEAK: %s", name)
|
2011-04-12 00:54:47 +08:00
|
|
|
|
2008-10-30 21:25:53 +08:00
|
|
|
logging.debug("Exiting app normally.")
|
2015-12-04 04:54:52 +08:00
|
|
|
self._application.quit()
|
2008-06-14 00:12:37 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _cleanup_connstate(self, uri):
|
|
|
|
try:
|
|
|
|
connstate = self._connstates[uri]
|
|
|
|
if connstate.windowHost:
|
|
|
|
connstate.windowHost.cleanup()
|
2015-04-12 02:34:38 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
detailsmap = connstate.windowDetails
|
|
|
|
for win in list(detailsmap.values()):
|
|
|
|
win.cleanup()
|
|
|
|
except Exception:
|
|
|
|
logging.exception("Error cleaning up conn in engine")
|
2012-11-08 18:02:17 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
def _add_conn(self, uri, probe):
|
|
|
|
if uri in self._connstates:
|
|
|
|
return self._connobjs[uri]
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
connstate = _ConnState(uri, probe)
|
|
|
|
conn = vmmConnectionManager.get_instance().add_conn(uri)
|
2010-11-24 07:54:12 +08:00
|
|
|
conn.connect("vm-removed", self._do_vm_removed)
|
2015-11-04 04:56:39 +08:00
|
|
|
conn.connect("vm-renamed", self._do_vm_renamed)
|
2011-07-23 04:43:26 +08:00
|
|
|
conn.connect("state-changed", self._do_conn_changed)
|
2013-07-13 10:10:16 +08:00
|
|
|
conn.connect("connect-error", self._connect_error)
|
2013-07-07 08:03:42 +08:00
|
|
|
conn.connect("priority-tick", self._schedule_priority_tick)
|
2018-03-15 01:13:22 +08:00
|
|
|
self._connstates[uri] = connstate
|
2009-07-15 02:48:09 +08:00
|
|
|
return conn
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
def _remove_conn(self, _src, uri):
|
|
|
|
self._cleanup_connstate(uri)
|
|
|
|
self._connstates.pop(uri)
|
|
|
|
vmmConnectionManager.get_instance().remove_conn(uri)
|
2012-11-08 18:02:17 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _do_conn_changed(self, conn):
|
|
|
|
if conn.is_active() or conn.is_connecting():
|
|
|
|
return
|
2013-08-08 20:11:18 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
uri = conn.get_uri()
|
2012-11-08 18:02:17 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
detailsmap = self._connstates[conn.get_uri()].windowDetails
|
|
|
|
for connkey in list(detailsmap):
|
|
|
|
detailsmap[connkey].cleanup()
|
|
|
|
detailsmap.pop(connkey)
|
2012-11-08 18:02:17 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
if (self.windowCreate and
|
|
|
|
self.windowCreate.conn and
|
|
|
|
self.windowCreate.conn.get_uri() == uri):
|
|
|
|
self.windowCreate.close()
|
2012-11-08 18:02:17 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _connect_to_uri(self, uri, autoconnect=None, probe=False):
|
|
|
|
conn = self._add_conn(uri, probe=probe)
|
2018-03-15 01:13:22 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
if autoconnect is not None:
|
|
|
|
conn.set_autoconnect(bool(autoconnect))
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
conn.open()
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2013-07-13 10:10:16 +08:00
|
|
|
def _connect_error(self, conn, errmsg, tb, warnconsole):
|
|
|
|
errmsg = errmsg.strip(" \n")
|
|
|
|
tb = tb.strip(" \n")
|
|
|
|
hint = ""
|
|
|
|
show_errmsg = True
|
|
|
|
|
|
|
|
if conn.is_remote():
|
2014-09-25 22:13:20 +08:00
|
|
|
logging.debug("connect_error: conn transport=%s",
|
2015-04-12 00:08:57 +08:00
|
|
|
conn.get_uri_transport())
|
2013-07-13 10:10:16 +08:00
|
|
|
if re.search(r"nc: .* -- 'U'", tb):
|
2017-08-08 06:16:45 +08:00
|
|
|
hint += _("The remote host requires a version of netcat/nc "
|
2013-07-13 10:10:16 +08:00
|
|
|
"which supports the -U option.")
|
|
|
|
show_errmsg = False
|
2015-04-12 00:08:57 +08:00
|
|
|
elif (conn.get_uri_transport() == "ssh" and
|
2013-07-13 10:10:16 +08:00
|
|
|
re.search(r"ssh-askpass", tb)):
|
|
|
|
|
2017-08-08 05:41:52 +08:00
|
|
|
askpass = (self.config.askpass_package and
|
|
|
|
self.config.askpass_package[0] or
|
|
|
|
"openssh-askpass")
|
|
|
|
hint += _("You need to install %s or "
|
2017-08-08 06:16:45 +08:00
|
|
|
"similar to connect to this host.") % askpass
|
2013-07-13 10:10:16 +08:00
|
|
|
show_errmsg = False
|
|
|
|
else:
|
2017-08-08 06:16:45 +08:00
|
|
|
hint += _("Verify that the 'libvirtd' daemon is running "
|
2013-07-13 10:10:16 +08:00
|
|
|
"on the remote host.")
|
|
|
|
|
|
|
|
elif conn.is_xen():
|
|
|
|
hint += _("Verify that:\n"
|
|
|
|
" - A Xen host kernel was booted\n"
|
|
|
|
" - The Xen service has been started")
|
|
|
|
|
|
|
|
else:
|
|
|
|
if warnconsole:
|
2017-08-08 06:16:45 +08:00
|
|
|
hint += _("Could not detect a local session: if you are "
|
|
|
|
"running virt-manager over ssh -X or VNC, you "
|
|
|
|
"may not be able to connect to libvirt as a "
|
2013-07-13 10:10:16 +08:00
|
|
|
"regular user. Try running as root.")
|
|
|
|
show_errmsg = False
|
|
|
|
elif re.search(r"libvirt-sock", tb):
|
|
|
|
hint += _("Verify that the 'libvirtd' daemon is running.")
|
|
|
|
show_errmsg = False
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
connstate = self._connstates[conn.get_uri()]
|
2017-10-20 23:46:40 +08:00
|
|
|
msg = _("Unable to connect to libvirt %s." % conn.get_uri())
|
2013-07-13 10:10:16 +08:00
|
|
|
if show_errmsg:
|
|
|
|
msg += "\n\n%s" % errmsg
|
|
|
|
if hint:
|
|
|
|
msg += "\n\n%s" % hint
|
|
|
|
|
|
|
|
msg = msg.strip("\n")
|
|
|
|
details = msg
|
|
|
|
details += "\n\n"
|
|
|
|
details += "Libvirt URI is: %s\n\n" % conn.get_uri()
|
|
|
|
details += tb
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
if connstate.probeConnection:
|
2015-04-05 07:40:22 +08:00
|
|
|
msg += "\n\n"
|
|
|
|
msg += _("Would you still like to remember this connection?")
|
|
|
|
|
2013-08-08 20:11:18 +08:00
|
|
|
title = _("Virtual Machine Manager Connection Failure")
|
2018-03-15 01:13:22 +08:00
|
|
|
if connstate.probeConnection:
|
2013-08-08 20:11:18 +08:00
|
|
|
remember_connection = self.err.show_err(msg, details, title,
|
|
|
|
buttons=Gtk.ButtonsType.YES_NO,
|
2013-09-07 08:16:37 +08:00
|
|
|
dialog_type=Gtk.MessageType.QUESTION, modal=True)
|
2013-08-08 20:11:18 +08:00
|
|
|
if remember_connection:
|
2018-03-15 01:13:22 +08:00
|
|
|
connstate.probeConnection = False
|
2013-08-08 20:11:18 +08:00
|
|
|
else:
|
|
|
|
self.idle_add(self._do_edit_connect, self.windowManager, conn)
|
2013-07-13 10:10:16 +08:00
|
|
|
else:
|
2013-08-08 20:11:18 +08:00
|
|
|
if self._can_exit():
|
2013-09-07 08:16:37 +08:00
|
|
|
self.err.show_err(msg, details, title, modal=True)
|
2015-12-04 04:54:52 +08:00
|
|
|
self._exit_app_if_no_windows(conn)
|
2013-08-08 20:11:18 +08:00
|
|
|
else:
|
|
|
|
self.err.show_err(msg, details, title)
|
2013-07-13 10:10:16 +08:00
|
|
|
|
2015-04-05 07:40:22 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
##################################
|
|
|
|
# callbacks and dialog launchers #
|
|
|
|
##################################
|
|
|
|
|
|
|
|
def _do_vm_removed(self, conn, connkey):
|
|
|
|
detailsmap = self._connstates[conn.get_uri()].windowDetails
|
|
|
|
if connkey not in detailsmap:
|
|
|
|
return
|
|
|
|
|
|
|
|
detailsmap[connkey].cleanup()
|
|
|
|
detailsmap.pop(connkey)
|
|
|
|
|
|
|
|
def _do_vm_renamed(self, conn, oldconnkey, newconnkey):
|
|
|
|
detailsmap = self._connstates[conn.get_uri()].windowDetails
|
|
|
|
if oldconnkey not in detailsmap:
|
|
|
|
return
|
|
|
|
|
|
|
|
detailsmap[newconnkey] = detailsmap.pop(oldconnkey)
|
2010-11-24 07:54:12 +08:00
|
|
|
|
|
|
|
def _get_host_dialog(self, uri):
|
2018-03-15 01:13:22 +08:00
|
|
|
connstate = self._connstates[uri]
|
|
|
|
if connstate.windowHost:
|
|
|
|
return connstate.windowHost
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2018-03-15 06:58:22 +08:00
|
|
|
from .host import vmmHost
|
2018-03-15 01:13:22 +08:00
|
|
|
conn = self._connobjs[uri]
|
2014-06-03 05:17:47 +08:00
|
|
|
obj = vmmHost(conn)
|
2011-04-13 22:47:31 +08:00
|
|
|
|
2010-11-24 07:54:12 +08:00
|
|
|
obj.connect("action-view-manager", self._do_show_manager)
|
2011-04-13 22:47:31 +08:00
|
|
|
obj.connect("host-opened", self.increment_window_counter)
|
|
|
|
obj.connect("host-closed", self.decrement_window_counter)
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
connstate.windowHost = obj
|
|
|
|
return connstate.windowHost
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2010-11-24 09:13:50 +08:00
|
|
|
def _do_show_host(self, src, uri):
|
2010-11-24 07:54:12 +08:00
|
|
|
try:
|
|
|
|
self._get_host_dialog(uri).show()
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2011-04-06 23:22:03 +08:00
|
|
|
src.err.show_err(_("Error launching host dialog: %s") % str(e))
|
2010-11-24 07:54:12 +08:00
|
|
|
|
|
|
|
def _get_connect_dialog(self):
|
|
|
|
if self.windowConnect:
|
|
|
|
return self.windowConnect
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
def completed(_src, uri, autoconnect):
|
2018-03-15 06:43:47 +08:00
|
|
|
self._connect_to_uri(uri, autoconnect, probe=True)
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2012-11-08 18:02:17 +08:00
|
|
|
def cancelled(src):
|
2018-03-15 01:13:22 +08:00
|
|
|
if not self._connstates:
|
2012-11-08 18:02:17 +08:00
|
|
|
self.exit_app(src)
|
|
|
|
|
2010-12-09 06:26:19 +08:00
|
|
|
obj = vmmConnect()
|
2012-11-08 18:02:17 +08:00
|
|
|
obj.connect("completed", completed)
|
|
|
|
obj.connect("cancelled", cancelled)
|
2010-11-24 07:54:12 +08:00
|
|
|
self.windowConnect = obj
|
|
|
|
return self.windowConnect
|
|
|
|
|
2013-08-08 20:11:18 +08:00
|
|
|
def _do_show_connect(self, src, reset_state=True):
|
2010-11-24 07:54:12 +08:00
|
|
|
try:
|
2013-08-08 20:11:18 +08:00
|
|
|
self._get_connect_dialog().show(src.topwin, reset_state)
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2011-04-06 23:22:03 +08:00
|
|
|
src.err.show_err(_("Error launching connect dialog: %s") % str(e))
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2013-08-08 20:11:18 +08:00
|
|
|
def _do_edit_connect(self, src, connection):
|
|
|
|
try:
|
|
|
|
self._do_show_connect(src, False)
|
|
|
|
finally:
|
2018-03-15 01:13:22 +08:00
|
|
|
self._remove_conn(src, connection.get_uri())
|
2013-08-08 20:11:18 +08:00
|
|
|
|
2014-06-03 05:17:47 +08:00
|
|
|
def _get_details_dialog(self, uri, connkey):
|
2018-03-15 01:13:22 +08:00
|
|
|
detailsmap = self._connstates[uri].windowDetails
|
|
|
|
if connkey in detailsmap:
|
|
|
|
return detailsmap[connkey]
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2018-03-15 06:58:22 +08:00
|
|
|
from .details import vmmDetails
|
2018-03-15 01:13:22 +08:00
|
|
|
obj = vmmDetails(self._connobjs[uri].get_vm(connkey))
|
2010-11-24 07:54:12 +08:00
|
|
|
obj.connect("action-view-manager", self._do_show_manager)
|
2011-04-13 22:47:31 +08:00
|
|
|
obj.connect("details-opened", self.increment_window_counter)
|
|
|
|
obj.connect("details-closed", self.decrement_window_counter)
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
detailsmap[connkey] = obj
|
|
|
|
return detailsmap[connkey]
|
2013-07-13 10:10:16 +08:00
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
def _show_vm_helper(self, src, uri, connkey, page, forcepage):
|
2014-06-03 05:17:47 +08:00
|
|
|
try:
|
2018-03-15 01:13:22 +08:00
|
|
|
details = self._get_details_dialog(uri, connkey)
|
2011-06-09 04:33:20 +08:00
|
|
|
|
|
|
|
if forcepage or not details.is_visible():
|
|
|
|
if page == DETAILS_PERF:
|
|
|
|
details.activate_performance_page()
|
|
|
|
elif page == DETAILS_CONFIG:
|
|
|
|
details.activate_config_page()
|
|
|
|
elif page == DETAILS_CONSOLE:
|
|
|
|
details.activate_console_page()
|
|
|
|
elif page is None:
|
|
|
|
details.activate_default_page()
|
|
|
|
|
2010-11-24 07:54:12 +08:00
|
|
|
details.show()
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2011-04-06 23:22:03 +08:00
|
|
|
src.err.show_err(_("Error launching details: %s") % str(e))
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2014-06-03 05:17:47 +08:00
|
|
|
def _do_show_vm(self, src, uri, connkey):
|
2018-03-15 01:13:22 +08:00
|
|
|
self._show_vm_helper(src, uri, connkey, None, False)
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2018-03-15 06:43:47 +08:00
|
|
|
def _get_manager(self):
|
2010-11-24 07:54:12 +08:00
|
|
|
if self.windowManager:
|
|
|
|
return self.windowManager
|
|
|
|
|
2018-03-15 06:58:22 +08:00
|
|
|
from .manager import vmmManager
|
2018-03-15 01:13:22 +08:00
|
|
|
obj = vmmManager()
|
2013-09-23 03:13:41 +08:00
|
|
|
obj.connect("action-show-domain", self._do_show_vm)
|
2010-11-24 07:54:12 +08:00
|
|
|
obj.connect("action-show-create", self._do_show_create)
|
|
|
|
obj.connect("action-show-host", self._do_show_host)
|
|
|
|
obj.connect("action-show-connect", self._do_show_connect)
|
2011-04-13 22:47:31 +08:00
|
|
|
obj.connect("manager-opened", self.increment_window_counter)
|
|
|
|
obj.connect("manager-closed", self.decrement_window_counter)
|
2018-03-15 01:13:22 +08:00
|
|
|
obj.connect("remove-conn", self._remove_conn)
|
2011-07-23 01:42:20 +08:00
|
|
|
|
2010-11-24 07:54:12 +08:00
|
|
|
self.windowManager = obj
|
|
|
|
return self.windowManager
|
|
|
|
|
2010-11-24 09:13:50 +08:00
|
|
|
def _do_toggle_manager(self, ignore):
|
2018-03-15 06:43:47 +08:00
|
|
|
manager = self._get_manager()
|
2010-12-14 06:48:19 +08:00
|
|
|
if manager.is_visible():
|
|
|
|
manager.close()
|
|
|
|
else:
|
2010-11-24 07:54:12 +08:00
|
|
|
manager.show()
|
|
|
|
|
2010-11-24 09:13:50 +08:00
|
|
|
def _do_show_manager(self, src):
|
2010-11-24 07:54:12 +08:00
|
|
|
try:
|
2018-03-15 06:43:47 +08:00
|
|
|
manager = self._get_manager()
|
2011-04-13 21:27:02 +08:00
|
|
|
manager.show()
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2010-11-24 09:13:50 +08:00
|
|
|
if not src:
|
|
|
|
raise
|
2011-04-06 23:22:03 +08:00
|
|
|
src.err.show_err(_("Error launching manager: %s") % str(e))
|
2010-11-24 07:54:12 +08:00
|
|
|
|
|
|
|
def _get_create_dialog(self):
|
|
|
|
if self.windowCreate:
|
|
|
|
return self.windowCreate
|
|
|
|
|
2018-03-15 06:58:22 +08:00
|
|
|
from .create import vmmCreate
|
2018-03-15 01:13:22 +08:00
|
|
|
obj = vmmCreate()
|
2013-09-23 03:13:41 +08:00
|
|
|
obj.connect("action-show-domain", self._do_show_vm)
|
2016-05-20 21:27:17 +08:00
|
|
|
obj.connect("create-opened", self.increment_window_counter)
|
|
|
|
obj.connect("create-closed", self.decrement_window_counter)
|
2010-11-24 07:54:12 +08:00
|
|
|
self.windowCreate = obj
|
|
|
|
return self.windowCreate
|
|
|
|
|
2010-11-24 09:13:50 +08:00
|
|
|
def _do_show_create(self, src, uri):
|
2010-11-24 07:54:12 +08:00
|
|
|
try:
|
2011-04-14 20:47:42 +08:00
|
|
|
self._get_create_dialog().show(src.topwin, uri)
|
2017-05-06 00:47:21 +08:00
|
|
|
except Exception as e:
|
2011-04-06 23:22:03 +08:00
|
|
|
src.err.show_err(_("Error launching manager: %s") % str(e))
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2017-02-23 18:22:27 +08:00
|
|
|
|
2010-11-24 09:13:50 +08:00
|
|
|
##########################################
|
|
|
|
# Window launchers from virt-manager cli #
|
|
|
|
##########################################
|
|
|
|
|
2014-06-03 05:17:47 +08:00
|
|
|
def _find_vm_by_cli_str(self, uri, clistr):
|
|
|
|
"""
|
|
|
|
Lookup a VM by a string passed in on the CLI. Can be either
|
|
|
|
ID, domain name, or UUID
|
|
|
|
"""
|
|
|
|
if clistr.isdigit():
|
|
|
|
clistr = int(clistr)
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
for vm in self._connobjs[uri].list_vms():
|
2014-06-03 05:17:47 +08:00
|
|
|
if clistr == vm.get_id():
|
|
|
|
return vm
|
|
|
|
elif clistr == vm.get_name():
|
|
|
|
return vm
|
|
|
|
elif clistr == vm.get_uuid():
|
|
|
|
return vm
|
|
|
|
|
|
|
|
def _cli_show_vm_helper(self, uri, clistr, page):
|
2018-03-15 06:43:47 +08:00
|
|
|
src = self._get_manager()
|
2014-06-03 05:17:47 +08:00
|
|
|
|
|
|
|
vm = self._find_vm_by_cli_str(uri, clistr)
|
|
|
|
if not vm:
|
|
|
|
src.err.show_err("%s does not have VM '%s'" %
|
|
|
|
(uri, clistr), modal=True)
|
|
|
|
return
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
self._show_vm_helper(src, uri, vm.get_connkey(), page, True)
|
2014-06-03 05:17:47 +08:00
|
|
|
|
2015-11-25 04:21:26 +08:00
|
|
|
def _show_manager(self):
|
|
|
|
self._do_show_manager(None)
|
|
|
|
|
|
|
|
def _show_host_summary(self, uri):
|
2018-03-15 06:43:47 +08:00
|
|
|
self._do_show_host(self._get_manager(), uri)
|
2015-11-25 04:21:26 +08:00
|
|
|
|
|
|
|
def _show_domain_creator(self, uri):
|
2018-03-15 06:43:47 +08:00
|
|
|
self._do_show_create(self._get_manager(), uri)
|
2015-11-25 04:21:26 +08:00
|
|
|
|
|
|
|
def _show_domain_console(self, uri, clistr):
|
2015-12-04 04:54:52 +08:00
|
|
|
self._cli_show_vm_helper(uri, clistr, DETAILS_CONSOLE)
|
2014-06-03 05:17:47 +08:00
|
|
|
|
2015-11-25 04:21:26 +08:00
|
|
|
def _show_domain_editor(self, uri, clistr):
|
2015-12-04 04:54:52 +08:00
|
|
|
self._cli_show_vm_helper(uri, clistr, DETAILS_CONFIG)
|
2010-11-24 09:13:50 +08:00
|
|
|
|
2015-11-25 04:21:26 +08:00
|
|
|
def _show_domain_performance(self, uri, clistr):
|
2015-12-04 04:54:52 +08:00
|
|
|
self._cli_show_vm_helper(uri, clistr, DETAILS_PERF)
|
2010-11-24 07:54:12 +08:00
|
|
|
|
2015-11-25 04:21:26 +08:00
|
|
|
def _launch_cli_window(self, uri, show_window, clistr):
|
2015-12-04 04:54:52 +08:00
|
|
|
try:
|
|
|
|
logging.debug("Launching requested window '%s'", show_window)
|
2018-01-10 01:58:38 +08:00
|
|
|
if show_window == self.CLI_SHOW_MANAGER:
|
2018-03-15 06:43:47 +08:00
|
|
|
self._get_manager().set_initial_selection(uri)
|
2018-01-10 01:58:38 +08:00
|
|
|
self._show_manager()
|
|
|
|
elif show_window == self.CLI_SHOW_DOMAIN_CREATOR:
|
2015-12-04 04:54:52 +08:00
|
|
|
self._show_domain_creator(uri)
|
|
|
|
elif show_window == self.CLI_SHOW_DOMAIN_EDITOR:
|
|
|
|
self._show_domain_editor(uri, clistr)
|
|
|
|
elif show_window == self.CLI_SHOW_DOMAIN_PERFORMANCE:
|
|
|
|
self._show_domain_performance(uri, clistr)
|
|
|
|
elif show_window == self.CLI_SHOW_DOMAIN_CONSOLE:
|
|
|
|
self._show_domain_console(uri, clistr)
|
|
|
|
elif show_window == self.CLI_SHOW_HOST_SUMMARY:
|
|
|
|
self._show_host_summary(uri)
|
|
|
|
else:
|
|
|
|
raise RuntimeError("Unknown cli window command '%s'" %
|
|
|
|
show_window)
|
|
|
|
finally:
|
|
|
|
# In case of cli error, we may need to exit the app
|
|
|
|
self._exit_app_if_no_windows()
|
2015-11-25 04:21:26 +08:00
|
|
|
|
|
|
|
def _cli_conn_connected_cb(self, conn, uri, show_window, domain):
|
2015-12-04 04:54:52 +08:00
|
|
|
try:
|
|
|
|
ignore = conn
|
2015-11-25 04:21:26 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
if conn.is_disconnected():
|
|
|
|
raise RuntimeError("failed to connect to cli uri=%s" % uri)
|
2015-11-25 04:21:26 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
if conn.is_active():
|
|
|
|
self._launch_cli_window(uri, show_window, domain)
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2015-12-04 04:54:52 +08:00
|
|
|
# In case of cli error, we may need to exit the app
|
|
|
|
logging.debug("Error in cli connection callback", exc_info=True)
|
|
|
|
self._exit_app_if_no_windows()
|
2015-11-25 04:21:26 +08:00
|
|
|
return True
|
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
def _do_handle_cli_command(self, actionobj, variant):
|
|
|
|
ignore = actionobj
|
|
|
|
uri = variant[0]
|
|
|
|
show_window = variant[1]
|
|
|
|
domain = variant[2]
|
2015-11-25 04:21:26 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
logging.debug("processing cli command uri=%s show_window=%s domain=%s",
|
|
|
|
uri, show_window, domain)
|
2015-11-25 04:21:26 +08:00
|
|
|
if not uri:
|
2015-12-04 04:54:52 +08:00
|
|
|
logging.debug("No cli action requested, launching default window")
|
|
|
|
self._show_manager()
|
2015-11-25 04:21:26 +08:00
|
|
|
return
|
|
|
|
|
2018-03-15 01:13:22 +08:00
|
|
|
conn = self._add_conn(uri, False)
|
2015-12-04 04:54:52 +08:00
|
|
|
|
|
|
|
if conn.is_disconnected():
|
|
|
|
# Schedule connection open
|
2018-03-15 06:43:47 +08:00
|
|
|
self.idle_add(self._connect_to_uri, uri)
|
2015-12-04 04:54:52 +08:00
|
|
|
|
2015-11-25 04:21:26 +08:00
|
|
|
if show_window:
|
|
|
|
if conn.is_active():
|
|
|
|
self.idle_add(self._launch_cli_window,
|
|
|
|
uri, show_window, domain)
|
|
|
|
else:
|
|
|
|
conn.connect_opt_out("state-changed",
|
|
|
|
self._cli_conn_connected_cb, uri, show_window, domain)
|
2015-12-04 04:54:52 +08:00
|
|
|
else:
|
2018-03-15 06:43:47 +08:00
|
|
|
self._get_manager().set_initial_selection(uri)
|
2015-12-04 04:54:52 +08:00
|
|
|
self._show_manager()
|
2015-11-25 04:21:26 +08:00
|
|
|
|
2015-12-04 04:54:52 +08:00
|
|
|
def _handle_cli_command(self, actionobj, variant):
|
|
|
|
try:
|
|
|
|
return self._do_handle_cli_command(actionobj, variant)
|
2017-07-24 16:26:48 +08:00
|
|
|
except Exception:
|
2015-12-04 04:54:52 +08:00
|
|
|
# In case of cli error, we may need to exit the app
|
|
|
|
logging.debug("Error handling cli command", exc_info=True)
|
|
|
|
self._exit_app_if_no_windows()
|