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