2006-06-28 23:50:17 +04:00
#
2014-06-26 13:51:38 +04:00
# Copyright (C) 2006, 2013-2014 Red Hat, Inc.
2006-06-28 23:50:17 +04: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-20 19:12:20 +03:00
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
2006-06-28 23:50:17 +04:00
#
2007-11-20 19:12:20 +03:00
2006-09-26 02:41:47 +04:00
import logging
2013-07-13 06:10:16 +04:00
import re
2017-10-11 14:35:53 +03:00
import queue
2009-07-12 05:23:16 +04:00
import threading
2014-04-16 18:32:52 +04:00
import traceback
2006-06-14 18:59:40 +04:00
2016-06-07 18:33:21 +03:00
from gi . repository import Gio
from gi . repository import GLib
from gi . repository import Gtk
2014-09-13 00:10:45 +04:00
from . import packageutils
from . baseclass import vmmGObject
2018-03-14 20:13:22 +03:00
from . connmanager import vmmConnectionManager
2014-09-13 00:10:45 +04:00
from . connect import vmmConnect
from . error import vmmErrorDialog
2018-03-13 20:00:59 +03:00
from . inspection import vmmInspection
2006-06-14 18:59:40 +04:00
2011-06-09 00:33:20 +04:00
DETAILS_PERF = 1
DETAILS_CONFIG = 2
DETAILS_CONSOLE = 3
2013-07-07 17:42:21 +04:00
( PRIO_HIGH ,
PRIO_LOW ) = range ( 1 , 3 )
2013-04-13 22:34:52 +04:00
2010-12-09 20:37:48 +03:00
class vmmEngine ( vmmGObject ) :
2018-01-09 20:58:38 +03:00
CLI_SHOW_MANAGER = " manager "
2015-11-24 23:21:26 +03: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 01:43:47 +03:00
@classmethod
def get_instance ( cls ) :
if not cls . _instance :
cls . _instance = cls ( )
return cls . _instance
2018-03-15 14:43:56 +03:00
__gsignals__ = {
" app-closing " : ( vmmGObject . RUN_FIRST , None , [ ] ) ,
}
2010-12-09 20:37:48 +03:00
def __init__ ( self ) :
vmmGObject . __init__ ( self )
2009-11-15 23:17:03 +03:00
2010-11-30 22:33:21 +03:00
self . err = vmmErrorDialog ( )
2006-06-14 18:59:40 +04:00
2018-03-15 12:53:58 +03:00
self . _exiting = False
2015-12-03 23:54:52 +03:00
2018-03-15 12:53:58 +03:00
self . _window_count = 0
2015-12-03 23:54:52 +03:00
self . _gtkapplication = None
self . _init_gtk_application ( )
2009-07-28 06:30:01 +04:00
2018-03-15 12:53:58 +03:00
self . _timer = None
2013-07-07 04:03:42 +04:00
self . _tick_counter = 0
2009-07-12 05:23:16 +04:00
self . _tick_thread_slow = False
2013-07-07 04:03:42 +04:00
self . _tick_thread = threading . Thread ( name = " Tick thread " ,
target = self . _handle_tick_queue ,
args = ( ) )
self . _tick_thread . daemon = True
2017-10-11 14:35:53 +03:00
self . _tick_queue = queue . PriorityQueue ( 100 )
2009-07-12 05:23:16 +04:00
2010-03-04 00:58:50 +03:00
2018-03-14 17:29:20 +03:00
@property
2018-03-14 20:13:22 +03:00
def _connobjs ( self ) :
return vmmConnectionManager . get_instance ( ) . conns
2018-03-14 17:29:20 +03:00
2018-03-15 01:43:47 +03:00
def _cleanup ( self ) :
self . err = None
if self . _timer is not None :
GLib . source_remove ( self . _timer )
#################
# init handling #
#################
2015-12-03 23:54:52 +03:00
2017-10-20 18:46:40 +03:00
def _default_startup ( self , skip_autostart , cliuri ) :
2018-03-15 01:43:47 +03:00
"""
Actual startup routines if we are running a new instance of the app
"""
2018-03-15 12:53:58 +03:00
from . systray import vmmSystray
vmmSystray . get_instance ( )
2018-03-15 01:43:47 +03: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 :
2018-03-15 12:53:58 +03:00
self . _add_conn ( _uri , False , force_init = True )
2018-03-15 01:43:47 +03:00
self . _tick_thread . start ( )
self . _tick ( )
2018-03-08 21:08:17 +03:00
2018-03-15 12:53:58 +03:00
uris = list ( self . _connobjs . keys ( ) )
2015-12-03 23:54:52 +03:00
if not uris :
logging . debug ( " No stored URIs found. " )
2013-05-30 01:43:38 +04:00
else :
2015-12-03 23:54:52 +03:00
logging . debug ( " Loading stored URIs: \n %s " ,
" \n " . join ( sorted ( uris ) ) )
2013-04-16 03:25:54 +04:00
2015-12-03 23:54:52 +03:00
if not skip_autostart :
2018-03-15 01:43:47 +03:00
self . idle_add ( self . _autostart_conns )
2013-04-16 03:25:54 +04:00
2017-10-20 18:46:40 +03:00
if not self . config . get_conn_uris ( ) and not cliuri :
2015-12-03 23:54:52 +03:00
# Only add default if no connections are currently known
self . timeout_add ( 1000 , self . _add_default_conn )
def _add_default_conn ( self ) :
2018-03-15 01:43:47 +03: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-01 22:19:23 +04:00
2010-03-04 00:58:50 +03:00
# Manager fail message
msg = _ ( " Could not detect a default hypervisor. Make \n "
" sure the appropriate virtualization packages \n "
2017-08-14 17:04:43 +03:00
" containing kvm, qemu, libvirt, etc. are \n "
" installed, and that libvirtd is running. \n \n "
2010-03-04 00:58:50 +03:00
" A hypervisor connection can be manually \n "
" added via File->Add Connection " )
logging . debug ( " Determining default libvirt URI " )
2018-03-14 20:13:22 +03:00
packages_verified = False
2010-03-04 00:58:50 +03:00
try :
2011-01-14 23:19:58 +03:00
libvirt_packages = self . config . libvirt_packages
packages = self . config . hv_packages + libvirt_packages
2018-03-14 20:13:22 +03:00
packages_verified = packageutils . check_packagekit (
manager , manager . err , packages )
2017-07-24 11:26:48 +03:00
except Exception :
2010-03-04 00:58:50 +03:00
logging . exception ( " Error talking to PackageKit " )
2017-08-08 00:26:48 +03:00
tryuri = None
2018-03-14 20:13:22 +03:00
if packages_verified :
2012-07-08 23:38:52 +04:00
tryuri = " qemu:///system "
2017-08-08 00:26:48 +03:00
elif not self . config . test_first_run :
2015-04-06 23:43:44 +03:00
tryuri = vmmConnect . default_uri ( )
2010-03-04 00:58:50 +03:00
if tryuri is None :
manager . set_startup_error ( msg )
return
2013-06-24 20:15:28 +04: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 01:35:48 +04: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-14 20:13:22 +03:00
libvirtd_started = packageutils . start_libvirtd ( )
connected = False
try :
2018-03-15 01:43:47 +03:00
self . _connect_to_uri ( tryuri , autoconnect = True )
2018-03-14 20:13:22 +03:00
connected = True
except Exception :
logging . exception ( " Error connecting to %s " , tryuri )
if not connected and not libvirtd_started :
2013-06-14 01:35:48 +04:00
manager . err . ok ( _ ( " Libvirt service must be started " ) , warnmsg )
self . idle_add ( idle_connect )
2010-03-04 00:58:50 +03:00
2018-03-15 01:43:47 +03:00
def _autostart_conns ( self ) :
2014-02-01 19:44:45 +04:00
"""
We serialize conn autostart , so polkit / ssh - askpass doesn ' t spam
"""
2018-03-15 14:43:56 +03:00
if self . _exiting :
return
2017-10-11 14:35:53 +03:00
connections_queue = queue . Queue ( )
2018-03-14 20:13:22 +03:00
auto_conns = [ conn . get_uri ( ) for conn in self . _connobjs . values ( ) if
conn . get_autoconnect ( ) ]
2014-02-01 19:44:45 +04:00
def add_next_to_queue ( ) :
if not auto_conns :
2017-10-11 14:35:53 +03:00
connections_queue . put ( None )
2014-02-01 19:44:45 +04:00
else :
2017-10-11 14:35:53 +03:00
connections_queue . put ( auto_conns . pop ( 0 ) )
2014-02-01 19:44:45 +04:00
def state_change_cb ( conn ) :
2014-09-12 02:16:21 +04:00
if conn . is_active ( ) :
2014-02-01 19:44:45 +04:00
add_next_to_queue ( )
2018-03-15 14:43:56 +03:00
return True
2014-02-01 19:44:45 +04:00
def handle_queue ( ) :
while True :
2017-10-11 14:35:53 +03:00
uri = connections_queue . get ( )
2014-02-01 19:44:45 +04:00
if uri is None :
return
2018-03-15 14:43:56 +03:00
if self . _exiting :
return
2018-03-14 20:13:22 +03:00
if uri not in self . _connobjs :
2014-02-01 19:44:45 +04:00
add_next_to_queue ( )
continue
2018-03-14 20:13:22 +03:00
conn = self . _connobjs [ uri ]
2018-03-15 14:43:56 +03:00
conn . connect_opt_out ( " state-changed " , state_change_cb )
2018-03-15 01:43:47 +03:00
self . idle_add ( self . _connect_to_uri , uri )
2014-02-01 19:44:45 +04:00
add_next_to_queue ( )
2014-09-12 19:28:27 +04:00
self . _start_thread ( handle_queue , " Conn autostart thread " )
2008-03-24 18:39:19 +03:00
2006-06-14 22:36:26 +04:00
2018-03-15 01:43:47 +03:00
############################
# Gtk Application handling #
############################
2011-04-12 02:35:21 +04:00
2018-03-15 01:43:47 +03: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 00:56:49 +04:00
2018-03-15 01:43:47 +03: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-03 23:56:39 +03:00
2018-03-15 01:43:47 +03: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-03 23:56:39 +03:00
2018-03-15 01:43:47 +03: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 " " ) )
2018-03-15 14:43:56 +03:00
is_remote = self . _application . get_is_remote ( )
if not is_remote :
self . _default_startup ( skip_autostart , uri )
2018-03-15 01:43:47 +03:00
self . _application . activate_action ( " cli_command " , data )
2018-03-15 14:43:56 +03:00
if is_remote :
2018-03-15 01:43:47 +03:00
logging . debug ( " Connected to remote app instance. " )
2007-09-27 05:04:02 +04:00
return
2018-03-15 01:43:47 +03:00
self . _application . run ( None )
2011-04-12 02:35:21 +04:00
2018-03-15 01:43:47 +03:00
###########################
# timer and tick handling #
###########################
2007-09-27 05:04:02 +04:00
2018-03-15 01:43:47 +03:00
def _timer_changed_cb ( self , * args , * * kwargs ) :
2016-04-18 23:42:12 +03:00
ignore1 = args
ignore2 = kwargs
2018-03-15 01:43:47 +03:00
self . _schedule_timer ( )
2006-06-14 18:59:40 +04:00
2018-03-15 01:43:47 +03:00
def _schedule_timer ( self ) :
2010-12-09 22:06:00 +03:00
interval = self . config . get_stats_update_interval ( ) * 1000
2006-06-14 18:59:40 +04:00
2018-03-15 01:43:47 +03:00
if self . _timer is not None :
self . remove_gobject_timeout ( self . _timer )
self . _timer = None
2006-06-14 18:59:40 +04:00
2018-03-15 01:43:47 +03:00
self . _timer = self . timeout_add ( interval , self . _tick )
2006-06-14 18:59:40 +04:00
2013-07-07 19:06:15 +04:00
def _add_obj_to_tick_queue ( self , obj , isprio , * * kwargs ) :
2013-07-07 04:03:42 +04:00
if self . _tick_queue . full ( ) :
2009-07-14 17:45:23 +04:00
if not self . _tick_thread_slow :
2009-07-12 05:23:16 +04:00
logging . debug ( " Tick is slow, not running at requested rate. " )
2009-10-01 20:04:03 +04:00
self . _tick_thread_slow = True
2013-07-07 04:03:42 +04:00
return
2009-07-12 05:23:16 +04:00
2013-07-07 04:03:42 +04:00
self . _tick_counter + = 1
2013-07-07 17:42:21 +04:00
self . _tick_queue . put ( ( isprio and PRIO_HIGH or PRIO_LOW ,
2013-07-07 19:06:15 +04:00
self . _tick_counter ,
obj , kwargs ) )
2007-03-10 00:22:43 +03:00
2013-07-07 19:06:15 +04:00
def _schedule_priority_tick ( self , conn , kwargs ) :
self . _add_obj_to_tick_queue ( conn , True , * * kwargs )
2013-07-07 04:03:42 +04:00
2018-03-15 01:43:47 +03:00
def _tick ( self ) :
2018-03-14 20:13:22 +03:00
for conn in self . _connobjs . values ( ) :
2013-07-07 19:06:15 +04:00
self . _add_obj_to_tick_queue ( conn , False ,
stats_update = True , pollvm = True )
2013-07-07 04:03:42 +04:00
return 1
2011-07-25 21:31:36 +04:00
2015-04-11 21:41:02 +03:00
def _handle_tick_error ( self , msg , details ) :
2018-03-15 12:53:58 +03:00
from . systray import vmmSystray
if ( self . _window_count == 1 and
vmmSystray . get_instance ( ) . is_visible ( ) ) :
2015-04-11 21:41:02 +03:00
# 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 04:03:42 +04:00
def _handle_tick_queue ( self ) :
while True :
2014-04-16 18:32:52 +04:00
ignore1 , ignore2 , conn , kwargs = self . _tick_queue . get ( )
try :
2015-04-13 23:56:46 +03:00
conn . tick_from_engine ( * * kwargs )
2017-05-05 19:47:21 +03:00
except Exception as e :
2014-04-16 18:32:52 +04:00
tb = " " . join ( traceback . format_exc ( ) )
error_msg = ( _ ( " Error polling connection ' %s ' : %s " )
% ( conn . get_uri ( ) , e ) )
2015-04-11 21:41:02 +03:00
self . idle_add ( self . _handle_tick_error , error_msg , tb )
2014-04-16 18:32:52 +04:00
2015-09-20 21:20:50 +03:00
# Need to clear reference to make leak check happy
conn = None
2013-07-07 04:03:42 +04:00
self . _tick_queue . task_done ( )
2006-06-14 18:59:40 +04:00
return 1
2013-07-07 04:03:42 +04:00
2018-03-15 01:43:47 +03:00
#####################################
# window counting and exit handling #
#####################################
2018-03-15 02:06:30 +03:00
def increment_window_counter ( self ) :
"""
Public function , called by toplevel windows
"""
2018-03-15 12:53:58 +03:00
self . _window_count + = 1
logging . debug ( " window counter incremented to %s " , self . _window_count )
2008-06-13 20:12:37 +04:00
2018-03-15 02:06:30 +03:00
def decrement_window_counter ( self ) :
"""
Public function , called by toplevel windows
"""
2018-03-15 12:53:58 +03:00
self . _window_count - = 1
logging . debug ( " window counter decremented to %s " , self . _window_count )
2011-04-13 17:27:02 +04:00
2018-03-15 02:06:30 +03:00
self . _exit_app_if_no_windows ( )
2008-06-13 20:12:37 +04:00
2013-07-13 06:10:16 +04:00
def _can_exit ( self ) :
2018-03-15 12:53:58 +03:00
return self . _window_count < = 0
2013-07-13 06:10:16 +04:00
2018-03-15 02:06:30 +03:00
def _exit_app_if_no_windows ( self ) :
2018-03-15 12:53:58 +03:00
if self . _can_exit ( ) :
logging . debug ( " No windows found, requesting app exit " )
self . exit_app ( )
2015-12-03 23:54:52 +03:00
2018-03-15 01:58:22 +03:00
def exit_app ( self ) :
"""
Public call , manager / details / . . . use this to force exit the app
"""
2018-03-15 12:53:58 +03:00
if self . _exiting :
2011-04-13 17:27:02 +04:00
return
2018-03-15 14:43:56 +03:00
self . _exiting = True
2011-04-14 19:26:53 +04:00
2018-03-15 14:43:56 +03:00
def _do_exit ( ) :
try :
vmmConnectionManager . get_instance ( ) . cleanup ( )
self . emit ( " app-closing " )
self . cleanup ( )
2011-04-11 20:54:47 +04:00
2018-03-15 14:43:56 +03:00
if self . config . test_leak_debug :
objs = self . config . get_objects ( )
# Engine will always appear to leak
objs . remove ( self . object_key )
2008-06-13 20:12:37 +04:00
2018-03-15 14:43:56 +03:00
for name in objs :
logging . debug ( " LEAK: %s " , name )
2015-04-11 21:34:38 +03:00
2018-03-15 14:43:56 +03:00
logging . debug ( " Exiting app normally. " )
finally :
self . _application . quit ( )
2012-11-08 14:02:17 +04:00
2018-03-15 14:43:56 +03:00
# We stick this in an idle callback, so the exit_app() caller
# reference is dropped, and leak check debug doesn't give a
# false positive
self . idle_add ( _do_exit )
2010-11-24 02:54:12 +03:00
2018-03-15 12:53:58 +03:00
def _add_conn ( self , uri , probe , force_init = False ) :
is_init = ( uri not in self . _connobjs )
2018-03-14 20:13:22 +03:00
conn = vmmConnectionManager . get_instance ( ) . add_conn ( uri )
2018-03-15 12:53:58 +03:00
if is_init or force_init :
conn . connect ( " connect-error " , self . _connect_error )
conn . connect ( " priority-tick " , self . _schedule_priority_tick )
setattr ( conn , " _from_connect_wizard " , probe )
2009-07-14 22:48:09 +04:00
return conn
2018-03-15 01:43:47 +03:00
def _connect_to_uri ( self , uri , autoconnect = None , probe = False ) :
conn = self . _add_conn ( uri , probe = probe )
2018-03-14 20:13:22 +03:00
2018-03-15 01:43:47 +03:00
if autoconnect is not None :
conn . set_autoconnect ( bool ( autoconnect ) )
2011-04-13 17:27:02 +04:00
2018-03-15 01:43:47 +03:00
conn . open ( )
2011-04-13 17:27:02 +04:00
2013-07-13 06:10:16 +04: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 18:13:20 +04:00
logging . debug ( " connect_error: conn transport= %s " ,
2015-04-11 19:08:57 +03:00
conn . get_uri_transport ( ) )
2013-07-13 06:10:16 +04:00
if re . search ( r " nc: .* -- ' U ' " , tb ) :
2017-08-08 01:16:45 +03:00
hint + = _ ( " The remote host requires a version of netcat/nc "
2013-07-13 06:10:16 +04:00
" which supports the -U option. " )
show_errmsg = False
2015-04-11 19:08:57 +03:00
elif ( conn . get_uri_transport ( ) == " ssh " and
2013-07-13 06:10:16 +04:00
re . search ( r " ssh-askpass " , tb ) ) :
2017-08-08 00:41:52 +03: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 01:16:45 +03:00
" similar to connect to this host. " ) % askpass
2013-07-13 06:10:16 +04:00
show_errmsg = False
else :
2017-08-08 01:16:45 +03:00
hint + = _ ( " Verify that the ' libvirtd ' daemon is running "
2013-07-13 06:10:16 +04: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 01:16:45 +03: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 06:10:16 +04: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
2017-10-20 18:46:40 +03:00
msg = _ ( " Unable to connect to libvirt %s . " % conn . get_uri ( ) )
2013-07-13 06:10:16 +04: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 12:53:58 +03:00
_from_connect_wizard = getattr ( conn , " _from_connect_wizard " , False )
if _from_connect_wizard :
2015-04-05 02:40:22 +03:00
msg + = " \n \n "
msg + = _ ( " Would you still like to remember this connection? " )
2013-08-08 16:11:18 +04:00
title = _ ( " Virtual Machine Manager Connection Failure " )
2018-03-15 12:53:58 +03:00
if _from_connect_wizard :
2013-08-08 16:11:18 +04:00
remember_connection = self . err . show_err ( msg , details , title ,
buttons = Gtk . ButtonsType . YES_NO ,
2013-09-07 04:16:37 +04:00
dialog_type = Gtk . MessageType . QUESTION , modal = True )
2013-08-08 16:11:18 +04:00
if remember_connection :
2018-03-15 12:53:58 +03:00
setattr ( conn , " _from_connect_wizard " , False )
2013-08-08 16:11:18 +04:00
else :
2018-03-15 12:53:58 +03:00
self . _edit_connect ( conn . get_uri ( ) )
2013-07-13 06:10:16 +04:00
else :
2013-08-08 16:11:18 +04:00
if self . _can_exit ( ) :
2013-09-07 04:16:37 +04:00
self . err . show_err ( msg , details , title , modal = True )
2018-03-15 12:53:58 +03:00
self . _exit_app_if_no_windows ( )
2013-08-08 16:11:18 +04:00
else :
self . err . show_err ( msg , details , title )
2013-07-13 06:10:16 +04:00
2015-04-05 02:40:22 +03:00
2018-03-15 01:43:47 +03:00
##################################
# callbacks and dialog launchers #
##################################
2018-03-15 12:53:58 +03:00
def _connect_completed ( self , _src , uri , autoconnect ) :
self . _connect_to_uri ( uri , autoconnect , probe = True )
2010-11-24 02:54:12 +03:00
2018-03-15 12:53:58 +03:00
def _connect_cancelled ( self , _src ) :
if not self . _connobjs :
self . exit_app ( )
2010-11-24 02:54:12 +03:00
2018-03-15 12:53:58 +03:00
def _show_connect_dialog ( self , src , reset_state ) :
is_init = vmmConnect . is_initialized ( )
obj = vmmConnect . get_instance ( src )
if not is_init :
obj . connect ( " completed " , self . _connect_completed )
obj . connect ( " cancelled " , self . _connect_cancelled )
obj . show ( src . topwin , reset_state )
2010-11-24 02:54:12 +03:00
2018-03-15 12:53:58 +03:00
def do_show_connect ( self , src , reset_state = True ) :
2010-11-24 02:54:12 +03:00
try :
2018-03-15 12:53:58 +03:00
self . _show_connect_dialog ( src , reset_state )
2017-05-05 19:47:21 +03:00
except Exception as e :
2011-04-06 19:22:03 +04:00
src . err . show_err ( _ ( " Error launching connect dialog: %s " ) % str ( e ) )
2010-11-24 02:54:12 +03:00
2018-03-15 12:53:58 +03:00
def _edit_connect ( self , uri ) :
vmmConnectionManager . get_instance ( ) . remove_conn ( uri )
self . do_show_connect ( self . _get_manager ( ) , reset_state = False )
2010-11-24 02:54:12 +03:00
2017-02-23 13:22:27 +03:00
2010-11-24 04:13:50 +03:00
##########################################
# Window launchers from virt-manager cli #
##########################################
2014-06-03 01:17:47 +04: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-14 20:13:22 +03:00
for vm in self . _connobjs [ uri ] . list_vms ( ) :
2014-06-03 01:17:47 +04: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 01:43:47 +03:00
src = self . _get_manager ( )
2014-06-03 01:17:47 +04: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 12:53:58 +03:00
try :
from . details import vmmDetails
details = vmmDetails . get_instance ( src , vm )
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 ( )
2014-06-03 01:17:47 +04:00
2018-03-15 14:43:56 +03:00
details . show ( default_page = False )
2018-03-15 12:53:58 +03:00
except Exception as e :
src . err . show_err ( _ ( " Error launching details: %s " ) % str ( e ) )
def _get_manager ( self ) :
from . manager import vmmManager
return vmmManager . get_instance ( self )
def _show_manager_uri ( self , uri ) :
manager = self . _get_manager ( )
manager . set_initial_selection ( uri )
manager . show ( )
2015-11-24 23:21:26 +03:00
def _show_host_summary ( self , uri ) :
2018-03-15 12:53:58 +03:00
from . host import vmmHost
vmmHost . show_instance ( self . _get_manager ( ) , self . _connobjs [ uri ] )
2015-11-24 23:21:26 +03:00
def _show_domain_creator ( self , uri ) :
2018-03-15 12:53:58 +03:00
from . create import vmmCreate
vmmCreate . show_instance ( self . _get_manager ( ) , uri )
2015-11-24 23:21:26 +03:00
def _show_domain_console ( self , uri , clistr ) :
2015-12-03 23:54:52 +03:00
self . _cli_show_vm_helper ( uri , clistr , DETAILS_CONSOLE )
2014-06-03 01:17:47 +04:00
2015-11-24 23:21:26 +03:00
def _show_domain_editor ( self , uri , clistr ) :
2015-12-03 23:54:52 +03:00
self . _cli_show_vm_helper ( uri , clistr , DETAILS_CONFIG )
2010-11-24 04:13:50 +03:00
2015-11-24 23:21:26 +03:00
def _show_domain_performance ( self , uri , clistr ) :
2015-12-03 23:54:52 +03:00
self . _cli_show_vm_helper ( uri , clistr , DETAILS_PERF )
2010-11-24 02:54:12 +03:00
2015-11-24 23:21:26 +03:00
def _launch_cli_window ( self , uri , show_window , clistr ) :
2015-12-03 23:54:52 +03:00
try :
logging . debug ( " Launching requested window ' %s ' " , show_window )
2018-01-09 20:58:38 +03:00
if show_window == self . CLI_SHOW_MANAGER :
2018-03-15 12:53:58 +03:00
self . _show_manager_uri ( uri )
2018-01-09 20:58:38 +03:00
elif show_window == self . CLI_SHOW_DOMAIN_CREATOR :
2015-12-03 23:54:52 +03: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-24 23:21:26 +03:00
def _cli_conn_connected_cb ( self , conn , uri , show_window , domain ) :
2015-12-03 23:54:52 +03:00
try :
ignore = conn
2015-11-24 23:21:26 +03:00
2015-12-03 23:54:52 +03:00
if conn . is_disconnected ( ) :
raise RuntimeError ( " failed to connect to cli uri= %s " % uri )
2015-11-24 23:21:26 +03:00
2015-12-03 23:54:52 +03:00
if conn . is_active ( ) :
self . _launch_cli_window ( uri , show_window , domain )
return True
return False
2017-07-24 11:26:48 +03:00
except Exception :
2015-12-03 23:54:52 +03: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-24 23:21:26 +03:00
return True
2015-12-03 23:54:52 +03:00
def _do_handle_cli_command ( self , actionobj , variant ) :
ignore = actionobj
uri = variant [ 0 ]
show_window = variant [ 1 ]
domain = variant [ 2 ]
2015-11-24 23:21:26 +03:00
2015-12-03 23:54:52 +03:00
logging . debug ( " processing cli command uri= %s show_window= %s domain= %s " ,
uri , show_window , domain )
2015-11-24 23:21:26 +03:00
if not uri :
2015-12-03 23:54:52 +03:00
logging . debug ( " No cli action requested, launching default window " )
2018-03-15 12:53:58 +03:00
self . _get_manager ( ) . show ( )
2015-11-24 23:21:26 +03:00
return
2018-03-14 20:13:22 +03:00
conn = self . _add_conn ( uri , False )
2015-12-03 23:54:52 +03:00
if conn . is_disconnected ( ) :
# Schedule connection open
2018-03-15 01:43:47 +03:00
self . idle_add ( self . _connect_to_uri , uri )
2015-12-03 23:54:52 +03:00
2015-11-24 23:21:26 +03: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-03 23:54:52 +03:00
else :
2018-03-15 12:53:58 +03:00
self . _show_manager_uri ( uri )
2015-11-24 23:21:26 +03:00
2015-12-03 23:54:52 +03:00
def _handle_cli_command ( self , actionobj , variant ) :
try :
return self . _do_handle_cli_command ( actionobj , variant )
2017-07-24 11:26:48 +03:00
except Exception :
2015-12-03 23:54:52 +03: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 ( )