2006-08-09 19:40:34 +04:00
#
2009-03-09 23:16:45 +03:00
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2008 Cole Robinson <crobinso@redhat.com>
2006-08-09 19:40:34 +04:00
#
# 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-08-09 19:40:34 +04:00
#
import gobject
import gtk
import gtk . glade
2009-03-09 23:16:45 +03:00
import os , sys , statvfs
import time
2007-04-11 02:50:04 +04:00
import traceback
2009-03-09 23:16:45 +03:00
import threading
import logging
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
import virtinst
from virtinst import VirtualNetworkInterface
2009-07-02 20:43:08 +04:00
import virtManager . opticalhelper
2009-03-09 23:16:45 +03:00
from virtManager import util
2007-04-11 02:50:04 +04:00
from virtManager . error import vmmErrorDialog
2009-03-09 23:16:45 +03:00
from virtManager . asyncjob import vmmAsyncJob
2007-04-23 23:26:46 +04:00
from virtManager . createmeter import vmmCreateMeter
2009-03-09 23:19:39 +03:00
from virtManager . storagebrowse import vmmStorageBrowser
2006-08-17 00:00:28 +04:00
2009-03-09 23:16:45 +03:00
OS_GENERIC = " generic "
2006-08-10 23:42:06 +04:00
2009-03-09 23:16:45 +03:00
# Number of seconds to wait for media detection
DETECT_TIMEOUT = 20
2006-08-10 02:53:30 +04:00
2009-03-09 23:16:45 +03:00
PAGE_NAME = 0
PAGE_INSTALL = 1
PAGE_MEM = 2
PAGE_STORAGE = 3
PAGE_FINISH = 4
2008-02-23 23:26:26 +03:00
2009-03-09 23:16:45 +03:00
INSTALL_PAGE_ISO = 0
INSTALL_PAGE_URL = 1
INSTALL_PAGE_PXE = 2
2007-03-21 19:28:36 +03:00
2006-08-09 19:40:34 +04:00
class vmmCreate ( gobject . GObject ) :
2006-08-17 01:25:32 +04:00
__gsignals__ = {
" action-show-console " : ( gobject . SIGNAL_RUN_FIRST ,
2006-08-18 23:32:59 +04:00
gobject . TYPE_NONE , ( str , str ) ) ,
" action-show-terminal " : ( gobject . SIGNAL_RUN_FIRST ,
2009-03-09 23:16:45 +03:00
gobject . TYPE_NONE , ( str , str ) ) ,
2007-03-20 03:17:30 +03:00
" action-show-help " : ( gobject . SIGNAL_RUN_FIRST ,
2009-03-09 23:16:45 +03:00
gobject . TYPE_NONE , [ str ] ) ,
}
def __init__ ( self , config , engine ) :
2006-08-09 19:40:34 +04:00
self . __gobject_init__ ( )
2009-03-09 23:16:45 +03:00
self . window = gtk . glade . XML ( config . get_glade_dir ( ) + \
" /vmm-create.glade " ,
" vmm-create " , domain = " virt-manager " )
2006-08-09 19:40:34 +04:00
self . config = config
2009-03-09 23:16:45 +03:00
self . engine = engine
self . conn = None
self . caps = None
self . capsguest = None
self . capsdomain = None
self . guest = None
self . usepool = False
self . storage_browser = None
2006-08-10 02:53:30 +04:00
self . topwin = self . window . get_widget ( " vmm-create " )
2008-03-14 20:18:44 +03:00
self . err = vmmErrorDialog ( self . topwin ,
0 , gtk . MESSAGE_ERROR , gtk . BUTTONS_CLOSE ,
_ ( " Unexpected Error " ) ,
_ ( " An unexpected error occurred " ) )
2008-11-19 01:01:22 +03:00
2009-03-09 23:16:45 +03:00
# Distro detection state variables
self . detectThread = None
self . detectedDistro = None
self . detectThreadLock = threading . Lock ( )
2009-07-07 00:49:47 +04:00
# 'Guest' class from the previous failed install
self . failed_guest = None
2009-03-09 23:16:45 +03:00
2009-09-22 00:09:51 +04:00
# Host space polling
self . host_storage_timer = None
self . host_storage = None
2006-08-10 02:53:30 +04:00
self . window . signal_autoconnect ( {
2009-03-09 23:16:45 +03:00
" on_vmm_newcreate_delete_event " : self . close ,
" on_create_cancel_clicked " : self . close ,
2006-08-10 02:53:30 +04:00
" on_create_back_clicked " : self . back ,
" on_create_forward_clicked " : self . forward ,
" on_create_finish_clicked " : self . finish ,
2007-03-20 03:17:30 +03:00
" on_create_help_clicked " : self . show_help ,
2009-03-09 23:16:45 +03:00
" on_create_pages_switch_page " : self . page_changed ,
2006-10-25 23:02:57 +04:00
2009-03-09 23:16:45 +03:00
" on_create_conn_changed " : self . conn_changed ,
" on_install_url_box_changed " : self . url_box_changed ,
" on_install_local_cdrom_toggled " : self . local_cdrom_toggled ,
" on_install_local_cdrom_combo_changed " : self . detect_media_os ,
2009-05-11 19:00:03 +04:00
" on_install_local_box_changed " : self . detect_media_os ,
2009-03-09 23:16:45 +03:00
" on_install_local_browse_clicked " : self . browse_iso ,
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
" on_install_detect_os_toggled " : self . toggle_detect_os ,
" on_install_os_type_changed " : self . change_os_type ,
" on_install_local_iso_toggled " : self . toggle_local_iso ,
" on_install_detect_os_box_show " : self . detect_visibility_changed ,
" on_install_detect_os_box_hide " : self . detect_visibility_changed ,
2007-06-22 21:32:13 +04:00
2009-03-09 23:16:45 +03:00
" on_enable_storage_toggled " : self . toggle_enable_storage ,
" on_config_storage_browse_clicked " : self . browse_storage ,
" on_config_storage_select_toggled " : self . toggle_storage_select ,
" on_config_set_macaddr_toggled " : self . toggle_macaddr ,
" on_config_hv_changed " : self . hv_changed ,
" on_config_arch_changed " : self . arch_changed ,
} )
self . set_initial_state ( )
def show ( self , uri = None ) :
self . reset_state ( uri )
2006-08-10 02:53:30 +04:00
self . topwin . show ( )
2006-09-13 01:49:29 +04:00
self . topwin . present ( )
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
def close ( self , ignore1 = None , ignore2 = None ) :
self . topwin . hide ( )
2009-09-22 00:09:51 +04:00
self . remove_timers ( )
2009-03-09 23:16:45 +03:00
return 1
2009-09-22 00:09:51 +04:00
def remove_timers ( self ) :
try :
if self . host_storage_timer :
2009-10-06 02:22:50 +04:00
gobject . source_remove ( self . host_storage_timer )
2009-09-22 00:09:51 +04:00
self . host_storage_timer = None
except :
pass
2009-03-09 23:16:45 +03:00
def set_conn ( self , newconn ) :
if self . conn == newconn :
return
self . conn = newconn
if self . conn :
self . set_conn_state ( )
# State init methods
def startup_error ( self , error ) :
2009-09-29 22:00:50 +04:00
self . window . get_widget ( " startup-error " ) . show ( )
self . window . get_widget ( " install-box " ) . hide ( )
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " create-forward " ) . set_sensitive ( False )
2009-09-29 22:00:50 +04:00
self . window . get_widget ( " startup-error " ) . set_text ( " Error: %s " % error )
2009-03-09 23:16:45 +03:00
return False
2006-08-09 19:40:34 +04:00
def set_initial_state ( self ) :
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " create-pages " ) . set_show_tabs ( False )
self . window . get_widget ( " install-method-pages " ) . set_show_tabs ( False )
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
# FIXME: Unhide this when we make some documentation
self . window . get_widget ( " create-help " ) . hide ( )
2006-08-24 01:12:16 +04:00
2009-03-09 23:16:45 +03:00
blue = gtk . gdk . color_parse ( " #0072A8 " )
self . window . get_widget ( " create-header " ) . modify_bg ( gtk . STATE_NORMAL ,
blue )
2007-04-12 19:46:51 +04:00
2009-03-09 23:58:55 +03:00
box = self . window . get_widget ( " create-vm-icon-box " )
2009-07-26 23:47:46 +04:00
image = gtk . image_new_from_icon_name ( " vm_new_wizard " ,
gtk . ICON_SIZE_DIALOG )
2009-03-09 23:58:55 +03:00
image . show ( )
box . pack_end ( image , False )
2009-03-09 23:16:45 +03:00
# Connection list
2009-09-29 22:00:50 +04:00
self . window . get_widget ( " create-conn-label " ) . set_text ( " " )
self . window . get_widget ( " startup-error " ) . set_text ( " " )
2009-03-09 23:16:45 +03:00
conn_list = self . window . get_widget ( " create-conn " )
conn_model = gtk . ListStore ( str , str )
conn_list . set_model ( conn_model )
text = gtk . CellRendererText ( )
conn_list . pack_start ( text , True )
conn_list . add_attribute ( text , ' text ' , 1 )
2009-05-11 19:00:03 +04:00
# ISO media list
iso_list = self . window . get_widget ( " install-local-box " )
iso_model = gtk . ListStore ( str )
iso_list . set_model ( iso_model )
iso_list . set_text_column ( 0 )
self . window . get_widget ( " install-local-box " ) . child . connect ( " activate " , self . detect_media_os )
2009-03-09 23:16:45 +03:00
# Lists for the install urls
media_url_list = self . window . get_widget ( " install-url-box " )
2006-10-11 17:07:45 +04:00
media_url_model = gtk . ListStore ( str )
media_url_list . set_model ( media_url_model )
2006-10-11 17:58:06 +04:00
media_url_list . set_text_column ( 0 )
2009-05-11 18:17:52 +04:00
self . window . get_widget ( " install-url-box " ) . child . connect ( " activate " , self . detect_media_os )
2006-10-11 17:07:45 +04:00
2009-03-09 23:16:45 +03:00
ks_url_list = self . window . get_widget ( " install-ks-box " )
2006-10-11 17:07:45 +04:00
ks_url_model = gtk . ListStore ( str )
ks_url_list . set_model ( ks_url_model )
2006-10-11 17:58:06 +04:00
ks_url_list . set_text_column ( 0 )
2006-10-11 17:07:45 +04:00
2009-03-09 23:16:45 +03:00
# Lists for distro type + variant
os_type_list = self . window . get_widget ( " install-os-type " )
2007-04-15 21:41:12 +04:00
os_type_model = gtk . ListStore ( str , str )
2007-02-19 19:52:37 +03:00
os_type_list . set_model ( os_type_model )
text = gtk . CellRendererText ( )
os_type_list . pack_start ( text , True )
2007-04-15 21:41:12 +04:00
os_type_list . add_attribute ( text , ' text ' , 1 )
2007-02-19 19:52:37 +03:00
2009-03-09 23:16:45 +03:00
os_variant_list = self . window . get_widget ( " install-os-version " )
2007-04-15 21:41:12 +04:00
os_variant_model = gtk . ListStore ( str , str )
2007-02-19 19:52:37 +03:00
os_variant_list . set_model ( os_variant_model )
text = gtk . CellRendererText ( )
os_variant_list . pack_start ( text , True )
2007-04-15 21:41:12 +04:00
os_variant_list . add_attribute ( text , ' text ' , 1 )
2007-02-19 19:52:37 +03:00
2009-03-09 23:16:45 +03:00
# Physical CD-ROM model
cd_list = self . window . get_widget ( " install-local-cdrom-combo " )
cd_radio = self . window . get_widget ( " install-local-cdrom " )
2009-07-02 20:43:08 +04:00
2009-03-09 23:16:45 +03:00
# FIXME: We should disable all this if on a remote connection
try :
2009-07-02 20:43:08 +04:00
virtManager . opticalhelper . init_optical_combo ( cd_list )
2009-03-09 23:16:45 +03:00
except Exception , e :
logging . error ( " Unable to create optical-helper widget: ' %s ' " , e )
cd_radio . set_sensitive ( False )
cd_list . set_sensitive ( False )
util . tooltip_wrapper ( self . window . get_widget ( " install-local-cdrom-box " ) , _ ( " Error listing CD-ROM devices. " ) )
# Networking
# [ interface type, device name, label, sensitive ]
net_list = self . window . get_widget ( " config-netdev " )
net_model = gtk . ListStore ( str , str , str , bool )
net_list . set_model ( net_model )
text = gtk . CellRendererText ( )
net_list . pack_start ( text , True )
net_list . add_attribute ( text , ' text ' , 2 )
net_list . add_attribute ( text , ' sensitive ' , 3 )
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
# Archtecture
2008-03-10 01:18:33 +03:00
archModel = gtk . ListStore ( str )
2009-03-09 23:16:45 +03:00
archList = self . window . get_widget ( " config-arch " )
text = gtk . CellRendererText ( )
archList . pack_start ( text , True )
archList . add_attribute ( text , ' text ' , 0 )
2008-03-10 01:18:33 +03:00
archList . set_model ( archModel )
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
hyperModel = gtk . ListStore ( str , str , str , bool )
hyperList = self . window . get_widget ( " config-hv " )
text = gtk . CellRendererText ( )
hyperList . pack_start ( text , True )
hyperList . add_attribute ( text , ' text ' , 0 )
hyperList . add_attribute ( text , ' sensitive ' , 3 )
2008-03-10 01:18:33 +03:00
hyperList . set_model ( hyperModel )
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
sparse_info = self . window . get_widget ( " config-storage-nosparse-info " )
sparse_str = _ ( " Fully allocating storage will take longer now, "
" but the OS install phase will be quicker. \n \n "
" Skipping allocation can also cause space issues on "
" the host machine, if the maximum image size exceeds "
" available storage space. " )
util . tooltip_wrapper ( sparse_info , sparse_str )
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
def reset_state ( self , urihint = None ) :
2008-03-10 01:18:33 +03:00
2009-07-07 00:49:47 +04:00
self . failed_guest = None
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " create-pages " ) . set_current_page ( PAGE_NAME )
self . page_changed ( None , None , PAGE_NAME )
2009-09-29 22:00:50 +04:00
self . window . get_widget ( " startup-error " ) . hide ( )
self . window . get_widget ( " install-box " ) . show ( )
2006-11-06 19:36:55 +03:00
2009-03-09 23:16:45 +03:00
# Name page state
2006-09-13 01:49:29 +04:00
self . window . get_widget ( " create-vm-name " ) . set_text ( " " )
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " method-local " ) . set_active ( True )
self . window . get_widget ( " create-conn " ) . set_active ( - 1 )
activeconn = self . populate_conn_list ( urihint )
self . set_conn ( activeconn )
if not activeconn :
return self . startup_error ( _ ( " No active connection to install on. " ) )
# Everything from this point forward should be connection independent
# Distro/Variant
self . toggle_detect_os ( self . window . get_widget ( " install-detect-os " ) )
2007-04-15 21:41:12 +04:00
self . populate_os_type_model ( )
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " install-os-type " ) . set_active ( 0 )
2007-04-23 23:08:56 +04:00
2009-03-09 23:16:45 +03:00
# Install local/iso
2009-05-11 19:00:03 +04:00
self . window . get_widget ( " install-local-box " ) . child . set_text ( " " )
iso_model = self . window . get_widget ( " install-local-box " ) . get_model ( )
self . populate_media_model ( iso_model , self . conn . config_get_iso_paths ( ) )
2007-07-10 05:13:56 +04:00
2009-03-09 23:16:45 +03:00
# Install URL
self . window . get_widget ( " install-urlopts-entry " ) . set_text ( " " )
2009-05-11 18:17:52 +04:00
self . window . get_widget ( " install-ks-box " ) . child . set_text ( " " )
self . window . get_widget ( " install-url-box " ) . child . set_text ( " " )
2009-03-09 23:16:45 +03:00
urlmodel = self . window . get_widget ( " install-url-box " ) . get_model ( )
ksmodel = self . window . get_widget ( " install-ks-box " ) . get_model ( )
2009-05-11 19:00:03 +04:00
self . populate_media_model ( urlmodel , self . config . get_media_urls ( ) )
self . populate_media_model ( ksmodel , self . config . get_kickstart_urls ( ) )
2007-07-14 22:43:52 +04:00
2009-03-09 23:16:45 +03:00
# Mem / CPUs
self . window . get_widget ( " config-mem " ) . set_value ( 512 )
self . window . get_widget ( " config-cpus " ) . set_value ( 1 )
2007-04-15 21:41:12 +04:00
2009-03-09 23:16:45 +03:00
# Storage
2009-09-22 00:09:51 +04:00
if not self . host_storage_timer :
self . host_storage_timer = gobject . timeout_add ( 3 * 1000 ,
self . host_space_tick )
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " enable-storage " ) . set_active ( True )
self . window . get_widget ( " config-storage-create " ) . set_active ( True )
self . window . get_widget ( " config-storage-size " ) . set_value ( 8 )
self . window . get_widget ( " config-storage-entry " ) . set_text ( " " )
self . window . get_widget ( " config-storage-nosparse " ) . set_active ( True )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
# Final page
self . window . get_widget ( " config-advanced-expander " ) . set_expanded ( False )
def set_conn_state ( self ) :
# Update all state that has some dependency on the current connection
self . window . get_widget ( " create-forward " ) . set_sensitive ( True )
if self . conn . is_read_only ( ) :
return self . startup_error ( _ ( " Connection is read only. " ) )
# A bit out of order, but populate arch + hv lists so we can
# determine a default
self . caps = self . conn . get_capabilities ( )
2006-08-09 19:40:34 +04:00
2008-03-14 20:18:44 +03:00
try :
2009-03-09 23:16:45 +03:00
self . change_caps ( )
2008-03-14 20:18:44 +03:00
except Exception , e :
2009-03-09 23:16:45 +03:00
logging . exception ( " Error determining default hypervisor " )
return self . startup_error ( _ ( " No guests are supported for this "
" connection. " ) )
self . populate_hv ( )
is_local = not self . conn . is_remote ( )
is_storage_capable = self . conn . is_storage_capable ( )
is_pv = ( self . capsguest . os_type == " xen " )
# Install Options
method_tree = self . window . get_widget ( " method-tree " )
method_pxe = self . window . get_widget ( " method-pxe " )
method_local = self . window . get_widget ( " method-local " )
method_tree . set_sensitive ( is_local )
method_local . set_sensitive ( not is_pv )
method_pxe . set_sensitive ( not is_pv )
pxe_tt = None
local_tt = None
tree_tt = None
if is_pv :
base = _ ( " %s installs not available for paravirt guests. " )
pxe_tt = base % " PXE "
local_tt = base % " CDROM/ISO "
if not is_local :
tree_tt = _ ( " URL installs not available for remote connections. " )
if not is_storage_capable and not local_tt :
local_tt = _ ( " Connection does not support storage management. " )
if not is_local and not is_storage_capable :
method_local . set_sensitive ( False )
if method_tree . get_active ( ) and not is_local :
method_local . set_active ( True )
elif is_pv :
method_tree . set_active ( True )
if not ( method_tree . get_property ( " sensitive " ) or
method_local . get_property ( " sensitive " ) or
method_pxe . get_property ( " sensitive " ) ) :
self . startup_error ( _ ( " No install options available for this "
" connection. " ) )
util . tooltip_wrapper ( method_tree , tree_tt )
util . tooltip_wrapper ( method_local , local_tt )
util . tooltip_wrapper ( method_pxe , pxe_tt )
# Attempt to create the default pool
self . usepool = False
try :
if is_storage_capable :
# FIXME: Emit 'pool-added' or something?
util . build_default_pool ( self . conn . vmm )
self . usepool = True
except Exception , e :
logging . debug ( " Building default pool failed: %s " % str ( e ) )
2006-08-14 21:34:06 +04:00
2009-03-09 23:16:45 +03:00
# Install local
self . window . get_widget ( " install-local-cdrom-box " ) . set_sensitive ( is_local )
if not is_local :
self . window . get_widget ( " install-local-iso " ) . set_active ( True )
# Don't select physical CDROM if no valid media is present
use_cd = ( self . window . get_widget ( " install-local-cdrom-combo " ) . get_active ( ) > = 0 )
if use_cd :
self . window . get_widget ( " install-local-cdrom " ) . set_active ( True )
2006-08-10 02:53:30 +04:00
else :
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " install-local-iso " ) . set_active ( True )
# Memory
memory = int ( self . conn . host_memory_size ( ) )
mem_label = _ ( " Up to %(maxmem)s available on the host " ) % { ' maxmem ' : \
self . pretty_memory ( memory ) }
mem_label = ( " <span size= ' small ' color= ' #484848 ' > %s </span> " %
mem_label )
self . window . get_widget ( " config-mem " ) . set_range ( 50 , memory / 1024 )
self . window . get_widget ( " phys-mem-label " ) . set_markup ( mem_label )
# CPU
phys_cpus = self . conn . host_active_processor_count ( )
max_v = self . conn . get_max_vcpus ( _type = self . capsdomain . hypervisor_type )
cmax = phys_cpus
if int ( max_v ) < int ( phys_cpus ) :
cmax = max_v
cpu_tooltip = ( _ ( " Hypervisor only supports %d virtual CPUs. " ) %
max_v )
else :
cpu_tooltip = None
util . tooltip_wrapper ( self . window . get_widget ( " config-cpus " ) ,
cpu_tooltip )
2009-03-10 05:42:17 +03:00
cmax = int ( cmax )
if cmax < = 0 :
cmax = 1
2009-03-09 23:16:45 +03:00
cpu_label = _ ( " Up to %(numcpus)d available " ) % { ' numcpus ' : \
int ( phys_cpus ) }
cpu_label = ( " <span size= ' small ' color= ' #484848 ' > %s </span> " %
cpu_label )
2009-03-10 05:42:17 +03:00
self . window . get_widget ( " config-cpus " ) . set_range ( 1 , cmax )
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " phys-cpu-label " ) . set_markup ( cpu_label )
# Storage
have_storage = ( is_local or is_storage_capable )
storage_tooltip = None
use_storage = self . window . get_widget ( " config-storage-select " )
storage_area = self . window . get_widget ( " config-storage-area " )
storage_area . set_sensitive ( have_storage )
if not have_storage :
storage_tooltip = _ ( " Connection does not support storage "
" management. " )
use_storage . set_sensitive ( True )
util . tooltip_wrapper ( storage_area , storage_tooltip )
# Networking
# This function will take care of all the remote stuff for us
self . populate_network_model ( )
self . window . get_widget ( " config-set-macaddr " ) . set_active ( True )
newmac = " "
try :
net = VirtualNetworkInterface ( conn = self . conn . vmm )
net . setup ( self . conn . vmm )
newmac = net . macaddr
except Exception , e :
logging . exception ( " Generating macaddr failed: %s " % str ( e ) )
self . window . get_widget ( " config-macaddr " ) . set_text ( newmac )
2006-08-10 02:53:30 +04:00
2009-03-09 23:16:45 +03:00
def populate_hv ( self ) :
hv_list = self . window . get_widget ( " config-hv " )
model = hv_list . get_model ( )
model . clear ( )
default = 0
tooltip = None
instmethod = self . get_config_install_page ( )
for guest in self . caps . guests :
gtype = guest . os_type
for dom in guest . domains :
domtype = dom . hypervisor_type
2009-05-12 21:09:08 +04:00
label = util . pretty_hv ( gtype , domtype )
2009-03-09 23:16:45 +03:00
# Don't add multiple rows for each arch
for m in model :
if m [ 0 ] == label :
label = None
break
if label == None :
continue
# Determine if this is the default given by guest_lookup
if ( gtype == self . capsguest . os_type and
self . capsdomain . hypervisor_type == domtype ) :
default = len ( model )
if gtype == " xen " :
if ( instmethod == INSTALL_PAGE_PXE or
instmethod == INSTALL_PAGE_ISO ) :
tooltip = _ ( " Only URL installs are supported for "
" paravirt. " )
model . append ( [ label , gtype , domtype , not bool ( tooltip ) ] )
hv_info = self . window . get_widget ( " config-hv-info " )
if tooltip :
hv_info . show ( )
util . tooltip_wrapper ( hv_info , tooltip )
2006-08-10 02:53:30 +04:00
else :
2009-03-09 23:16:45 +03:00
hv_info . hide ( )
2006-08-09 19:40:34 +04:00
2009-03-09 23:16:45 +03:00
hv_list . set_active ( default )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
def populate_arch ( self ) :
arch_list = self . window . get_widget ( " config-arch " )
model = arch_list . get_model ( )
model . clear ( )
default = 0
for guest in self . caps . guests :
for dom in guest . domains :
if ( guest . os_type == self . capsguest . os_type and
dom . hypervisor_type == self . capsdomain . hypervisor_type ) :
arch = guest . arch
if arch == self . capsguest . arch :
default = len ( model )
model . append ( [ guest . arch ] )
arch_list . set_active ( default )
def populate_conn_list ( self , urihint = None ) :
conn_list = self . window . get_widget ( " create-conn " )
model = conn_list . get_model ( )
model . clear ( )
default = - 1
for c in self . engine . connections . values ( ) :
connobj = c [ " connection " ]
if not connobj . is_active ( ) :
continue
if connobj . get_uri ( ) == urihint :
default = len ( model )
elif default < 0 and not connobj . is_remote ( ) :
# Favor local connections over remote connections
default = len ( model )
2009-07-20 22:47:50 +04:00
model . append ( [ connobj . get_uri ( ) , connobj . get_pretty_desc_active ( ) ] )
2009-03-09 23:16:45 +03:00
no_conns = ( len ( model ) == 0 )
if default < 0 and not no_conns :
default = 0
activeuri = " "
activedesc = " "
activeconn = None
if not no_conns :
conn_list . set_active ( default )
activeuri , activedesc = model [ default ]
activeconn = self . engine . connections [ activeuri ] [ " connection " ]
self . window . get_widget ( " create-conn-label " ) . set_text ( activedesc )
if len ( model ) < = 1 :
self . window . get_widget ( " create-conn " ) . hide ( )
self . window . get_widget ( " create-conn-label " ) . show ( )
2006-09-13 01:49:29 +04:00
else :
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " create-conn " ) . show ( )
self . window . get_widget ( " create-conn-label " ) . hide ( )
return activeconn
def populate_os_type_model ( self ) :
model = self . window . get_widget ( " install-os-type " ) . get_model ( )
model . clear ( )
model . append ( [ OS_GENERIC , _ ( " Generic " ) ] )
types = virtinst . FullVirtGuest . list_os_types ( )
for t in types :
model . append ( [ t , virtinst . FullVirtGuest . get_os_type_label ( t ) ] )
def populate_os_variant_model ( self , _type ) :
model = self . window . get_widget ( " install-os-version " ) . get_model ( )
model . clear ( )
if _type == OS_GENERIC :
model . append ( [ OS_GENERIC , _ ( " Generic " ) ] )
return
variants = virtinst . FullVirtGuest . list_os_variants ( _type )
for variant in variants :
model . append ( [ variant ,
virtinst . FullVirtGuest . get_os_variant_label ( _type ,
variant ) ] )
2009-05-11 19:00:03 +04:00
def populate_media_model ( self , model , urls ) :
2009-03-09 23:16:45 +03:00
model . clear ( )
for url in urls :
model . append ( [ url ] )
def populate_network_model ( self ) :
net_list = self . window . get_widget ( " config-netdev " )
model = net_list . get_model ( )
model . clear ( )
# For qemu:///session
if self . conn . is_qemu_session ( ) :
model . append ( [ VirtualNetworkInterface . TYPE_USER , None ,
_ ( " Usermode Networking " ) , True ] )
net_list . set_active ( 0 )
return
hasNet = False
netIdx = 0
# Virtual Networks
for uuid in self . conn . list_net_uuids ( ) :
net = self . conn . get_net ( uuid )
# FIXME: Should we use 'default' even if it's inactive?
label = _ ( " Virtual network " ) + " ' %s ' " % net . get_name ( )
if not net . is_active ( ) :
label + = " ( %s ) " % _ ( " Inactive " )
use_nat , host_dev = net . get_ipv4_forward ( )
if not use_nat :
desc = _ ( " Isolated network " )
elif host_dev :
desc = _ ( " NAT to %s " ) % host_dev
2008-02-23 23:26:26 +03:00
else :
2009-03-09 23:16:45 +03:00
desc = _ ( " NAT to any device " )
label + = " : %s " % desc
2007-09-13 01:57:36 +04:00
2009-03-09 23:16:45 +03:00
model . append ( [ VirtualNetworkInterface . TYPE_VIRTUAL ,
net . get_name ( ) , label , True ] )
hasNet = True
# FIXME: This preference should be configurable
if net . get_name ( ) == " default " :
netIdx = len ( model ) - 1
if not hasNet :
model . append ( [ None , None , _ ( " No virtual networks available " ) ,
False ] )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
# Physical devices
hasShared = False
brIndex = - 1
if not self . conn . is_remote ( ) :
for name in self . conn . list_net_device_paths ( ) :
br = self . conn . get_net_device ( name )
if br . is_shared ( ) :
hasShared = True
if brIndex < 0 :
brIndex = len ( model )
brlabel = " ( %s %s ) " % ( _ ( " Bridge " ) , br . get_bridge ( ) )
sensitive = True
else :
brlabel = " ( %s ) " % _ ( " Not bridged " )
sensitive = False
model . append ( [ VirtualNetworkInterface . TYPE_BRIDGE ,
br . get_bridge ( ) ,
_ ( " Host device %s %s " ) % ( br . get_name ( ) , brlabel ) ,
sensitive ] )
# If there is a bridge device, default to that
# If not, use 'default' network
# If not present, use first list entry
# If list empty, use no network devices
if hasShared :
default = brIndex
elif hasNet :
default = netIdx
2006-09-13 01:49:29 +04:00
else :
2009-03-09 23:16:45 +03:00
model . insert ( 0 , [ None , None , _ ( " No networking. " ) , True ] )
default = 0
net_list . set_active ( default )
2009-05-11 21:18:14 +04:00
def change_caps ( self , gtype = None , dtype = None , arch = None ) :
2009-03-13 21:37:15 +03:00
if gtype == None :
# If none specified, prefer HVM. This way, the default install
# options won't be limited because we default to PV. If hvm not
# supported, differ to guest_lookup
for g in self . caps . guests :
if g . os_type == " hvm " :
gtype = " hvm "
break
2009-03-09 23:16:45 +03:00
( newg ,
newdom ) = virtinst . CapabilitiesParser . guest_lookup ( conn = self . conn . vmm ,
caps = self . caps ,
os_type = gtype ,
type = dtype ,
2009-05-11 21:18:14 +04:00
accelerated = True ,
arch = arch )
2009-03-09 23:16:45 +03:00
if ( self . capsguest and self . capsdomain and
( newg . arch == self . capsguest . arch and
newg . os_type == self . capsguest . os_type and
newdom . hypervisor_type == self . capsdomain . hypervisor_type ) ) :
# No change
return
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
self . capsguest = newg
self . capsdomain = newdom
logging . debug ( " Guest type set to os_type= %s , arch= %s , dom_type= %s " %
( self . capsguest . os_type , self . capsguest . arch ,
self . capsdomain . hypervisor_type ) )
def populate_summary ( self ) :
ignore , ignore , dlabel , vlabel = self . get_config_os_info ( )
mem = self . pretty_memory ( int ( self . guest . memory ) * 1024 )
cpu = str ( int ( self . guest . vcpus ) )
instmethod = self . get_config_install_page ( )
install = " "
if instmethod == INSTALL_PAGE_ISO :
install = _ ( " Local CDROM/ISO " )
elif instmethod == INSTALL_PAGE_URL :
install = _ ( " URL Install Tree " )
elif instmethod == INSTALL_PAGE_PXE :
install = _ ( " PXE Install " )
if len ( self . guest . disks ) == 0 :
storage = _ ( " None " )
2006-09-13 01:49:29 +04:00
else :
2009-03-09 23:16:45 +03:00
disk = self . guest . disks [ 0 ]
storage = " %s " % self . pretty_storage ( disk . size )
storage + = ( " <span size= ' small ' color= ' #484848 ' > %s </span> " %
disk . path )
osstr = " "
if not dlabel :
osstr = _ ( " Generic " )
elif not vlabel :
osstr = _ ( " Generic " ) + " " + dlabel
2007-03-21 19:28:36 +03:00
else :
2009-03-09 23:16:45 +03:00
osstr = vlabel
2007-03-21 19:28:36 +03:00
2009-03-09 23:16:45 +03:00
title = " Ready to begin installation of <b> %s </b> " % self . guest . name
2007-05-24 23:51:32 +04:00
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " summary-title " ) . set_markup ( title )
self . window . get_widget ( " summary-os " ) . set_text ( osstr )
self . window . get_widget ( " summary-install " ) . set_text ( install )
self . window . get_widget ( " summary-mem " ) . set_text ( mem )
self . window . get_widget ( " summary-cpu " ) . set_text ( cpu )
self . window . get_widget ( " summary-storage " ) . set_markup ( storage )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
# get_* methods
def get_config_name ( self ) :
return self . window . get_widget ( " create-vm-name " ) . get_text ( )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
def get_config_install_page ( self ) :
2008-02-23 23:26:26 +03:00
if self . window . get_widget ( " method-local " ) . get_active ( ) :
2009-03-09 23:16:45 +03:00
return INSTALL_PAGE_ISO
2008-02-23 23:26:26 +03:00
elif self . window . get_widget ( " method-tree " ) . get_active ( ) :
2009-03-09 23:16:45 +03:00
return INSTALL_PAGE_URL
elif self . window . get_widget ( " method-pxe " ) . get_active ( ) :
return INSTALL_PAGE_PXE
def get_config_os_info ( self ) :
d_list = self . window . get_widget ( " install-os-type " )
d_idx = d_list . get_active ( )
v_list = self . window . get_widget ( " install-os-version " )
v_idx = v_list . get_active ( )
distro = None
dlabel = None
variant = None
vlabel = None
if d_idx > = 0 :
distro , dlabel = d_list . get_model ( ) [ d_idx ]
if v_idx > = 0 :
variant , vlabel = v_list . get_model ( ) [ v_idx ]
return ( distro , variant , dlabel , vlabel )
2009-05-11 19:00:03 +04:00
def get_config_local_media ( self , store_media = False ) :
2009-03-09 23:16:45 +03:00
if self . window . get_widget ( " install-local-cdrom " ) . get_active ( ) :
return self . window . get_widget ( " install-local-cdrom-combo " ) . get_active_text ( )
else :
2009-05-11 19:00:03 +04:00
ret = self . window . get_widget ( " install-local-box " ) . child . get_text ( )
if ret and store_media :
self . conn . config_add_iso_path ( ret )
return ret
2009-03-09 23:16:45 +03:00
def get_config_detectable_media ( self ) :
instpage = self . get_config_install_page ( )
media = " "
if instpage == INSTALL_PAGE_ISO :
media = self . get_config_local_media ( )
elif instpage == INSTALL_PAGE_URL :
2009-05-11 18:17:52 +04:00
media = self . window . get_widget ( " install-url-box " ) . get_active_text ( )
2009-03-09 23:16:45 +03:00
return media
2009-05-11 19:00:03 +04:00
def get_config_url_info ( self , store_media = False ) :
2009-05-11 18:17:52 +04:00
media = self . window . get_widget ( " install-url-box " ) . get_active_text ( ) . strip ( )
2009-03-09 23:16:45 +03:00
extra = self . window . get_widget ( " install-urlopts-entry " ) . get_text ( ) . strip ( )
2009-05-11 18:17:52 +04:00
ks = self . window . get_widget ( " install-ks-box " ) . get_active_text ( ) . strip ( )
2009-03-09 23:16:45 +03:00
2009-05-11 19:00:03 +04:00
if media and store_media :
2009-03-09 23:16:45 +03:00
self . config . add_media_url ( media )
2009-05-11 19:00:03 +04:00
if ks and store_media :
2009-03-09 23:16:45 +03:00
self . config . add_kickstart_url ( ks )
return ( media . strip ( ) , extra . strip ( ) , ks . strip ( ) )
def get_storage_info ( self ) :
path = None
size = self . window . get_widget ( " config-storage-size " ) . get_value ( )
2009-06-16 23:31:18 +04:00
sparse = not self . window . get_widget ( " config-storage-nosparse " ) . get_active ( )
2009-03-09 23:16:45 +03:00
if self . window . get_widget ( " config-storage-create " ) . get_active ( ) :
path = self . get_default_path ( self . guest . name )
logging . debug ( " Default storage path is: %s " % path )
else :
path = self . window . get_widget ( " config-storage-entry " ) . get_text ( )
2009-06-16 23:31:18 +04:00
return ( path , size , sparse )
2009-03-09 23:16:45 +03:00
def get_default_path ( self , name ) :
path = " "
# Don't generate a new path if the install failed
2009-07-07 00:49:47 +04:00
if self . failed_guest :
if len ( self . failed_guest . disks ) > 0 :
return self . failed_guest . disks [ 0 ] . path
2009-03-09 23:16:45 +03:00
if not self . usepool :
# Use old generating method
d = self . config . get_default_image_dir ( self . conn )
origf = os . path . join ( d , name + " .img " )
f = origf
n = 1
while os . path . exists ( f ) and n < 100 :
f = os . path . join ( d , self . get_config_name ( ) +
" - " + str ( n ) + " .img " )
n + = 1
if os . path . exists ( f ) :
f = origf
path = f
2008-02-23 23:26:26 +03:00
else :
2009-03-09 23:16:45 +03:00
pool = self . conn . vmm . storagePoolLookupByName ( util . DEFAULT_POOL_NAME )
path = virtinst . Storage . StorageVolume . find_free_name ( name ,
pool_object = pool , suffix = " .img " )
path = os . path . join ( util . DEFAULT_POOL_PATH , path )
return path
def host_disk_space ( self , path = None ) :
if not path :
path = util . DEFAULT_POOL_PATH
avail = 0
if self . usepool :
# FIXME: make sure not inactive?
# FIXME: use a conn specific function after we send pool-added
pool = virtinst . util . lookup_pool_by_path ( self . conn . vmm , path )
if pool :
2009-09-22 00:09:51 +04:00
pool . refresh ( 0 )
2009-03-09 23:16:45 +03:00
avail = int ( virtinst . util . get_xml_path ( pool . XMLDesc ( 0 ) ,
" /pool/available " ) )
if not avail and not self . conn . is_remote ( ) :
vfs = os . statvfs ( os . path . dirname ( path ) )
avail = vfs [ statvfs . F_FRSIZE ] * vfs [ statvfs . F_BAVAIL ]
2009-09-22 00:09:51 +04:00
return float ( avail / 1024.0 / 1024.0 / 1024.0 )
def host_space_tick ( self ) :
max_storage = self . host_disk_space ( )
if self . host_storage == max_storage :
return 1
self . host_storage = max_storage
hd_label = ( " %s available in the default location " %
self . pretty_storage ( max_storage ) )
hd_label = ( " <span color= ' #484848 ' > %s </span> " % hd_label )
self . window . get_widget ( " phys-hd-label " ) . set_markup ( hd_label )
self . window . get_widget ( " config-storage-size " ) . set_range ( 1 , self . host_storage )
return 1
2009-03-09 23:16:45 +03:00
def get_config_network_info ( self ) :
netidx = self . window . get_widget ( " config-netdev " ) . get_active ( )
netinfo = self . window . get_widget ( " config-netdev " ) . get_model ( ) [ netidx ]
macaddr = self . window . get_widget ( " config-macaddr " ) . get_text ( )
return netinfo [ 0 ] , netinfo [ 1 ] , macaddr . strip ( )
2007-02-19 19:52:37 +03:00
2008-09-02 20:09:39 +04:00
def get_config_sound ( self ) :
2009-03-09 23:16:45 +03:00
if self . conn . is_remote ( ) :
2008-09-02 20:09:39 +04:00
return self . config . get_remote_sound ( )
return self . config . get_local_sound ( )
2009-03-09 23:16:45 +03:00
def is_detect_active ( self ) :
return self . window . get_widget ( " install-detect-os " ) . get_active ( )
# Listeners
def conn_changed ( self , src ) :
idx = src . get_active ( )
model = src . get_model ( )
if idx < 0 :
self . set_conn ( None )
return
uri = model [ idx ] [ 0 ]
conn = self . engine . connections [ uri ] [ " connection " ]
self . set_conn ( conn )
def hv_changed ( self , src ) :
idx = src . get_active ( )
if idx < 0 :
return
row = src . get_model ( ) [ idx ]
self . change_caps ( row [ 1 ] , row [ 2 ] )
self . populate_arch ( )
def arch_changed ( self , src ) :
idx = src . get_active ( )
if idx < 0 :
return
2009-05-11 21:18:14 +04:00
arch = src . get_model ( ) [ idx ] [ 0 ]
self . change_caps ( self . capsguest . os_type ,
self . capsdomain . hypervisor_type ,
arch )
2009-03-09 23:16:45 +03:00
def url_box_changed ( self , ignore ) :
# If the url_entry has focus, don't fire detect_media_os, it means
# the user is probably typing
2009-05-11 18:17:52 +04:00
if self . window . get_widget ( " install-url-box " ) . child . flags ( ) & gtk . HAS_FOCUS :
2009-03-09 23:16:45 +03:00
return
self . detect_media_os ( )
def detect_media_os ( self , ignore1 = None ) :
curpage = self . window . get_widget ( " create-pages " ) . get_current_page ( )
if self . is_detect_active ( ) and curpage == PAGE_INSTALL :
self . detect_os_distro ( )
def toggle_detect_os ( self , src ) :
dodetect = src . get_active ( )
if dodetect :
self . window . get_widget ( " install-os-type-label " ) . show ( )
self . window . get_widget ( " install-os-version-label " ) . show ( )
self . window . get_widget ( " install-os-type " ) . hide ( )
self . window . get_widget ( " install-os-version " ) . hide ( )
self . detect_media_os ( ) # Run detection
else :
self . window . get_widget ( " install-os-type-label " ) . hide ( )
self . window . get_widget ( " install-os-version-label " ) . hide ( )
self . window . get_widget ( " install-os-type " ) . show ( )
self . window . get_widget ( " install-os-version " ) . show ( )
def change_os_type ( self , box ) :
model = box . get_model ( )
if box . get_active_iter ( ) != None :
_type = model . get_value ( box . get_active_iter ( ) , 0 )
self . populate_os_variant_model ( _type )
variant = self . window . get_widget ( " install-os-version " )
variant . set_active ( 0 )
def local_cdrom_toggled ( self , src ) :
combo = self . window . get_widget ( " install-local-cdrom-combo " )
is_active = src . get_active ( )
if is_active :
if combo . get_active ( ) != - 1 :
# Local CDROM was selected with media preset, detect distro
self . detect_media_os ( )
self . window . get_widget ( " install-local-cdrom-combo " ) . set_sensitive ( is_active )
def toggle_local_iso ( self , src ) :
uselocal = src . get_active ( )
2009-05-11 19:00:03 +04:00
self . window . get_widget ( " install-local-box " ) . set_sensitive ( uselocal )
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " install-local-browse " ) . set_sensitive ( uselocal )
def detect_visibility_changed ( self , src , ignore = None ) :
is_visible = src . get_property ( " visible " )
detect_chkbox = self . window . get_widget ( " install-detect-os " )
nodetect_label = self . window . get_widget ( " install-nodetect-label " )
detect_chkbox . set_active ( is_visible )
detect_chkbox . toggled ( )
if is_visible :
nodetect_label . hide ( )
else :
nodetect_label . show ( )
def browse_iso ( self , ignore1 = None , ignore2 = None ) :
2009-06-18 18:40:37 +04:00
self . _browse_file ( _ ( " Locate ISO Image " ) ,
2009-06-24 03:30:12 +04:00
self . set_iso_storage_path ,
is_media = True )
2009-05-11 19:00:03 +04:00
self . window . get_widget ( " install-local-box " ) . activate ( )
2009-03-09 23:16:45 +03:00
def toggle_enable_storage ( self , src ) :
self . window . get_widget ( " config-storage-box " ) . set_sensitive ( src . get_active ( ) )
def browse_storage ( self , ignore1 ) :
2009-06-18 18:40:37 +04:00
self . _browse_file ( _ ( " Locate existing storage " ) ,
2009-06-24 03:30:12 +04:00
self . set_disk_storage_path ,
is_media = False )
2009-03-09 23:16:45 +03:00
def toggle_storage_select ( self , src ) :
act = src . get_active ( )
self . window . get_widget ( " config-storage-browse-box " ) . set_sensitive ( act )
def toggle_macaddr ( self , src ) :
self . window . get_widget ( " config-macaddr " ) . set_sensitive ( src . get_active ( ) )
2009-06-18 18:40:37 +04:00
def set_iso_storage_path ( self , ignore , path ) :
self . window . get_widget ( " install-local-box " ) . child . set_text ( path )
def set_disk_storage_path ( self , ignore , path ) :
self . window . get_widget ( " config-storage-entry " ) . set_text ( path )
2009-03-09 23:16:45 +03:00
# Navigation methods
def set_install_page ( self ) :
instnotebook = self . window . get_widget ( " install-method-pages " )
detectbox = self . window . get_widget ( " install-detect-os-box " )
instpage = self . get_config_install_page ( )
# Detection only works/ is valid for URL,
# FIXME: Also works for CDROM if running as root (since we need to
# mount the iso/cdrom), but we should probably make this work for
# more distros (like windows) before we enable it
if ( instpage == INSTALL_PAGE_URL ) :
detectbox . show ( )
else :
detectbox . hide ( )
if instpage == INSTALL_PAGE_PXE :
# Hide the install notebook for pxe, since there isn't anything
# to ask for
instnotebook . hide ( )
else :
instnotebook . show ( )
instnotebook . set_current_page ( instpage )
def back ( self , src ) :
notebook = self . window . get_widget ( " create-pages " )
curpage = notebook . get_current_page ( )
if curpage == PAGE_INSTALL :
self . reset_guest_type ( )
notebook . set_current_page ( curpage - 1 )
def forward ( self , src ) :
notebook = self . window . get_widget ( " create-pages " )
curpage = notebook . get_current_page ( )
if self . validate ( notebook . get_current_page ( ) ) != True :
return
if curpage == PAGE_NAME :
self . set_install_page ( )
# See if we need to alter our default HV based on install method
# FIXME: URL installs also come into play with whether we want
# PV or FV
self . guest_from_install_type ( )
notebook . set_current_page ( curpage + 1 )
def page_changed ( self , ignore1 , ignore2 , pagenum ) :
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
# Update page number
page_lbl = ( " <span color= ' #59B0E2 ' > %s </span> " %
_ ( " Step %(current_page)d of %(max_page)d " ) %
{ ' current_page ' : pagenum + 1 , ' max_page ' : PAGE_FINISH + 1 } )
self . window . get_widget ( " config-pagenum " ) . set_markup ( page_lbl )
if pagenum == PAGE_NAME :
2006-08-10 02:53:30 +04:00
self . window . get_widget ( " create-back " ) . set_sensitive ( False )
2009-03-09 23:16:45 +03:00
else :
self . window . get_widget ( " create-back " ) . set_sensitive ( True )
2008-09-05 17:42:25 +04:00
2009-03-09 23:16:45 +03:00
if pagenum == PAGE_INSTALL :
self . detect_media_os ( )
2007-05-24 23:51:32 +04:00
2009-03-09 23:16:45 +03:00
if pagenum == PAGE_FINISH :
2006-08-10 02:53:30 +04:00
self . window . get_widget ( " create-forward " ) . hide ( )
self . window . get_widget ( " create-finish " ) . show ( )
2009-03-09 23:16:45 +03:00
self . populate_summary ( )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
# Repopulate the HV list, so we can make install method relevant
# changes
self . populate_hv ( )
else :
self . window . get_widget ( " create-forward " ) . show ( )
self . window . get_widget ( " create-finish " ) . hide ( )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
def validate ( self , pagenum ) :
try :
if pagenum == PAGE_NAME :
return self . validate_name_page ( )
elif pagenum == PAGE_INSTALL :
2009-09-24 19:41:49 +04:00
return self . validate_install_page ( revalidate = False )
2009-03-09 23:16:45 +03:00
elif pagenum == PAGE_MEM :
return self . validate_mem_page ( )
elif pagenum == PAGE_STORAGE :
# If the user selects 'no storage' and they used cd/iso install
# media, we want to go back and change the installer to
# LiveCDInstaller, which means re-validate everything
if not self . validate_name_page ( ) :
return False
elif not self . validate_install_page ( ) :
return False
elif not self . validate_mem_page ( ) :
return False
2009-09-24 19:41:49 +04:00
return self . validate_storage_page ( revalidate = False )
2006-11-03 18:02:02 +03:00
2009-03-09 23:16:45 +03:00
elif pagenum == PAGE_FINISH :
# Since we allow the user to change to change HV type + arch
# on the last page, we need to revalidate everything
if not self . validate_name_page ( ) :
return False
elif not self . validate_install_page ( ) :
return False
elif not self . validate_mem_page ( ) :
return False
elif not self . validate_storage_page ( ) :
return False
return self . validate_final_page ( )
2006-09-13 01:49:29 +04:00
2009-03-09 23:16:45 +03:00
except Exception , e :
self . err . show_err ( _ ( " Uncaught error validating install "
" parameters: %s " ) % str ( e ) ,
" " . join ( traceback . format_exc ( ) ) )
return
def validate_name_page ( self ) :
name = self . get_config_name ( )
self . guest = None
2006-09-13 01:49:29 +04:00
2006-08-15 19:32:02 +04:00
try :
2009-03-09 23:16:45 +03:00
g = virtinst . Guest ( connection = self . conn . vmm )
g . name = name
except Exception , e :
return self . verr ( _ ( " Invalid System Name " ) , str ( e ) )
return True
2009-09-24 19:41:49 +04:00
def validate_install_page ( self , revalidate = True ) :
2009-03-09 23:16:45 +03:00
instmethod = self . get_config_install_page ( )
installer = None
location = None
extra = None
ks = None
cdrom = False
distro , variant , ignore1 , ignore2 = self . get_config_os_info ( )
if instmethod == INSTALL_PAGE_ISO :
if self . window . get_widget ( " enable-storage " ) . get_active ( ) :
instclass = virtinst . DistroInstaller
else :
# CD/ISO install and no disks implies LiveCD
instclass = virtinst . LiveCDInstaller
media = self . get_config_local_media ( )
if not media :
return self . verr ( _ ( " An install media selection is required. " ) )
location = media
cdrom = True
elif instmethod == INSTALL_PAGE_URL :
instclass = virtinst . DistroInstaller
media , extra , ks = self . get_config_url_info ( )
if not media :
return self . verr ( _ ( " An install tree is required. " ) )
location = media
elif instmethod == INSTALL_PAGE_PXE :
instclass = virtinst . PXEInstaller
# Build the installer and Guest instance
try :
installer = self . build_installer ( instclass )
self . guest = installer . guest_from_installer ( )
self . guest . name = self . get_config_name ( )
except Exception , e :
return self . verr ( _ ( " Error setting installer parameters. " ) , str ( e ) )
# Validate media location
try :
if location is not None :
self . guest . installer . location = location
if cdrom :
self . guest . installer . cdrom = True
extraargs = " "
if extra :
extraargs + = extra
if ks :
extraargs + = " ks= %s " % ks
if extraargs :
self . guest . installer . extraargs = extraargs
except Exception , e :
return self . verr ( _ ( " Error setting install media location. " ) ,
str ( e ) )
# OS distro/variant validation
try :
if distro and distro != OS_GENERIC :
self . guest . os_type = distro
if variant and variant != OS_GENERIC :
self . guest . os_variant = variant
2008-08-25 23:03:51 +04:00
except ValueError , e :
2009-03-09 23:16:45 +03:00
return self . err . val_err ( _ ( " Error setting OS information. " ) ,
str ( e ) )
2009-05-11 19:00:03 +04:00
# Validation passed, store the install path (if there is one) in
# gconf
self . get_config_local_media ( store_media = True )
self . get_config_url_info ( store_media = True )
2009-03-09 23:16:45 +03:00
return True
2007-02-01 22:16:44 +03:00
2009-03-09 23:16:45 +03:00
def validate_mem_page ( self ) :
cpus = self . window . get_widget ( " config-cpus " ) . get_value ( )
mem = self . window . get_widget ( " config-mem " ) . get_value ( )
# VCPUS
try :
self . guest . vcpus = int ( cpus )
except Exception , e :
return self . verr ( _ ( " Error setting CPUs. " ) , str ( e ) )
# Memory
try :
self . guest . memory = int ( mem )
self . guest . maxmemory = int ( mem )
except Exception , e :
return self . verr ( _ ( " Error setting guest memory. " ) , str ( e ) )
return True
2009-09-24 19:41:49 +04:00
def validate_storage_page ( self , revalidate = True ) :
2009-03-09 23:16:45 +03:00
use_storage = self . window . get_widget ( " enable-storage " ) . get_active ( )
self . guest . disks = [ ]
# Validate storage
if not use_storage :
return True
try :
# This can error out
diskpath , disksize , sparse = self . get_storage_info ( )
if not diskpath :
return self . verr ( _ ( " A storage path must be specified. " ) )
disk = virtinst . VirtualDisk ( conn = self . conn . vmm ,
path = diskpath ,
size = disksize ,
sparse = sparse )
2008-02-15 01:33:52 +03:00
2009-03-09 23:16:45 +03:00
self . guest . disks . append ( disk )
except Exception , e :
return self . verr ( _ ( " Storage parameter error. " ) , str ( e ) )
isfatal , errmsg = disk . is_size_conflict ( )
2009-09-24 19:41:49 +04:00
if not revalidate and not isfatal and errmsg :
2009-03-09 23:16:45 +03:00
# Fatal errors are reported when setting 'size'
res = self . err . ok_cancel ( _ ( " Not Enough Free Space " ) , errmsg )
if not res :
return False
# Disk collision
2009-09-24 19:41:49 +04:00
if not revalidate and disk . is_conflict_disk ( self . guest . conn ) :
res = self . err . yes_no ( _ ( ' Disk " %s " is already in use by another '
' guest! ' % disk . path ) ,
_ ( " Do you really want to use the disk? " ) )
if not res :
return False
return True
2009-03-09 23:16:45 +03:00
def validate_final_page ( self ) :
nettype , devname , macaddr = self . get_config_network_info ( )
self . guest . nics = [ ]
# Make sure VirtualNetwork is running
if ( nettype == VirtualNetworkInterface . TYPE_VIRTUAL and
devname not in self . conn . vmm . listNetworks ( ) ) :
res = self . err . yes_no ( _ ( " Virtual Network is not active. " ) ,
_ ( " Virtual Network ' %s ' is not active. "
" Would you like to start the network "
" now? " ) % devname )
if not res :
return False
# Try to start the network
try :
net = self . conn . vmm . networkLookupByName ( devname )
net . create ( )
logging . info ( " Started network ' %s ' . " % devname )
except Exception , e :
return self . err . show_err ( _ ( " Could not start virtual network "
" ' %s ' : %s " ) % ( devname , str ( e ) ) ,
" " . join ( traceback . format_exc ( ) ) )
if nettype is None :
# No network device available
instmethod = self . get_config_install_page ( )
methname = None
if instmethod == INSTALL_PAGE_PXE :
methname = " PXE "
elif instmethod == INSTALL_PAGE_URL :
methname = " URL "
if methname :
return self . verr ( _ ( " Network device required for %s install. " ) %
methname )
return True
# Create network device
try :
bridge = None
netname = None
if nettype == VirtualNetworkInterface . TYPE_VIRTUAL :
netname = devname
elif nettype == VirtualNetworkInterface . TYPE_BRIDGE :
bridge = devname
elif nettype == VirtualNetworkInterface . TYPE_USER :
pass
net = VirtualNetworkInterface ( type = nettype ,
bridge = bridge ,
network = netname ,
macaddr = macaddr )
self . guest . nics . append ( net )
except Exception , e :
return self . verr ( _ ( " Error with network parameters. " ) , str ( e ) )
# Make sure there is no mac address collision
isfatal , errmsg = net . is_conflict_net ( self . guest . conn )
if isfatal :
return self . err . val_err ( _ ( " Mac address collision. " ) , errmsg )
elif errmsg is not None :
return self . err . yes_no ( _ ( " Mac address collision. " ) ,
_ ( " %s Are you sure you want to use this "
" address? " ) % errmsg )
return True
# Interesting methods
def build_installer ( self , instclass ) :
installer = instclass ( conn = self . conn . vmm ,
type = self . capsdomain . hypervisor_type ,
os_type = self . capsguest . os_type )
installer . arch = self . capsguest . arch
return installer
def guest_from_install_type ( self ) :
instmeth = self . get_config_install_page ( )
conntype = self . conn . get_type ( ) . lower ( )
if conntype not in [ " xen " , " test " ] :
return
# FIXME: some things are dependent on domain type (vcpu max)
if instmeth == INSTALL_PAGE_URL :
self . change_caps ( gtype = " xen " , dtype = conntype )
2008-02-15 01:33:52 +03:00
else :
2009-03-09 23:16:45 +03:00
self . change_caps ( gtype = " hvm " , dtype = conntype )
def reset_guest_type ( self ) :
self . change_caps ( )
def finish ( self , src ) :
# Validate the final page
if self . validate ( self . window . get_widget ( " create-pages " ) . get_current_page ( ) ) != True :
return False
2008-02-15 01:33:52 +03:00
2009-03-09 23:16:45 +03:00
guest = self . guest
disk = len ( guest . disks ) and guest . disks [ 0 ]
# Generate UUID
try :
guest . uuid = virtinst . util . uuidToString ( virtinst . util . randomUUID ( ) )
except Exception , e :
self . err . show_err ( _ ( " Error setting UUID: %s " ) % str ( e ) ,
" " . join ( traceback . format_exc ( ) ) )
return False
# Set up graphics device
2008-03-17 21:17:58 +03:00
try :
2008-06-16 20:00:13 +04:00
guest . _graphics_dev = virtinst . VirtualGraphics ( type = virtinst . VirtualGraphics . TYPE_VNC )
2008-03-17 21:17:58 +03:00
except Exception , e :
self . err . show_err ( _ ( " Error setting up graphics device: " ) + str ( e ) ,
" " . join ( traceback . format_exc ( ) ) )
return False
2006-08-29 07:06:31 +04:00
2009-03-09 23:16:45 +03:00
# Set up sound device (if present)
2008-10-23 23:15:19 +04:00
guest . sound_devs = [ ]
2008-09-02 20:09:39 +04:00
try :
if self . get_config_sound ( ) :
guest . sound_devs . append ( virtinst . VirtualAudio ( model = " es1370 " ) )
except Exception , e :
self . err . show_err ( _ ( " Error setting up sound device: " ) + str ( e ) ,
" " . join ( traceback . format_exc ( ) ) )
return False
2009-03-09 23:16:45 +03:00
logging . debug ( " Creating a VM %s " % guest . name +
" \n Type: %s , %s " % ( guest . type ,
guest . installer . os_type ) +
" \n UUID: %s " % guest . uuid +
" \n Install Source: %s " % guest . location +
" \n OS: %s : %s " % ( guest . os_type , guest . os_variant ) +
" \n Kernel args: %s " % guest . extraargs +
" \n Memory: %s " % guest . memory +
" \n Max Memory: %s " % guest . maxmemory +
" \n # VCPUs: %s " % str ( guest . vcpus ) +
" \n Filesize: %s " % ( disk and disk . size ) or " None " +
" \n Disk image: %s " % ( disk and disk . path ) or " None " +
" \n Audio?: %s " % str ( self . get_config_sound ( ) ) )
# Start the install
2009-07-07 00:49:47 +04:00
self . failed_guest = None
2006-10-25 17:38:17 +04:00
self . topwin . set_sensitive ( False )
2006-11-08 01:25:08 +03:00
self . topwin . window . set_cursor ( gtk . gdk . Cursor ( gtk . gdk . WATCH ) )
2007-01-11 00:11:57 +03:00
2006-08-17 00:00:28 +04:00
progWin = vmmAsyncJob ( self . config , self . do_install , [ guest ] ,
2007-02-01 22:16:44 +03:00
title = _ ( " Creating Virtual Machine " ) ,
2009-03-09 23:16:45 +03:00
text = _ ( " The virtual machine is now being "
" created. Allocation of disk storage "
" and retrieval of the installation "
" images may take a few minutes to "
" complete. " ) )
2006-08-17 00:00:28 +04:00
progWin . run ( )
2009-04-03 22:15:15 +04:00
error , details = progWin . get_error ( )
2007-02-01 22:16:44 +03:00
2009-04-03 22:15:15 +04:00
if error != None :
self . err . show_err ( error , details )
2006-09-20 23:45:40 +04:00
2006-10-25 23:03:38 +04:00
self . topwin . set_sensitive ( True )
2006-11-08 01:25:08 +03:00
self . topwin . window . set_cursor ( gtk . gdk . Cursor ( gtk . gdk . TOP_LEFT_ARROW ) )
2009-04-03 22:15:15 +04:00
if error :
2009-07-07 00:49:47 +04:00
self . failed_guest = self . guest
2009-04-03 22:15:15 +04:00
return
2006-10-03 19:53:07 +04:00
# Ensure new VM is loaded
2009-03-09 23:16:45 +03:00
# FIXME: Hmm, shouldn't we emit a signal here rather than do this?
self . conn . tick ( noStatsUpdate = True )
2006-10-03 19:53:07 +04:00
2006-11-06 23:01:28 +03:00
if self . config . get_console_popup ( ) == 1 :
2006-10-31 22:29:22 +03:00
# user has requested console on new created vms only
2009-03-09 23:16:45 +03:00
vm = self . conn . get_vm ( guest . uuid )
2008-11-18 22:48:10 +03:00
( gtype , ignore , ignore , ignore , ignore ) = vm . get_graphics_console ( )
2006-10-31 22:29:22 +03:00
if gtype == " vnc " :
2009-03-09 23:16:45 +03:00
self . emit ( " action-show-console " , self . conn . get_uri ( ) ,
guest . uuid )
2006-10-31 22:29:22 +03:00
else :
2009-03-09 23:16:45 +03:00
self . emit ( " action-show-terminal " , self . conn . get_uri ( ) ,
guest . uuid )
2006-08-17 00:00:28 +04:00
self . close ( )
2009-03-09 23:16:45 +03:00
2007-01-12 23:39:18 +03:00
def do_install ( self , guest , asyncjob ) :
2007-01-11 00:11:57 +03:00
meter = vmmCreateMeter ( asyncjob )
2009-04-03 22:15:15 +04:00
error = None
details = None
2006-08-15 19:32:02 +04:00
try :
2006-09-26 23:50:59 +04:00
logging . debug ( " Starting background install process " )
2008-08-18 20:02:49 +04:00
2009-03-09 23:16:45 +03:00
guest . conn = util . dup_conn ( self . config , self . conn )
# FIXME: This is why we need a more unified virtinst device API: so
# we can do things like swap out the connection on all
# devices for a forked one. At least we should get a helper
# method in the Guest API.
2008-09-09 05:56:18 +04:00
for disk in guest . disks :
disk . conn = guest . conn
2008-08-18 20:02:49 +04:00
2007-01-11 00:11:57 +03:00
dom = guest . start_install ( False , meter = meter )
2006-09-26 23:50:59 +04:00
if dom == None :
2009-04-03 22:15:15 +04:00
error = _ ( " Guest installation failed to complete " )
details = error
2006-09-26 23:50:59 +04:00
logging . error ( " Guest install did not return a domain " )
else :
logging . debug ( " Install completed " )
2007-04-11 02:50:04 +04:00
except :
2008-11-18 23:42:51 +03:00
( _type , value , stacktrace ) = sys . exc_info ( )
2007-04-11 02:50:04 +04:00
# Detailed error message, in English so it can be Googled.
2009-03-09 23:16:45 +03:00
details = ( " Unable to complete install ' %s ' " %
( str ( _type ) + " " + str ( value ) + " \n " +
traceback . format_exc ( stacktrace ) ) )
2009-04-03 22:15:15 +04:00
error = ( _ ( " Unable to complete install: ' %s ' " ) % str ( value ) )
2007-04-11 02:50:04 +04:00
2009-04-03 22:15:15 +04:00
if error :
asyncjob . set_error ( error , details )
2007-06-22 21:32:13 +04:00
2009-03-09 23:16:45 +03:00
def pretty_storage ( self , size ) :
return " %.1f Gb " % float ( size )
2007-06-22 21:32:13 +04:00
2009-03-09 23:16:45 +03:00
def pretty_memory ( self , mem ) :
return " %d MB " % ( mem / 1024.0 )
# Distro detection methods
# Clear global detection thread state
def _clear_detect_thread ( self ) :
self . detectThreadLock . acquire ( )
self . detectThread = None
self . detectThreadLock . release ( )
# Create and launch a detection thread (if no detection already running)
def detect_os_distro ( self ) :
self . detectThreadLock . acquire ( )
if self . detectThread is not None :
# We are already checking (some) media, so let that continue
self . detectThreadLock . release ( )
return
2008-04-08 23:22:53 +04:00
2009-03-09 23:16:45 +03:00
self . detectThread = threading . Thread ( target = self . do_detect ,
name = " Detect OS " )
self . detectThread . setDaemon ( True )
self . detectThreadLock . release ( )
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
self . detectThread . start ( )
2007-06-22 21:32:13 +04:00
2009-03-09 23:16:45 +03:00
def set_distro_labels ( self , distro , ver ) :
# Helper to set auto detect result labels
if not self . is_detect_active ( ) :
return
2008-08-25 23:00:11 +04:00
2009-03-09 23:16:45 +03:00
self . window . get_widget ( " install-os-type-label " ) . set_text ( distro )
self . window . get_widget ( " install-os-version-label " ) . set_text ( ver )
2007-03-28 23:27:19 +04:00
2009-03-09 23:16:45 +03:00
def set_os_val ( self , os_widget , value ) :
# Helper method to set the OS Type/Variant selections to the passed
# values, or -1 if not present.
model = os_widget . get_model ( )
idx = 0
2007-06-22 21:32:13 +04:00
2009-03-09 23:16:45 +03:00
for idx in range ( 0 , len ( model ) ) :
row = model [ idx ]
if row [ 0 ] == value :
break
2007-03-21 19:28:36 +03:00
2009-03-09 23:16:45 +03:00
if idx == len ( os_widget . get_model ( ) ) - 1 :
idx = - 1
2008-03-14 17:55:12 +03:00
2009-03-09 23:16:45 +03:00
os_widget . set_active ( idx )
2008-03-14 20:18:44 +03:00
2009-03-09 23:16:45 +03:00
if idx > = 0 :
return row [ 1 ]
else :
return value
2007-04-15 21:41:12 +04:00
2009-03-09 23:16:45 +03:00
def set_distro_selection ( self , distro , ver ) :
# Wrapper to change OS Type/Variant values, and update the distro
# detection labels
if not self . is_detect_active ( ) :
2007-04-23 23:08:56 +04:00
return
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
if not distro :
distro = _ ( " Unknown " )
ver = _ ( " Unknown " )
elif not ver :
ver = _ ( " Unknown " )
2007-03-21 19:28:36 +03:00
2009-03-09 23:16:45 +03:00
dl = self . set_os_val ( self . window . get_widget ( " install-os-type " ) ,
distro )
vl = self . set_os_val ( self . window . get_widget ( " install-os-version " ) ,
ver )
self . set_distro_labels ( dl , vl )
2007-02-19 19:52:37 +03:00
2009-03-09 23:16:45 +03:00
def _safe_wrapper ( self , func , args ) :
gtk . gdk . threads_enter ( )
try :
return func ( * args )
finally :
gtk . gdk . threads_leave ( )
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
def _set_forward_sensitive ( self , val ) :
self . window . get_widget ( " create-forward " ) . set_sensitive ( val )
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
# The actual detection routine
def do_detect ( self ) :
try :
media = self . _safe_wrapper ( self . get_config_detectable_media , ( ) )
if not media :
return
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
self . detectedDistro = None
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
logging . debug ( " Starting OS detection thread for media= %s " % media )
self . _safe_wrapper ( self . _set_forward_sensitive , ( False , ) )
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
detectThread = threading . Thread ( target = self . actually_detect ,
name = " Actual media detection " ,
args = ( media , ) )
detectThread . setDaemon ( True )
detectThread . start ( )
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
base = _ ( " Detecting " )
for i in range ( 1 , DETECT_TIMEOUT * 2 ) :
if self . detectedDistro != None :
break
detect_str = base + ( " . " * ( ( ( i + 2 ) % 3 ) + 1 ) )
self . _safe_wrapper ( self . set_distro_labels ,
( detect_str , detect_str ) )
time . sleep ( .5 )
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
results = self . detectedDistro
if results == None :
results = ( None , None )
2007-02-20 07:11:21 +03:00
2009-03-09 23:16:45 +03:00
self . _safe_wrapper ( self . set_distro_selection , results )
finally :
self . _clear_detect_thread ( )
self . _safe_wrapper ( self . _set_forward_sensitive , ( True , ) )
logging . debug ( " Leaving OS detection thread. " )
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
return
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
def actually_detect ( self , media ) :
try :
installer = self . build_installer ( virtinst . DistroInstaller )
installer . location = media
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
self . detectedDistro = installer . detect_distro ( )
except :
logging . exception ( " Error detecting distro. " )
self . detectedDistro = ( None , None )
2008-03-10 01:18:33 +03:00
2009-06-24 03:30:12 +04:00
def _browse_file ( self , dialog_name , callback , folder = None , is_media = False ) :
2009-06-18 18:40:37 +04:00
if self . storage_browser == None :
2009-06-24 03:30:12 +04:00
self . storage_browser = vmmStorageBrowser ( self . config , self . conn ,
is_media )
2009-09-14 18:39:57 +04:00
self . storage_browser . set_finish_cb ( callback )
2009-06-24 03:30:12 +04:00
if is_media :
reason = self . config . CONFIG_DIR_MEDIA
else :
reason = self . config . CONFIG_DIR_IMAGE
2009-06-18 18:40:37 +04:00
self . storage_browser . local_args = { " dialog_name " : dialog_name ,
2009-06-24 03:30:12 +04:00
" start_folder " : folder ,
" browse_reason " : reason }
2009-06-18 18:40:37 +04:00
self . storage_browser . show ( self . conn )
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
def show_help ( self , ignore ) :
# No help available yet.
pass
2008-03-10 01:18:33 +03:00
2009-03-09 23:16:45 +03:00
def verr ( self , msg , extra = None ) :
return self . err . val_err ( msg , extra )
2007-03-20 03:17:30 +03:00
2007-04-12 23:35:09 +04:00
gobject . type_register ( vmmCreate )