2006-06-28 23:50:17 +04:00
#
# Copyright (C) 2006 Red Hat, Inc.
# 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
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
2006-06-14 18:59:40 +04:00
import gobject
2006-06-14 22:36:26 +04:00
import gtk
2006-06-15 00:20:06 +04:00
import sys
2006-07-17 21:08:58 +04:00
import libvirt
2006-09-26 02:41:47 +04:00
import logging
2007-03-08 22:07:00 +03:00
import gnome
2007-03-22 18:11:05 +03:00
import traceback
2006-06-14 18:59:40 +04:00
from virtManager . about import vmmAbout
from virtManager . connect import vmmConnect
from virtManager . connection import vmmConnection
from virtManager . preferences import vmmPreferences
2006-06-15 00:20:06 +04:00
from virtManager . manager import vmmManager
from virtManager . details import vmmDetails
from virtManager . console import vmmConsole
2006-07-24 21:50:11 +04:00
from virtManager . asyncjob import vmmAsyncJob
2006-08-09 01:02:15 +04:00
from virtManager . create import vmmCreate
2006-08-11 00:47:14 +04:00
from virtManager . serialcon import vmmSerialConsole
2007-03-23 03:59:10 +03:00
from virtManager . error import vmmErrorDialog
2007-03-28 03:52:00 +04:00
from virtManager . host import vmmHost
2006-06-14 18:59:40 +04:00
class vmmEngine :
def __init__ ( self , config ) :
2006-06-15 00:20:06 +04:00
self . windowConnect = None
2006-06-14 18:59:40 +04:00
self . windowPreferences = None
self . windowAbout = None
2006-08-09 01:02:15 +04:00
self . windowCreate = None
2007-08-10 00:19:41 +04:00
self . windowManager = None
2006-06-14 18:59:40 +04:00
self . connections = { }
self . timer = None
self . last_timeout = 0
self . config = config
self . config . on_stats_update_interval_changed ( self . reschedule_timer )
self . schedule_timer ( )
self . tick ( )
2006-06-15 00:20:06 +04:00
def _do_connection_disconnected ( self , connection , hvuri ) :
2006-06-27 22:16:13 +04:00
del self . connections [ hvuri ]
2007-08-15 00:28:36 +04:00
if len ( self . connections . keys ( ) ) == 0 and self . windowConnect == None \
and self . windowManager == None :
2006-06-14 22:36:26 +04:00
gtk . main_quit ( )
2007-08-10 00:19:41 +04:00
if self . windowManager is not None :
2007-08-15 00:28:36 +04:00
self . windowManager . disconnect_connection ( hvuri )
2007-08-10 00:19:41 +04:00
def connect_to_uri ( self , uri , readOnly = None ) :
self . _connect_to_uri ( None , uri , readOnly )
2006-06-14 22:36:26 +04:00
def _connect_to_uri ( self , connect , uri , readOnly ) :
2006-06-27 22:16:13 +04:00
self . windowConnect = None
2006-06-27 18:08:55 +04:00
try :
2006-06-14 22:36:26 +04:00
conn = self . get_connection ( uri , readOnly )
2007-08-10 00:19:41 +04:00
self . show_manager ( )
2006-06-27 18:08:55 +04:00
except :
2007-03-23 03:59:10 +03:00
( type , value , stacktrace ) = sys . exc_info ( )
2006-10-03 18:54:49 +04:00
2007-03-23 03:59:10 +03:00
# Detailed error message, in English so it can be Googled.
details = \
( " Unable to open connection to hypervisor URI ' %s ' : \n " %
str ( uri ) ) + \
str ( type ) + " " + str ( value ) + " \n " + \
traceback . format_exc ( stacktrace )
logging . error ( details )
# Error dialog.
2006-10-03 18:54:49 +04:00
if uri is None :
uri = " xen "
if uri == " xen " :
2007-03-23 03:59:10 +03:00
dg = vmmErrorDialog ( None , 0 , gtk . MESSAGE_ERROR ,
gtk . BUTTONS_CLOSE ,
_ ( " Unable to open a connection to the Xen hypervisor/daemon. \n \n " +
" Verify that: \n " +
" - A Xen host kernel was booted \n " +
" - The Xen service has been started \n " ) ,
details )
2007-07-04 08:48:32 +04:00
elif uri . startswith ( " qemu: " ) :
dg = vmmErrorDialog ( None , 0 , gtk . MESSAGE_ERROR ,
gtk . BUTTONS_CLOSE ,
_ ( " Unable to open a connection to the QEMU management daemon. \n \n " +
" Verify that: \n " +
" - The ' libvirt_qemud ' daemon has been started \n " ) ,
details )
2006-10-03 18:54:49 +04:00
else :
2007-03-23 03:59:10 +03:00
dg = vmmErrorDialog ( None , 0 , gtk . MESSAGE_ERROR ,
gtk . BUTTONS_CLOSE ,
_ ( " Unable to open connection to hypervisor ' %s ' " ) % str ( uri ) ,
details )
2006-10-03 18:54:49 +04:00
dg . set_title ( _ ( " Virtual Machine Manager Connection Failure " ) )
dg . run ( )
dg . hide ( )
dg . destroy ( )
2006-06-27 18:08:55 +04:00
if len ( self . connections . keys ( ) ) == 0 :
gtk . main_quit ( )
2006-06-14 22:36:26 +04:00
2006-07-20 19:38:32 +04:00
def _connect_cancelled ( self , connect ) :
2006-06-27 22:16:13 +04:00
self . windowConnect = None
2006-06-27 18:08:55 +04:00
if len ( self . connections . keys ( ) ) == 0 :
2006-06-14 22:36:26 +04:00
gtk . main_quit ( )
2006-06-15 00:56:49 +04:00
def _do_vm_removed ( self , connection , hvuri , vmuuid ) :
if self . connections [ hvuri ] [ " windowDetails " ] . has_key ( vmuuid ) :
2006-07-13 21:35:40 +04:00
self . connections [ hvuri ] [ " windowDetails " ] [ vmuuid ] . close ( )
2006-06-15 00:56:49 +04:00
del self . connections [ hvuri ] [ " windowDetails " ] [ vmuuid ]
if self . connections [ hvuri ] [ " windowConsole " ] . has_key ( vmuuid ) :
2006-07-13 21:35:40 +04:00
self . connections [ hvuri ] [ " windowConsole " ] [ vmuuid ] . close ( )
2006-06-15 00:56:49 +04:00
del self . connections [ hvuri ] [ " windowConsole " ] [ vmuuid ]
2006-08-18 22:27:49 +04:00
if self . connections [ hvuri ] [ " windowSerialConsole " ] . has_key ( vmuuid ) :
self . connections [ hvuri ] [ " windowSerialConsole " ] [ vmuuid ] . close ( )
del self . connections [ hvuri ] [ " windowSerialConsole " ] [ vmuuid ]
2006-06-15 00:56:49 +04:00
2006-06-14 18:59:40 +04:00
def reschedule_timer ( self , ignore1 , ignore2 , ignore3 , ignore4 ) :
self . schedule_timer ( )
def schedule_timer ( self ) :
interval = self . get_config ( ) . get_stats_update_interval ( ) * 1000
if self . timer != None :
gobject . source_remove ( self . timer )
self . timer = None
self . timer = gobject . timeout_add ( interval , self . tick )
def tick ( self ) :
2007-03-10 00:22:43 +03:00
gtk . gdk . threads_enter ( )
try :
2007-03-13 18:48:19 +03:00
return self . _tick ( )
2007-03-10 00:22:43 +03:00
finally :
gtk . gdk . threads_leave ( )
def _tick ( self ) :
2006-11-03 18:02:02 +03:00
if self . windowConnect == None and gtk . main_level ( ) > 0 and self . count_visible_windows ( ) == 0 :
gtk . main_quit ( )
2006-06-14 18:59:40 +04:00
for uri in self . connections . keys ( ) :
try :
2006-06-15 00:20:06 +04:00
self . connections [ uri ] [ " connection " ] . tick ( )
2006-07-11 23:36:54 +04:00
except KeyboardInterrupt :
raise KeyboardInterrupt
2006-06-14 18:59:40 +04:00
except :
2007-03-23 03:59:10 +03:00
logging . error ( ( " Could not refresh connection %s \n " % ( uri ) ) + str ( sys . exc_info ( ) [ 0 ] ) + \
2007-03-22 18:11:05 +03:00
" " + str ( sys . exc_info ( ) [ 1 ] ) + " \n " + \
traceback . format_exc ( sys . exc_info ( ) [ 2 ] ) )
2006-06-14 18:59:40 +04:00
return 1
2006-11-03 18:02:02 +03:00
def count_visible_windows ( self ) :
ct = 0
for conn in self . connections . values ( ) :
2007-08-15 01:11:44 +04:00
for winname in [ " windowDetails " , " windowConsole " , " windowSerialConsole " ] :
for window in conn [ winname ] . values ( ) :
2006-11-03 18:02:02 +03:00
ct + = window . is_visible ( )
2007-08-15 01:11:44 +04:00
if conn [ " windowHost " ] != None and conn [ " windowHost " ] . is_visible ( ) :
ct + = 1
2006-11-03 18:02:02 +03:00
if self . windowCreate :
ct + = self . windowCreate . is_visible ( )
2007-08-10 00:19:41 +04:00
if self . windowManager :
ct + = self . windowManager . is_visible ( )
2006-11-03 18:02:02 +03:00
return ct
2006-06-14 18:59:40 +04:00
def change_timer_interval ( self , ignore1 , ignore2 , ignore3 , ignore4 ) :
gobject . source_remove ( self . timer )
self . schedule_timer ( )
def get_config ( self ) :
return self . config
2006-06-15 00:20:06 +04:00
def _do_show_about ( self , src ) :
self . show_about ( )
def _do_show_preferences ( self , src ) :
self . show_preferences ( )
2007-03-28 03:52:00 +04:00
def _do_show_host ( self , src , uri ) :
self . show_host ( uri )
2006-06-15 00:20:06 +04:00
def _do_show_connect ( self , src ) :
self . show_connect ( )
2007-08-15 00:28:36 +04:00
def _do_connect ( self , src , uri ) :
self . connect_to_uri ( uri )
2006-06-15 00:20:06 +04:00
def _do_show_details ( self , src , uri , uuid ) :
self . show_details ( uri , uuid )
2007-08-14 01:13:39 +04:00
def _do_show_create ( self , src , uri ) :
self . show_create ( uri )
2007-03-08 22:07:00 +03:00
def _do_show_help ( self , src , index ) :
self . show_help ( index )
2006-06-15 00:20:06 +04:00
def _do_show_console ( self , src , uri , uuid ) :
self . show_console ( uri , uuid )
2006-08-11 00:47:14 +04:00
def _do_show_terminal ( self , src , uri , uuid ) :
self . show_serial_console ( uri , uuid )
2006-07-17 21:08:58 +04:00
def _do_save_domain ( self , src , uri , uuid ) :
2006-07-19 02:14:44 +04:00
self . save_domain ( src , uri , uuid )
2006-11-15 20:27:36 +03:00
def _do_destroy_domain ( self , src , uri , uuid ) :
self . destroy_domain ( src , uri , uuid )
2006-06-15 00:20:06 +04:00
2006-06-14 18:59:40 +04:00
def show_about ( self ) :
if self . windowAbout == None :
self . windowAbout = vmmAbout ( self . get_config ( ) )
self . windowAbout . show ( )
2007-03-08 22:07:00 +03:00
def show_help ( self , index ) :
try :
gnome . help_display ( self . config . get_appname ( ) , index )
except gobject . GError , e :
2007-03-16 23:27:50 +03:00
logging . error ( ( " Unable to display documentation: \n %s " ) % e )
2007-03-08 22:07:00 +03:00
2006-06-14 18:59:40 +04:00
def show_preferences ( self ) :
if self . windowPreferences == None :
self . windowPreferences = vmmPreferences ( self . get_config ( ) )
2007-03-20 01:12:40 +03:00
self . windowPreferences . connect ( " action-show-help " , self . _do_show_help )
2006-06-14 18:59:40 +04:00
self . windowPreferences . show ( )
2007-03-28 03:52:00 +04:00
def show_host ( self , uri ) :
con = self . get_connection ( uri )
if self . connections [ uri ] [ " windowHost " ] == None :
manager = vmmHost ( self . get_config ( ) , con )
manager . connect ( " action-show-help " , self . _do_show_help )
self . connections [ uri ] [ " windowHost " ] = manager
self . connections [ uri ] [ " windowHost " ] . show ( )
2006-06-15 00:20:06 +04:00
def show_connect ( self ) :
if self . windowConnect == None :
self . windowConnect = vmmConnect ( self . get_config ( ) , self )
self . windowConnect . connect ( " completed " , self . _connect_to_uri )
2006-06-27 19:17:46 +04:00
self . windowConnect . connect ( " cancelled " , self . _connect_cancelled )
2006-06-15 00:20:06 +04:00
self . windowConnect . show ( )
2006-06-14 18:59:40 +04:00
def show_console ( self , uri , uuid ) :
con = self . get_connection ( uri )
2006-06-15 00:20:06 +04:00
if not ( self . connections [ uri ] [ " windowConsole " ] . has_key ( uuid ) ) :
console = vmmConsole ( self . get_config ( ) ,
2006-06-15 01:52:49 +04:00
con . get_vm ( uuid ) )
2006-06-15 00:20:06 +04:00
console . connect ( " action-show-details " , self . _do_show_details )
2006-08-11 00:47:14 +04:00
console . connect ( " action-show-terminal " , self . _do_show_terminal )
2006-07-20 21:38:37 +04:00
console . connect ( " action-save-domain " , self . _do_save_domain )
2006-11-15 20:27:36 +03:00
console . connect ( " action-destroy-domain " , self . _do_destroy_domain )
2007-03-20 00:19:46 +03:00
console . connect ( " action-show-help " , self . _do_show_help )
2006-06-15 00:20:06 +04:00
self . connections [ uri ] [ " windowConsole " ] [ uuid ] = console
self . connections [ uri ] [ " windowConsole " ] [ uuid ] . show ( )
2006-06-14 18:59:40 +04:00
2006-08-11 00:47:14 +04:00
def show_serial_console ( self , uri , uuid ) :
con = self . get_connection ( uri )
if not ( self . connections [ uri ] [ " windowSerialConsole " ] . has_key ( uuid ) ) :
console = vmmSerialConsole ( self . get_config ( ) ,
con . get_vm ( uuid ) )
self . connections [ uri ] [ " windowSerialConsole " ] [ uuid ] = console
self . connections [ uri ] [ " windowSerialConsole " ] [ uuid ] . show ( )
2006-07-14 01:44:49 +04:00
def show_details_performance ( self , uri , uuid ) :
win = self . show_details ( uri , uuid )
win . activate_performance_page ( )
def show_details_config ( self , uri , uuid ) :
win = self . show_details ( uri , uuid )
win . activate_config_page ( )
2007-03-28 03:52:00 +04:00
2006-06-14 18:59:40 +04:00
def show_details ( self , uri , uuid ) :
con = self . get_connection ( uri )
2006-06-15 00:20:06 +04:00
if not ( self . connections [ uri ] [ " windowDetails " ] . has_key ( uuid ) ) :
details = vmmDetails ( self . get_config ( ) ,
2006-06-15 01:52:49 +04:00
con . get_vm ( uuid ) )
2006-06-15 00:20:06 +04:00
details . connect ( " action-show-console " , self . _do_show_console )
2006-08-11 00:47:14 +04:00
details . connect ( " action-show-terminal " , self . _do_show_terminal )
2006-07-17 21:08:58 +04:00
details . connect ( " action-save-domain " , self . _do_save_domain )
2006-11-15 20:27:36 +03:00
details . connect ( " action-destroy-domain " , self . _do_destroy_domain )
2007-03-16 23:27:50 +03:00
details . connect ( " action-show-help " , self . _do_show_help )
2006-06-15 00:20:06 +04:00
self . connections [ uri ] [ " windowDetails " ] [ uuid ] = details
self . connections [ uri ] [ " windowDetails " ] [ uuid ] . show ( )
2006-07-14 01:44:49 +04:00
return self . connections [ uri ] [ " windowDetails " ] [ uuid ]
2006-06-14 18:59:40 +04:00
2007-08-10 00:19:41 +04:00
def get_manager ( self ) :
if self . windowManager == None :
self . windowManager = vmmManager ( self . get_config ( ) )
self . windowManager . connect ( " action-show-console " , self . _do_show_console )
self . windowManager . connect ( " action-show-terminal " , self . _do_show_terminal )
self . windowManager . connect ( " action-show-details " , self . _do_show_details )
self . windowManager . connect ( " action-show-preferences " , self . _do_show_preferences )
self . windowManager . connect ( " action-show-create " , self . _do_show_create )
self . windowManager . connect ( " action-show-help " , self . _do_show_help )
self . windowManager . connect ( " action-show-about " , self . _do_show_about )
self . windowManager . connect ( " action-show-host " , self . _do_show_host )
self . windowManager . connect ( " action-show-connect " , self . _do_show_connect )
2007-08-15 00:28:36 +04:00
self . windowManager . connect ( " action-connect " , self . _do_connect )
2007-08-10 00:19:41 +04:00
return self . windowManager
def show_manager ( self ) :
self . get_manager ( ) . show ( )
2007-08-14 01:13:39 +04:00
def show_create ( self , uri ) :
2006-08-09 01:02:15 +04:00
if self . windowCreate == None :
2007-08-14 01:13:39 +04:00
self . windowCreate = vmmCreate ( self . get_config ( ) , self . get_connection ( uri , False ) )
self . windowCreate . connect ( " action-show-console " , self . _do_show_console )
self . windowCreate . connect ( " action-show-terminal " , self . _do_show_terminal )
self . windowCreate . connect ( " action-show-help " , self . _do_show_help )
self . windowCreate . reset_state ( )
else :
self . windowCreate . connection = self . get_connection ( uri , False )
2006-08-10 02:53:30 +04:00
self . windowCreate . reset_state ( )
2006-08-09 01:02:15 +04:00
self . windowCreate . show ( )
2007-04-13 03:43:31 +04:00
def get_connection ( self , uri , readOnly = None ) :
2006-06-27 22:16:13 +04:00
if not ( self . connections . has_key ( uri ) ) :
2007-04-13 03:43:31 +04:00
conn = vmmConnection ( self . get_config ( ) , uri , readOnly )
2006-06-27 22:16:13 +04:00
self . connections [ uri ] = {
2007-04-13 03:43:31 +04:00
" connection " : conn ,
2007-03-28 03:52:00 +04:00
" windowHost " : None ,
2006-06-15 00:20:06 +04:00
" windowDetails " : { } ,
2006-08-11 00:47:14 +04:00
" windowConsole " : { } ,
" windowSerialConsole " : { } ,
2006-06-15 00:20:06 +04:00
}
2006-06-27 22:16:13 +04:00
self . connections [ uri ] [ " connection " ] . connect ( " disconnected " , self . _do_connection_disconnected )
self . connections [ uri ] [ " connection " ] . connect ( " vm-removed " , self . _do_vm_removed )
2007-08-10 00:19:41 +04:00
self . get_manager ( ) . add_connection ( self . connections [ uri ] [ " connection " ] )
2006-06-27 22:16:13 +04:00
self . connections [ uri ] [ " connection " ] . tick ( )
2006-06-15 00:20:06 +04:00
2006-06-27 22:16:13 +04:00
return self . connections [ uri ] [ " connection " ]
2006-07-17 21:08:58 +04:00
2006-07-19 02:14:44 +04:00
def save_domain ( self , src , uri , uuid ) :
2006-07-17 21:08:58 +04:00
con = self . get_connection ( uri , False )
vm = con . get_vm ( uuid )
status = vm . status ( )
2006-07-19 18:54:39 +04:00
if status in [ libvirt . VIR_DOMAIN_SHUTDOWN ,
libvirt . VIR_DOMAIN_SHUTOFF ,
libvirt . VIR_DOMAIN_CRASHED ,
libvirt . VIR_DOMAIN_PAUSED ] :
2006-09-26 02:22:27 +04:00
logging . warning ( " Save requested, but machine is shutdown / shutoff / paused " )
2006-07-17 21:08:58 +04:00
else :
2006-08-04 23:46:06 +04:00
self . fcdialog = gtk . FileChooserDialog ( _ ( " Save Virtual Machine " ) ,
src . window . get_widget ( " vmm-details " ) ,
gtk . FILE_CHOOSER_ACTION_SAVE ,
( gtk . STOCK_CANCEL , gtk . RESPONSE_CANCEL ,
gtk . STOCK_SAVE , gtk . RESPONSE_ACCEPT ) ,
None )
2007-04-12 19:46:51 +04:00
self . fcdialog . set_current_folder ( self . config . get_default_save_dir ( con ) )
2006-07-19 02:14:44 +04:00
self . fcdialog . set_do_overwrite_confirmation ( True )
response = self . fcdialog . run ( )
self . fcdialog . hide ( )
2006-07-18 03:37:24 +04:00
if ( response == gtk . RESPONSE_ACCEPT ) :
2006-07-20 19:16:07 +04:00
file_to_save = self . fcdialog . get_filename ( )
2006-07-24 21:50:11 +04:00
progWin = vmmAsyncJob ( self . config , vm . save ,
2006-08-04 23:46:06 +04:00
[ file_to_save ] ,
_ ( " Saving Virtual Machine " ) )
2006-07-20 19:16:07 +04:00
progWin . run ( )
self . fcdialog . destroy ( )
2006-11-15 20:27:36 +03:00
def destroy_domain ( self , src , uri , uuid ) :
con = self . get_connection ( uri , False )
vm = con . get_vm ( uuid )
status = vm . status ( )
if status in [ libvirt . VIR_DOMAIN_SHUTDOWN ,
libvirt . VIR_DOMAIN_SHUTOFF ] :
logging . warning ( " Destroy requested, but machine is shutdown / shutoff " )
else :
message_box = gtk . MessageDialog ( None , \
gtk . DIALOG_MODAL , \
gtk . MESSAGE_WARNING , \
gtk . BUTTONS_OK_CANCEL , \
_ ( " About to destroy virtual machine %s " % vm . get_name ( ) ) )
message_box . format_secondary_text ( _ ( " This will immediately destroy the VM and may corrupt its disk image. Are you sure? " ) )
response_id = message_box . run ( )
message_box . destroy ( )
if response_id == gtk . RESPONSE_OK :
vm . destroy ( )
else :
return