2014-01-20 20:09:13 +04:00
# Copyright (C) 2009, 2013, 2014 Red Hat, Inc.
2009-11-20 19:39:22 +03:00
# Copyright (C) 2009 Cole Robinson <crobinso@redhat.com>
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2009-11-20 19:39:22 +03:00
2012-05-14 17:24:56 +04:00
from gi . repository import Gtk
2009-11-20 19:39:22 +03:00
2019-06-17 04:12:39 +03:00
from virtinst import log
2018-03-08 21:42:45 +03:00
from . asyncjob import vmmAsyncJob
2014-01-27 02:42:24 +04:00
2009-12-01 00:21:04 +03:00
####################################################################
# Build toolbar shutdown button menu (manager and details toolbar) #
####################################################################
2013-09-22 23:13:41 +04:00
class _VMMenu ( Gtk . Menu ) :
2013-09-22 23:44:58 +04:00
def __init__ ( self , src , current_vm_cb , show_open = True ) :
2013-09-22 21:24:59 +04:00
Gtk . Menu . __init__ ( self )
self . _parent = src
self . _current_vm_cb = current_vm_cb
2013-09-22 23:44:58 +04:00
self . _show_open = show_open
2013-09-22 21:24:59 +04:00
self . _init_state ( )
2018-03-08 21:42:45 +03:00
def _add_action ( self , label , widgetname , cb ,
iconname = " system-shutdown " ) :
2013-09-22 23:13:41 +04:00
if label . startswith ( " gtk- " ) :
item = Gtk . ImageMenuItem . new_from_stock ( label , None )
else :
2013-09-22 21:24:59 +04:00
item = Gtk . ImageMenuItem . new_with_mnemonic ( label )
2013-09-22 23:13:41 +04:00
if iconname :
if iconname . startswith ( " gtk- " ) :
icon = Gtk . Image . new_from_stock ( iconname , Gtk . IconSize . MENU )
else :
icon = Gtk . Image . new_from_icon_name ( iconname ,
Gtk . IconSize . MENU )
item . set_image ( icon )
2013-09-22 21:24:59 +04:00
2018-03-08 21:42:45 +03:00
item . vmm_widget_name = widgetname
if cb :
def _cb ( _menuitem ) :
_vm = self . _current_vm_cb ( )
if _vm :
return cb ( self . _parent , _vm )
item . connect ( " activate " , _cb )
2013-09-22 23:13:41 +04:00
self . add ( item )
return item
2013-09-22 21:24:59 +04:00
2013-09-22 23:13:41 +04:00
def _init_state ( self ) :
raise NotImplementedError ( )
def update_widget_states ( self , vm ) :
raise NotImplementedError ( )
class VMShutdownMenu ( _VMMenu ) :
2018-03-08 21:42:45 +03:00
"""
Shutdown submenu for reboot , forceoff , reset , etc .
"""
2013-09-22 23:13:41 +04:00
def _init_state ( self ) :
2018-03-08 21:42:45 +03:00
self . _add_action ( _ ( " _Reboot " ) , " reboot " , VMActionUI . reboot )
self . _add_action ( _ ( " _Shut Down " ) , " shutdown " , VMActionUI . shutdown )
self . _add_action ( _ ( " F_orce Reset " ) , " reset " , VMActionUI . reset )
self . _add_action ( _ ( " _Force Off " ) , " destroy " , VMActionUI . destroy )
2013-09-22 23:13:41 +04:00
self . add ( Gtk . SeparatorMenuItem ( ) )
2018-03-08 21:42:45 +03:00
self . _add_action ( _ ( " Sa_ve " ) , " save " , VMActionUI . save ,
iconname = Gtk . STOCK_SAVE )
2013-09-22 23:13:41 +04:00
2020-08-26 20:13:36 +03:00
self . get_accessible ( ) . set_name ( " vmm-shutdown-menu " )
2013-09-22 23:13:41 +04:00
self . show_all ( )
2013-09-22 21:24:59 +04:00
def update_widget_states ( self , vm ) :
statemap = {
" reboot " : bool ( vm and vm . is_stoppable ( ) ) ,
" shutdown " : bool ( vm and vm . is_stoppable ( ) ) ,
" reset " : bool ( vm and vm . is_stoppable ( ) ) ,
" destroy " : bool ( vm and vm . is_destroyable ( ) ) ,
2018-03-08 21:42:45 +03:00
" save " : bool ( vm and vm . is_destroyable ( ) ) ,
2013-09-22 21:24:59 +04:00
}
for child in self . get_children ( ) :
name = getattr ( child , " vmm_widget_name " , None )
if name in statemap :
child . set_sensitive ( statemap [ name ] )
2010-05-12 19:42:59 +04:00
2013-07-09 17:20:43 +04:00
2013-09-22 23:13:41 +04:00
class VMActionMenu ( _VMMenu ) :
2018-03-08 21:42:45 +03:00
"""
VM submenu for run , pause , shutdown , clone , etc
"""
2013-09-22 23:13:41 +04:00
def _init_state ( self ) :
2018-03-08 21:42:45 +03:00
self . _add_action ( _ ( " _Run " ) , " run " , VMActionUI . run ,
iconname = Gtk . STOCK_MEDIA_PLAY )
self . _add_action ( _ ( " _Pause " ) , " suspend " , VMActionUI . suspend ,
Gtk . STOCK_MEDIA_PAUSE )
self . _add_action ( _ ( " R_esume " ) , " resume " , VMActionUI . resume ,
Gtk . STOCK_MEDIA_PAUSE )
s = self . _add_action ( _ ( " _Shut Down " ) , " shutdown " , None )
2013-09-22 23:13:41 +04:00
s . set_submenu ( VMShutdownMenu ( self . _parent , self . _current_vm_cb ) )
self . add ( Gtk . SeparatorMenuItem ( ) )
2018-03-08 21:42:45 +03:00
self . _add_action ( _ ( " Clone... " ) , " clone " ,
2018-03-15 01:17:03 +03:00
VMActionUI . clone , iconname = None )
2018-03-08 21:42:45 +03:00
self . _add_action ( _ ( " Migrate... " ) , " migrate " ,
2018-03-15 00:50:22 +03:00
VMActionUI . migrate , iconname = None )
2018-03-08 21:42:45 +03:00
self . _add_action ( _ ( " _Delete " ) , " delete " ,
2018-03-15 00:48:17 +03:00
VMActionUI . delete , iconname = Gtk . STOCK_DELETE )
2013-09-22 23:13:41 +04:00
2013-09-22 23:44:58 +04:00
if self . _show_open :
self . add ( Gtk . SeparatorMenuItem ( ) )
2018-03-08 21:42:45 +03:00
self . _add_action ( Gtk . STOCK_OPEN , " show " ,
2018-03-15 12:53:58 +03:00
VMActionUI . show , iconname = None )
2013-09-22 23:13:41 +04:00
2020-08-26 20:13:36 +03:00
self . get_accessible ( ) . set_name ( " vm-action-menu " )
2013-09-22 23:13:41 +04:00
self . show_all ( )
def update_widget_states ( self , vm ) :
statemap = {
" run " : bool ( vm and vm . is_runable ( ) ) ,
" shutdown " : bool ( vm and vm . is_stoppable ( ) ) ,
" suspend " : bool ( vm and vm . is_stoppable ( ) ) ,
" resume " : bool ( vm and vm . is_paused ( ) ) ,
" migrate " : bool ( vm and vm . is_stoppable ( ) ) ,
2020-09-04 22:18:26 +03:00
" clone " : bool ( vm and vm . is_cloneable ( ) ) ,
2013-09-22 23:13:41 +04:00
}
vismap = {
" suspend " : bool ( vm and not vm . is_paused ( ) ) ,
" resume " : bool ( vm and vm . is_paused ( ) ) ,
}
for child in self . get_children ( ) :
name = getattr ( child , " vmm_widget_name " , None )
2015-04-11 21:14:24 +03:00
if child . get_submenu ( ) :
child . get_submenu ( ) . update_widget_states ( vm )
2013-09-22 23:13:41 +04:00
if name in statemap :
child . set_sensitive ( statemap [ name ] )
if name in vismap :
child . set_visible ( vismap [ name ] )
def change_run_text ( self , text ) :
for child in self . get_children ( ) :
if getattr ( child , " vmm_widget_name " , None ) == " run " :
child . get_child ( ) . set_label ( text )
2018-03-08 21:42:45 +03:00
class VMActionUI ( object ) :
"""
Singleton object for handling VM actions , asking for confirmation ,
showing errors / progress dialogs , etc .
"""
@staticmethod
def save_cancel ( asyncjob , vm ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Cancelling save job " )
2018-03-08 21:42:45 +03:00
if not vm :
2020-08-26 20:13:36 +03:00
return # pragma: no cover
2018-03-08 21:42:45 +03:00
try :
vm . abort_job ( )
except Exception as e :
2019-06-17 04:12:39 +03:00
log . exception ( " Error cancelling save job " )
2018-03-08 21:42:45 +03:00
asyncjob . show_warning ( _ ( " Error cancelling save job: %s " ) % str ( e ) )
return
2020-08-26 20:13:36 +03:00
asyncjob . job_canceled = True # pragma: no cover
2018-03-08 21:42:45 +03:00
@staticmethod
def save ( src , vm ) :
if not src . err . chkbox_helper ( src . config . get_confirm_poweroff ,
src . config . set_confirm_poweroff ,
text1 = _ ( " Are you sure you want to save ' %s ' ? " ) % vm . get_name ( ) ) :
return
_cancel_cb = None
2020-08-26 19:05:54 +03:00
if vm . supports_domain_job_info ( ) :
2018-03-08 21:42:45 +03:00
_cancel_cb = ( VMActionUI . save_cancel , vm )
def cb ( asyncjob ) :
vm . save ( meter = asyncjob . get_meter ( ) )
def finish_cb ( error , details ) :
2020-08-26 20:13:36 +03:00
if error is not None : # pragma: no cover
2018-03-08 21:42:45 +03:00
error = _ ( " Error saving domain: %s " ) % error
src . err . show_err ( error , details = details )
progWin = vmmAsyncJob ( cb , [ ] ,
finish_cb , [ ] ,
_ ( " Saving Virtual Machine " ) ,
_ ( " Saving virtual machine memory to disk " ) ,
src . topwin , cancel_cb = _cancel_cb )
progWin . run ( )
@staticmethod
def destroy ( src , vm ) :
if not src . err . chkbox_helper (
src . config . get_confirm_forcepoweroff ,
src . config . set_confirm_forcepoweroff ,
text1 = _ ( " Are you sure you want to force poweroff ' %s ' ? " %
vm . get_name ( ) ) ,
text2 = _ ( " This will immediately poweroff the VM without "
" shutting down the OS and may cause data loss. " ) ) :
return
2019-06-17 04:12:39 +03:00
log . debug ( " Destroying vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
vmmAsyncJob . simple_async_noshow ( vm . destroy , [ ] , src ,
_ ( " Error shutting down domain " ) )
@staticmethod
def suspend ( src , vm ) :
if not src . err . chkbox_helper ( src . config . get_confirm_pause ,
src . config . set_confirm_pause ,
text1 = _ ( " Are you sure you want to pause ' %s ' ? " %
vm . get_name ( ) ) ) :
return
2019-06-17 04:12:39 +03:00
log . debug ( " Pausing vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
vmmAsyncJob . simple_async_noshow ( vm . suspend , [ ] , src ,
_ ( " Error pausing domain " ) )
@staticmethod
def resume ( src , vm ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Unpausing vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
vmmAsyncJob . simple_async_noshow ( vm . resume , [ ] , src ,
_ ( " Error unpausing domain " ) )
@staticmethod
def run ( src , vm ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Starting vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
if vm . has_managed_save ( ) :
def errorcb ( error , details ) :
# This is run from the main thread
res = src . err . show_err (
2020-07-14 10:41:49 +03:00
_ ( " Error restoring domain: %s " ) % error ,
2018-03-08 21:42:45 +03:00
details = details ,
text2 = _ (
" The domain could not be restored. Would you like \n "
" to remove the saved state and perform a regular \n "
" start up? " ) ,
dialog_type = Gtk . MessageType . WARNING ,
buttons = Gtk . ButtonsType . YES_NO ,
modal = True )
if not res :
return
try :
vm . remove_saved_image ( )
VMActionUI . run ( src , vm )
2020-08-26 20:13:36 +03:00
except Exception as e : # pragma: no cover
2018-03-08 21:42:45 +03:00
src . err . show_err ( _ ( " Error removing domain state: %s " )
% str ( e ) )
# VM will be restored, which can take some time, so show progress
title = _ ( " Restoring Virtual Machine " )
text = _ ( " Restoring virtual machine memory from disk " )
vmmAsyncJob . simple_async ( vm . startup , [ ] , src ,
title , text , " " , errorcb = errorcb )
else :
# Regular startup
errorintro = _ ( " Error starting domain " )
vmmAsyncJob . simple_async_noshow ( vm . startup , [ ] , src , errorintro )
@staticmethod
def shutdown ( src , vm ) :
if not src . err . chkbox_helper ( src . config . get_confirm_poweroff ,
src . config . set_confirm_poweroff ,
text1 = _ ( " Are you sure you want to poweroff ' %s ' ? " %
vm . get_name ( ) ) ) :
return
2019-06-17 04:12:39 +03:00
log . debug ( " Shutting down vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
vmmAsyncJob . simple_async_noshow ( vm . shutdown , [ ] , src ,
_ ( " Error shutting down domain " ) )
@staticmethod
def reboot ( src , vm ) :
if not src . err . chkbox_helper ( src . config . get_confirm_poweroff ,
src . config . set_confirm_poweroff ,
text1 = _ ( " Are you sure you want to reboot ' %s ' ? " %
vm . get_name ( ) ) ) :
return
2019-06-17 04:12:39 +03:00
log . debug ( " Rebooting vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
vmmAsyncJob . simple_async_noshow ( vm . reboot , [ ] , src ,
_ ( " Error rebooting domain " ) )
@staticmethod
def reset ( src , vm ) :
if not src . err . chkbox_helper (
src . config . get_confirm_forcepoweroff ,
src . config . set_confirm_forcepoweroff ,
text1 = _ ( " Are you sure you want to force reset ' %s ' ? " %
vm . get_name ( ) ) ,
text2 = _ ( " This will immediately reset the VM without "
" shutting down the OS and may cause data loss. " ) ) :
return
2019-06-17 04:12:39 +03:00
log . debug ( " Resetting vm ' %s ' " , vm . get_name ( ) )
2018-03-08 21:42:45 +03:00
vmmAsyncJob . simple_async_noshow ( vm . reset , [ ] , src ,
_ ( " Error resetting domain " ) )
2018-03-15 00:48:17 +03:00
@staticmethod
def delete ( src , vm ) :
from . delete import vmmDeleteDialog
vmmDeleteDialog . show_instance ( src , vm )
2018-03-15 00:50:22 +03:00
@staticmethod
def migrate ( src , vm ) :
from . migrate import vmmMigrateDialog
vmmMigrateDialog . show_instance ( src , vm )
2018-03-15 01:17:03 +03:00
@staticmethod
def clone ( src , vm ) :
from . clone import vmmCloneVM
vmmCloneVM . show_instance ( src , vm )
2018-03-15 12:53:58 +03:00
@staticmethod
def show ( src , vm ) :
2019-05-05 23:25:35 +03:00
from . vmwindow import vmmVMWindow
vmmVMWindow . get_instance ( src , vm ) . show ( )