2014-06-11 13:36:28 +02:00
# Copyright (C) 2008, 2013, 2014 Red Hat, Inc.
2008-08-15 11:22:20 -04:00
# Copyright (C) 2008 Cole Robinson <crobinso@redhat.com>
#
2018-04-04 14:35:41 +01:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 15:00:02 -04:00
# See the COPYING file in the top-level directory.
2008-08-15 11:22:20 -04:00
2019-06-11 08:23:59 -04:00
import os
2016-06-07 17:33:21 +02:00
2015-04-09 14:42:25 -04:00
from gi . repository import Gtk
2008-08-15 11:22:20 -04:00
2019-06-16 21:12:39 -04:00
from virtinst import log
2016-12-13 12:36:49 -05:00
from virtinst import StoragePool
2019-06-16 22:19:17 -04:00
from . lib import uiutil
2019-05-04 15:03:36 -04:00
from . asyncjob import vmmAsyncJob
from . baseclass import vmmGObjectUI
2019-07-02 16:29:16 -04:00
from . object . storagepool import vmmStoragePool
2019-05-04 15:03:36 -04:00
from . xmleditor import vmmXMLEditor
2008-08-15 11:22:20 -04:00
2013-04-13 14:34:52 -04:00
2010-12-08 17:26:19 -05:00
class vmmCreatePool ( vmmGObjectUI ) :
def __init__ ( self , conn ) :
2013-09-22 16:10:16 -04:00
vmmGObjectUI . __init__ ( self , " createpool.ui " , " vmm-create-pool " )
2008-08-15 11:22:20 -04:00
self . conn = conn
2019-05-04 15:03:36 -04:00
self . _xmleditor = vmmXMLEditor ( self . builder , self . topwin ,
self . widget ( " pool-details-align " ) ,
self . widget ( " pool-details " ) )
self . _xmleditor . connect ( " xml-requested " ,
self . _xmleditor_xml_requested_cb )
2013-02-16 13:31:46 -05:00
self . builder . connect_signals ( {
2017-08-05 14:39:32 +08:00
" on_pool_cancel_clicked " : self . close ,
" on_vmm_create_pool_delete_event " : self . close ,
2019-05-04 14:37:56 -04:00
" on_pool_finish_clicked " : self . _finish_clicked_cb ,
2019-05-04 13:08:06 -04:00
" on_pool_type_changed " : self . _pool_type_changed_cb ,
2013-09-27 12:13:01 -04:00
2019-05-04 14:37:56 -04:00
" on_pool_source_button_clicked " : self . _browse_source_cb ,
" on_pool_target_button_clicked " : self . _browse_target_cb ,
2009-01-25 15:41:44 -05:00
2019-05-04 14:37:56 -04:00
" on_pool_iqn_chk_toggled " : self . _iqn_toggled_cb ,
2008-08-15 11:22:20 -04:00
} )
2011-04-18 11:25:28 -04:00
self . bind_escape_key_close ( )
2008-08-15 11:22:20 -04:00
2019-05-04 14:37:56 -04:00
self . _init_ui ( )
#######################
# Standard UI methods #
#######################
2008-08-15 11:22:20 -04:00
2011-04-14 08:47:42 -04:00
def show ( self , parent ) :
2019-06-16 21:12:39 -04:00
log . debug ( " Showing new pool wizard " )
2019-05-04 14:37:56 -04:00
self . _reset_state ( )
2011-04-14 08:47:42 -04:00
self . topwin . set_transient_for ( parent )
2008-08-15 11:22:20 -04:00
self . topwin . present ( )
def close ( self , ignore1 = None , ignore2 = None ) :
2019-06-16 21:12:39 -04:00
log . debug ( " Closing new pool wizard " )
2008-08-15 11:22:20 -04:00
self . topwin . hide ( )
return 1
2011-07-23 21:16:54 -04:00
def _cleanup ( self ) :
2011-04-13 09:27:02 -04:00
self . conn = None
2019-05-04 15:03:36 -04:00
self . _xmleditor . cleanup ( )
self . _xmleditor = None
2019-05-04 14:37:56 -04:00
###########
# UI init #
###########
2011-04-13 09:27:02 -04:00
2019-05-04 13:08:06 -04:00
def _build_pool_type_list ( self ) :
# [pool type, label]
model = Gtk . ListStore ( str , str )
type_list = self . widget ( " pool-type " )
type_list . set_model ( model )
uiutil . init_combo_text_column ( type_list , 1 )
2019-07-02 16:29:16 -04:00
for typ in vmmStoragePool . list_types ( ) :
desc = vmmStoragePool . pretty_type ( typ )
2019-05-04 13:08:06 -04:00
model . append ( [ typ , " %s : %s " % ( typ , desc ) ] )
2019-05-04 14:37:56 -04:00
def _init_ui ( self ) :
2011-07-14 13:13:13 -04:00
format_list = self . widget ( " pool-format " )
2012-05-14 14:24:56 +01:00
format_model = Gtk . ListStore ( str , str )
2008-08-15 11:22:20 -04:00
format_list . set_model ( format_model )
2015-04-10 13:04:02 -04:00
uiutil . init_combo_text_column ( format_list , 1 )
2018-09-05 20:24:23 -04:00
for f in [ " auto " ] :
format_model . append ( [ f , f ] )
2008-08-15 11:22:20 -04:00
2019-06-16 20:10:37 -04:00
combo = self . widget ( " pool-source-name " )
# [name, label]
model = Gtk . ListStore ( str , str )
model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
combo . set_model ( model )
combo . set_entry_text_column ( 0 )
2011-07-14 13:13:13 -04:00
source_list = self . widget ( " pool-source-path " )
2019-06-16 20:10:37 -04:00
# [source_path, label]
2019-07-03 17:55:01 -04:00
source_model = Gtk . ListStore ( str , str )
2012-05-14 14:24:56 +01:00
source_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2009-10-19 15:55:19 -04:00
source_list . set_model ( source_model )
2013-01-12 16:13:53 -05:00
source_list . set_entry_text_column ( 0 )
2009-10-19 15:55:19 -04:00
2019-05-04 13:08:06 -04:00
self . _build_pool_type_list ( )
2019-05-04 14:37:56 -04:00
def _reset_state ( self ) :
2019-05-04 15:03:36 -04:00
self . _xmleditor . reset_state ( )
2019-05-04 13:08:06 -04:00
defaultname = StoragePool . find_free_name (
self . conn . get_backend ( ) , " pool " )
self . widget ( " pool-name " ) . set_text ( defaultname )
2011-07-14 13:13:13 -04:00
self . widget ( " pool-name " ) . grab_focus ( )
2019-06-16 20:10:37 -04:00
self . widget ( " pool-target-path " ) . set_text ( " " )
2012-05-14 14:24:56 +01:00
self . widget ( " pool-source-path " ) . get_child ( ) . set_text ( " " )
2011-07-14 13:13:13 -04:00
self . widget ( " pool-hostname " ) . set_text ( " " )
2011-07-23 19:42:41 -04:00
self . widget ( " pool-iqn-chk " ) . set_active ( False )
self . widget ( " pool-iqn-chk " ) . toggled ( )
self . widget ( " pool-iqn " ) . set_text ( " " )
2018-09-05 20:24:23 -04:00
self . widget ( " pool-format " ) . set_active ( 0 )
2008-08-15 11:22:20 -04:00
2019-05-04 13:08:06 -04:00
uiutil . set_list_selection ( self . widget ( " pool-type " ) , 0 )
2019-05-04 14:37:56 -04:00
self . _show_options_by_pool ( )
2008-08-15 11:22:20 -04:00
2009-10-21 09:48:12 -04:00
2019-05-04 14:37:56 -04:00
#################
# UI populating #
#################
2011-07-23 19:42:41 -04:00
2019-05-04 14:37:56 -04:00
def _populate_pool_sources ( self ) :
pooltype = self . _get_config_pool_type ( )
2011-07-14 13:13:13 -04:00
source_list = self . widget ( " pool-source-path " )
2019-06-16 20:10:37 -04:00
source_list . get_model ( ) . clear ( )
2009-10-20 21:12:35 -04:00
2019-06-16 20:10:37 -04:00
name_list = self . widget ( " pool-source-name " )
name_list . get_model ( ) . clear ( )
2009-10-19 15:55:19 -04:00
2019-05-04 14:37:56 -04:00
if pooltype == StoragePool . TYPE_SCSI :
2019-07-03 17:55:01 -04:00
host_list = self . _list_scsi_adapters ( )
entry_list = [ [ h , h ] for h in host_list ]
2009-10-20 21:12:35 -04:00
use_list = source_list
2019-05-04 14:37:56 -04:00
elif pooltype == StoragePool . TYPE_LOGICAL :
2019-07-03 17:55:01 -04:00
vglist = self . _list_pool_sources ( pooltype )
2019-06-16 20:10:37 -04:00
entry_list = [ [ v , v ] for v in vglist ]
use_list = name_list
2009-10-19 15:55:19 -04:00
2019-06-16 20:10:37 -04:00
else :
return
2009-10-19 15:55:19 -04:00
2019-06-16 20:10:37 -04:00
for e in entry_list :
use_list . get_model ( ) . append ( e )
2009-10-19 15:55:19 -04:00
if entry_list :
2009-10-20 21:12:35 -04:00
use_list . set_active ( 0 )
2009-10-19 15:55:19 -04:00
2019-05-04 14:37:56 -04:00
def _list_scsi_adapters ( self ) :
2015-04-10 09:37:03 -04:00
scsi_hosts = self . conn . filter_nodedevs ( " scsi_host " )
2015-04-07 14:12:00 -04:00
host_list = [ dev . xmlobj . host for dev in scsi_hosts ]
2019-07-03 17:55:01 -04:00
return [ " host %s " % h for h in host_list ]
2009-10-19 15:55:19 -04:00
2019-07-03 17:55:01 -04:00
def _list_pool_sources ( self , pool_type ) :
2009-10-20 21:12:35 -04:00
plist = [ ]
try :
2013-09-19 20:18:12 -04:00
plist = StoragePool . pool_list_from_sources (
2019-07-03 17:55:01 -04:00
self . conn . get_backend ( ) , pool_type )
2019-07-03 18:26:57 -04:00
except Exception : # pragma: no cover
2019-06-16 21:12:39 -04:00
log . exception ( " Pool enumeration failed " )
2009-10-20 21:12:35 -04:00
return plist
2019-05-04 14:37:56 -04:00
def _get_build_default ( self , pooltype ) :
if pooltype in [ StoragePool . TYPE_DIR ,
StoragePool . TYPE_FS ,
StoragePool . TYPE_NETFS ] :
# Building for these simply entails creating a directory
2020-08-20 14:03:57 -04:00
return True
return False
2019-05-04 14:37:56 -04:00
def _show_options_by_pool ( self ) :
2011-07-23 16:22:02 -04:00
def show_row ( base , do_show ) :
2013-09-27 12:13:01 -04:00
widget = self . widget ( base + " -label " )
2014-01-26 18:15:50 -05:00
uiutil . set_grid_row_visible ( widget , do_show )
2011-07-23 16:22:02 -04:00
2019-05-04 14:37:56 -04:00
pool = self . _make_stub_pool ( )
2019-07-02 17:03:39 -04:00
src = pool . supports_source_path ( )
2013-09-19 20:18:12 -04:00
src_b = src and not self . conn . is_remote ( )
2019-07-02 17:03:39 -04:00
tgt = pool . supports_target_path ( )
2013-09-19 20:18:12 -04:00
tgt_b = tgt and not self . conn . is_remote ( )
2019-07-02 17:03:39 -04:00
host = pool . supports_hosts ( )
fmt = pool . supports_format ( )
iqn = pool . supports_iqn ( )
2009-10-20 16:53:13 -04:00
2019-06-16 20:10:37 -04:00
src_name = pool . supports_source_name ( )
is_lvm = pool . type == StoragePool . TYPE_LOGICAL
is_scsi = pool . type == StoragePool . TYPE_SCSI
2014-12-09 16:05:02 -05:00
2014-06-11 13:36:28 +02:00
# Source path browsing is meaningless for net pools
2019-05-04 14:37:56 -04:00
if pool . type in [ StoragePool . TYPE_NETFS ,
2013-09-19 20:18:12 -04:00
StoragePool . TYPE_ISCSI ,
2014-12-09 16:05:02 -05:00
StoragePool . TYPE_SCSI ,
StoragePool . TYPE_GLUSTER ] :
2009-10-20 16:53:13 -04:00
src_b = False
2011-07-23 16:22:02 -04:00
show_row ( " pool-target " , tgt )
show_row ( " pool-source " , src )
show_row ( " pool-hostname " , host )
show_row ( " pool-format " , fmt )
2011-07-23 19:42:41 -04:00
show_row ( " pool-iqn " , iqn )
2014-02-12 11:52:46 +01:00
show_row ( " pool-source-name " , src_name )
2011-07-23 16:22:02 -04:00
2019-06-16 20:10:37 -04:00
self . widget ( " pool-source-name-label " ) . set_label (
is_lvm and _ ( " Volg_roup Name: " ) or _ ( " Sou_rce Name: " ) )
src_label = _ ( " _Source Path: " )
2014-04-03 11:19:03 -04:00
if iqn :
2019-06-16 20:10:37 -04:00
src_label = _ ( " _Source IQN: " )
elif is_scsi :
src_label = _ ( " _Source Adapter: " )
self . widget ( " pool-source-label " ) . set_text ( src_label )
2019-07-03 18:26:57 -04:00
self . widget ( " pool-source-label " ) . set_use_underline ( True )
2014-04-03 11:19:03 -04:00
2014-02-12 10:29:22 +01:00
if tgt :
2019-06-16 20:10:37 -04:00
self . widget ( " pool-target-path " ) . set_text (
2019-05-04 14:37:56 -04:00
pool . default_target_path ( ) or " " )
2014-02-12 10:29:22 +01:00
2011-07-14 13:13:13 -04:00
self . widget ( " pool-target-button " ) . set_sensitive ( tgt_b )
self . widget ( " pool-source-button " ) . set_sensitive ( src_b )
2008-08-15 11:22:20 -04:00
2014-02-12 11:52:46 +01:00
if src_name :
2019-06-16 20:10:37 -04:00
self . widget ( " pool-source-name " ) . get_child ( ) . set_text (
2019-05-21 18:19:05 -04:00
pool . default_source_name ( ) or " " )
2014-02-12 11:52:46 +01:00
2019-05-04 14:37:56 -04:00
self . _populate_pool_sources ( )
2009-10-19 15:55:19 -04:00
2008-08-15 11:22:20 -04:00
2019-05-04 14:37:56 -04:00
################
# UI accessors #
################
2008-08-15 11:22:20 -04:00
2019-07-03 17:15:07 -04:00
def _get_visible_text ( self , widget_name , column = None ) :
widget = self . widget ( widget_name )
if not widget . get_sensitive ( ) or not widget . get_visible ( ) :
2009-10-20 21:12:35 -04:00
return None
2019-07-03 17:15:07 -04:00
if column is None :
return widget . get_text ( ) . strip ( )
2009-10-20 21:12:35 -04:00
2019-07-03 18:26:57 -04:00
return uiutil . get_list_selection ( widget , column = column )
2008-08-15 11:22:20 -04:00
2019-07-03 17:15:07 -04:00
def _get_config_pool_type ( self ) :
return uiutil . get_list_selection ( self . widget ( " pool-type " ) )
2009-10-19 15:55:19 -04:00
2019-07-03 17:15:07 -04:00
def _get_config_target_path ( self ) :
2019-06-16 20:10:37 -04:00
return self . _get_visible_text ( " pool-target-path " )
2019-07-03 17:15:07 -04:00
def _get_config_source_path ( self ) :
return self . _get_visible_text ( " pool-source-path " , column = 1 )
2008-08-15 11:22:20 -04:00
2019-05-04 14:37:56 -04:00
def _get_config_host ( self ) :
2019-07-03 17:15:07 -04:00
return self . _get_visible_text ( " pool-hostname " )
2008-08-15 11:22:20 -04:00
2019-05-04 14:37:56 -04:00
def _get_config_source_name ( self ) :
2019-06-16 20:10:37 -04:00
return self . _get_visible_text ( " pool-source-name " , column = 1 )
2014-02-12 11:52:46 +01:00
2019-05-04 14:37:56 -04:00
def _get_config_format ( self ) :
2015-05-19 17:17:53 -04:00
return uiutil . get_list_selection ( self . widget ( " pool-format " ) )
2008-08-15 11:22:20 -04:00
2019-05-04 14:37:56 -04:00
def _get_config_iqn ( self ) :
2019-07-03 17:15:07 -04:00
return self . _get_visible_text ( " pool-iqn " )
2011-07-23 19:42:41 -04:00
2013-09-27 12:13:01 -04:00
2019-05-04 14:37:56 -04:00
###################
# Object building #
###################
2013-11-27 16:10:34 +01:00
2019-05-04 15:03:36 -04:00
def _build_xmlobj_from_xmleditor ( self ) :
xml = self . _xmleditor . get_xml ( )
2019-06-16 21:12:39 -04:00
log . debug ( " Using XML from xmleditor: \n %s " , xml )
2019-05-04 15:03:36 -04:00
return StoragePool ( self . conn . get_backend ( ) , parsexml = xml )
2013-09-19 20:18:12 -04:00
def _make_stub_pool ( self ) :
2019-07-03 17:55:01 -04:00
pool = StoragePool ( self . conn . get_backend ( ) )
2019-05-04 14:37:56 -04:00
pool . type = self . _get_config_pool_type ( )
pool . name = self . widget ( " pool-name " ) . get_text ( )
2013-09-19 20:18:12 -04:00
return pool
2008-08-15 11:22:20 -04:00
2019-05-04 15:03:36 -04:00
def _build_xmlobj_from_ui ( self ) :
2019-05-04 14:37:56 -04:00
target = self . _get_config_target_path ( )
host = self . _get_config_host ( )
source = self . _get_config_source_path ( )
fmt = self . _get_config_format ( )
iqn = self . _get_config_iqn ( )
source_name = self . _get_config_source_name ( )
2013-09-19 20:18:12 -04:00
2019-05-04 15:03:36 -04:00
pool = self . _make_stub_pool ( )
pool . target_path = target
if host :
hostobj = pool . hosts . add_new ( )
hostobj . name = host
if source :
pool . source_path = source
2019-07-02 17:03:39 -04:00
if fmt and pool . supports_format ( ) :
2019-05-04 15:03:36 -04:00
pool . format = fmt
if iqn :
pool . iqn = iqn
if source_name :
pool . source_name = source_name
return pool
def _build_xmlobj ( self , check_xmleditor ) :
2013-09-19 20:18:12 -04:00
try :
2019-05-04 15:03:36 -04:00
xmlobj = self . _build_xmlobj_from_ui ( )
if check_xmleditor and self . _xmleditor . is_xml_selected ( ) :
xmlobj = self . _build_xmlobj_from_xmleditor ( )
return xmlobj
except Exception as e :
self . err . show_err ( _ ( " Error building XML: %s " ) % str ( e ) )
2019-05-04 13:08:06 -04:00
2019-05-04 15:03:36 -04:00
def _validate ( self , pool ) :
pool . validate ( )
2013-09-19 20:18:12 -04:00
2019-05-04 14:37:56 -04:00
##################
# Object install #
##################
2013-09-19 20:18:12 -04:00
2019-05-04 14:37:56 -04:00
def _finish_cb ( self , error , details , pool ) :
self . reset_finish_cursor ( )
if error :
error = _ ( " Error creating pool: %s " ) % error
self . err . show_err ( error ,
details = details )
else :
self . conn . schedule_priority_tick ( pollpool = True )
self . close ( )
2009-03-08 15:14:00 -04:00
2019-05-04 14:37:56 -04:00
def _async_pool_create ( self , asyncjob , pool , build ) :
meter = asyncjob . get_meter ( )
2019-06-16 21:12:39 -04:00
log . debug ( " Starting background pool creation. " )
2019-05-04 14:37:56 -04:00
poolobj = pool . install ( create = True , meter = meter , build = build )
poolobj . setAutostart ( True )
2019-06-16 21:12:39 -04:00
log . debug ( " Pool creation succeeded " )
2019-05-04 14:37:56 -04:00
def _finish ( self ) :
2019-05-04 15:03:36 -04:00
pool = self . _build_xmlobj ( check_xmleditor = True )
if not pool :
return
2019-05-04 14:37:56 -04:00
try :
2020-08-20 13:34:01 -04:00
self . _validate ( pool )
2020-08-20 14:03:57 -04:00
build = self . _get_build_default ( pool . type )
2019-07-03 18:26:57 -04:00
except Exception as e : # pragma: no cover
return self . err . show_err ( _ ( " Error validating pool: %s " ) % e )
2019-05-04 14:37:56 -04:00
self . reset_finish_cursor ( )
progWin = vmmAsyncJob ( self . _async_pool_create , [ pool , build ] ,
self . _finish_cb , [ pool ] ,
_ ( " Creating storage pool... " ) ,
_ ( " Creating the storage pool may take a "
" while... " ) ,
self . topwin )
progWin . run ( )
################
# UI listeners #
################
2019-05-04 15:03:36 -04:00
def _xmleditor_xml_requested_cb ( self , src ) :
xmlobj = self . _build_xmlobj ( check_xmleditor = False )
self . _xmleditor . set_xml ( xmlobj and xmlobj . get_xml ( ) or " " )
2019-05-04 14:37:56 -04:00
def _finish_clicked_cb ( self , src ) :
self . _finish ( )
def _pool_type_changed_cb ( self , src ) :
self . _show_options_by_pool ( )
def _browse_source_cb ( self , src ) :
2022-12-13 15:09:35 -05:00
source = self . err . browse_local (
2019-05-04 14:37:56 -04:00
_ ( " Choose source path " ) ,
start_folder = " /dev " )
if source :
self . widget ( " pool-source-path " ) . get_child ( ) . set_text ( source )
def _browse_target_cb ( self , src ) :
2019-07-03 17:15:07 -04:00
current = self . _get_config_target_path ( )
2019-06-11 08:23:59 -04:00
startfolder = None
if current :
startfolder = os . path . dirname ( current )
2022-12-13 15:09:35 -05:00
target = self . err . browse_local (
2019-05-04 14:37:56 -04:00
_ ( " Choose target directory " ) ,
dialog_type = Gtk . FileChooserAction . SELECT_FOLDER ,
start_folder = startfolder )
if target :
2019-06-16 20:10:37 -04:00
self . widget ( " pool-target-path " ) . set_text ( target )
2019-05-04 14:37:56 -04:00
def _iqn_toggled_cb ( self , src ) :
self . widget ( " pool-iqn " ) . set_sensitive ( src . get_active ( ) )