2014-01-20 20:09:13 +04:00
# Copyright (C) 2008, 2013, 2014 Red Hat, Inc.
2008-08-15 19:24:24 +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:24:24 +04:00
2012-05-14 17:24:56 +04:00
from gi . repository import Gtk
2011-04-18 20:39:53 +04:00
2019-06-17 04:12:39 +03:00
from virtinst import log
2024-02-27 01:31:05 +03:00
from virtinst import StorageVolume , StoragePool
2016-12-13 20:36:49 +03:00
2019-06-17 05:19:17 +03:00
from . lib import uiutil
2014-09-13 00:10:45 +04:00
from . asyncjob import vmmAsyncJob
2019-05-04 22:42:54 +03:00
from . baseclass import vmmGObjectUI
from . xmleditor import vmmXMLEditor
2008-08-15 19:24:24 +04:00
2013-04-13 22:34:52 +04:00
2010-12-09 01:26:19 +03:00
class vmmCreateVolume ( vmmGObjectUI ) :
2012-05-14 17:24:56 +04:00
__gsignals__ = {
2020-09-01 19:35:26 +03:00
" vol-created " : ( vmmGObjectUI . RUN_FIRST , None , [ object , object ] ) ,
2012-05-14 17:24:56 +04:00
}
2010-12-09 01:26:19 +03:00
def __init__ ( self , conn , parent_pool ) :
2013-09-23 00:10:16 +04:00
vmmGObjectUI . __init__ ( self , " createvol.ui " , " vmm-create-vol " )
2008-08-15 19:24:24 +04:00
self . conn = conn
2019-05-04 22:11:49 +03:00
self . _parent_pool = parent_pool
self . _name_hint = None
self . _storage_browser = None
2008-08-15 19:24:24 +04:00
2019-05-04 22:42:54 +03:00
self . _xmleditor = vmmXMLEditor ( self . builder , self . topwin ,
self . widget ( " details-box-align " ) ,
self . widget ( " details-box " ) )
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_vmm_create_vol_delete_event " : self . close ,
" on_vol_cancel_clicked " : self . close ,
2019-05-04 22:11:49 +03:00
" on_vol_create_clicked " : self . _create_clicked_cb ,
" on_vol_name_changed " : self . _vol_name_changed_cb ,
" on_vol_format_changed " : self . _vol_format_changed_cb ,
" on_backing_browse_clicked " : self . _browse_backing_clicked_cb ,
2008-08-15 19:24:24 +04:00
} )
2011-04-18 19:25:28 +04:00
self . bind_escape_key_close ( )
2008-08-15 19:24:24 +04:00
2013-09-22 20:18:49 +04:00
self . _init_state ( )
2008-08-15 19:24:24 +04:00
2019-05-04 22:11:49 +03:00
#######################
# Standard UI methods #
#######################
2011-04-14 16:47:42 +04:00
def show ( self , parent ) :
2015-08-10 23:45:44 +03:00
try :
2019-05-04 22:11:49 +03:00
parent_xml = self . _parent_pool . xmlobj . get_xml ( )
2020-08-22 19:07:57 +03:00
except Exception : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . debug ( " Error getting parent_pool xml " , exc_info = True )
2015-08-10 23:45:44 +03:00
parent_xml = None
2019-06-17 04:12:39 +03:00
log . debug ( " Showing new volume wizard for parent_pool= \n %s " ,
2015-08-10 23:45:44 +03:00
parent_xml )
2019-05-04 22:11:49 +03:00
self . _reset_state ( )
2011-04-14 16:47:42 +04:00
self . topwin . set_transient_for ( parent )
2008-08-15 19:24:24 +04:00
self . topwin . present ( )
def close ( self , ignore1 = None , ignore2 = None ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Closing new volume wizard " )
2008-08-15 19:24:24 +04:00
self . topwin . hide ( )
2019-05-04 22:11:49 +03:00
if self . _storage_browser :
self . _storage_browser . close ( )
2009-03-08 22:16:47 +03:00
self . set_modal ( False )
2008-08-15 19:24:24 +04:00
return 1
2011-07-24 05:16:54 +04:00
def _cleanup ( self ) :
self . conn = None
2019-05-04 22:11:49 +03:00
self . _parent_pool = None
2019-05-04 22:42:54 +03:00
self . _xmleditor . cleanup ( )
self . _xmleditor = None
2019-05-04 22:11:49 +03:00
if self . _storage_browser :
self . _storage_browser . cleanup ( )
self . _storage_browser = None
2011-04-12 02:35:21 +04:00
2019-05-04 22:11:49 +03:00
##############
# Public API #
##############
2013-09-29 18:53:37 +04:00
2009-11-15 23:57:38 +03:00
def set_name_hint ( self , hint ) :
2019-05-04 22:11:49 +03:00
self . _name_hint = hint
2009-11-15 23:57:38 +03:00
2009-03-08 22:16:47 +03:00
def set_modal ( self , modal ) :
self . topwin . set_modal ( bool ( modal ) )
2020-08-22 19:07:57 +03:00
def set_parent_pool ( self , pool ) :
2019-05-04 22:11:49 +03:00
self . _parent_pool = pool
2010-02-22 16:49:21 +03:00
2009-11-15 23:57:38 +03:00
2019-05-04 22:11:49 +03:00
###########
# UI init #
###########
2009-11-15 23:57:38 +03:00
2013-09-22 20:18:49 +04:00
def _init_state ( self ) :
format_list = self . widget ( " vol-format " )
format_model = Gtk . ListStore ( str , str )
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:00:14 +03:00
for fmt in [ " raw " , " qcow2 " ] :
format_model . append ( [ fmt , fmt ] )
2013-09-22 20:18:49 +04:00
2019-05-04 22:11:49 +03:00
def _reset_state ( self ) :
2019-05-04 22:42:54 +03:00
self . _xmleditor . reset_state ( )
2019-05-04 22:11:49 +03:00
vol = self . _make_stub_vol ( )
2013-09-22 20:18:49 +04:00
2019-07-02 23:56:35 +03:00
hasformat = vol . supports_format ( )
2014-01-27 03:15:50 +04:00
uiutil . set_grid_row_visible ( self . widget ( " vol-format " ) , hasformat )
2018-09-06 03:00:14 +03:00
uiutil . set_list_selection ( self . widget ( " vol-format " ) ,
self . conn . get_default_storage_format ( ) )
2008-08-15 19:24:24 +04:00
2019-05-04 23:26:15 +03:00
self . widget ( " vol-name " ) . set_text ( self . _default_vol_name ( ) or " " )
self . widget ( " vol-name " ) . grab_focus ( )
self . widget ( " vol-name " ) . emit ( " changed " )
2013-10-01 22:49:19 +04:00
self . widget ( " backing-store " ) . set_text ( " " )
2020-09-20 23:44:52 +03:00
self . widget ( " vol-nonsparse " ) . set_active (
not self . _should_default_sparse ( ) )
self . _show_sparse ( )
2013-10-01 22:49:19 +04:00
self . _show_backing ( )
2013-09-29 18:53:37 +04:00
self . widget ( " backing-expander " ) . set_expanded ( False )
2013-03-13 18:29:22 +04:00
2020-09-20 23:44:52 +03:00
pool_avail = int ( self . _parent_pool . get_available ( ) / 1024 / 1024 / 1024 )
default_cap = 20
2015-04-11 21:56:23 +03:00
self . widget ( " vol-capacity " ) . set_range ( 0.1 , 1000000 )
2020-09-20 23:44:52 +03:00
self . widget ( " vol-capacity " ) . set_value ( min ( default_cap , pool_avail ) )
2008-08-15 19:24:24 +04:00
2020-09-17 09:43:58 +03:00
self . widget ( " vol-parent-info " ) . set_markup (
_ ( " <b> %(volume)s ' s</b> available space: %(size)s " ) % {
" volume " : self . _parent_pool . get_name ( ) ,
" size " : self . _parent_pool . get_pretty_available ( ) ,
} )
2019-05-04 22:11:49 +03:00
2008-08-15 19:24:24 +04:00
2019-05-04 22:11:49 +03:00
###################
# Helper routines #
###################
def _get_config_format ( self ) :
2019-02-03 20:37:41 +03:00
if not self . widget ( " vol-format " ) . get_visible ( ) :
2018-09-06 03:00:14 +03:00
return None
2015-05-20 00:17:53 +03:00
return uiutil . get_list_selection ( self . widget ( " vol-format " ) )
2008-08-15 19:24:24 +04:00
2019-05-04 22:11:49 +03:00
def _default_vol_name ( self ) :
2019-05-04 23:26:15 +03:00
hint = self . _name_hint or " vol "
2019-05-04 22:11:49 +03:00
suffix = self . _default_suffix ( )
ret = " "
try :
ret = StorageVolume . find_free_name (
2019-06-11 15:52:12 +03:00
self . conn . get_backend ( ) ,
2019-05-04 22:11:49 +03:00
self . _parent_pool . get_backend ( ) ,
2019-05-04 23:26:15 +03:00
hint , suffix = suffix )
if ret and suffix :
ret = ret . rsplit ( " . " , 1 ) [ 0 ]
2020-08-22 19:07:57 +03:00
except Exception : # pragma: no cover
2019-06-17 04:12:39 +03:00
log . exception ( " Error finding a default vol name " )
2009-10-05 19:34:39 +04:00
2019-05-04 22:11:49 +03:00
return ret
2009-10-05 19:50:10 +04:00
2019-05-04 22:11:49 +03:00
def _default_suffix ( self ) :
vol = self . _make_stub_vol ( )
if vol . file_type != vol . TYPE_FILE :
return " "
return StorageVolume . get_file_extension_for_format (
self . _get_config_format ( ) )
2009-10-05 19:50:10 +04:00
2020-09-20 23:44:52 +03:00
def _should_default_sparse ( self ) :
return self . _get_config_format ( ) == " qcow2 "
2009-10-05 19:50:10 +04:00
2020-09-20 23:44:52 +03:00
def _can_sparse ( self ) :
dtype = self . _parent_pool . xmlobj . get_disk_type ( )
2024-02-27 01:31:05 +03:00
ptype = self . _parent_pool . xmlobj . type
return ( dtype == StorageVolume . TYPE_FILE or
ptype in [ StoragePool . TYPE_ZFS ] )
2019-05-04 22:11:49 +03:00
2020-09-20 23:44:52 +03:00
def _show_sparse ( self ) :
2019-05-04 22:11:49 +03:00
uiutil . set_grid_row_visible (
2020-09-20 23:44:52 +03:00
self . widget ( " vol-nonsparse " ) , self . _can_sparse ( ) )
2019-05-04 22:11:49 +03:00
def _can_backing ( self ) :
if self . _parent_pool . get_type ( ) == " logical " :
return True
if self . _get_config_format ( ) == " qcow2 " :
return True
return False
def _show_backing ( self ) :
uiutil . set_grid_row_visible (
self . widget ( " backing-expander " ) , self . _can_backing ( ) )
def _browse_file ( self ) :
if self . _storage_browser is None :
def cb ( src , text ) :
ignore = src
self . widget ( " backing-store " ) . set_text ( text )
from . storagebrowse import vmmStorageBrowser
self . _storage_browser = vmmStorageBrowser ( self . conn )
self . _storage_browser . set_finish_cb ( cb )
self . _storage_browser . topwin . set_modal ( self . topwin . get_modal ( ) )
self . _storage_browser . set_browse_reason (
2022-12-13 23:09:35 +03:00
vmmStorageBrowser . REASON_IMAGE )
2019-05-04 22:11:49 +03:00
self . _storage_browser . show ( self . topwin )
2009-10-05 19:50:10 +04:00
2019-05-04 22:11:49 +03:00
def _show_err ( self , info , details = None ) :
self . err . show_err ( info , details , modal = self . topwin . get_modal ( ) )
###################
# Object building #
###################
2019-05-04 22:42:54 +03:00
def _make_stub_vol ( self , xml = None ) :
vol = StorageVolume ( self . conn . get_backend ( ) , parsexml = xml )
2019-05-04 22:11:49 +03:00
vol . pool = self . _parent_pool . get_backend ( )
return vol
2019-05-04 22:42:54 +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:42:54 +03:00
return self . _make_stub_vol ( xml = xml )
def _build_xmlobj_from_ui ( self ) :
2019-05-04 22:11:49 +03:00
name = self . widget ( " vol-name " ) . get_text ( )
suffix = self . widget ( " vol-name-suffix " ) . get_text ( )
volname = name + suffix
fmt = self . _get_config_format ( )
cap = self . widget ( " vol-capacity " ) . get_value ( )
2020-09-20 23:44:52 +03:00
nonsparse = self . widget ( " vol-nonsparse " ) . get_active ( )
2019-05-04 22:11:49 +03:00
backing = self . widget ( " backing-store " ) . get_text ( )
2020-09-20 23:44:52 +03:00
alloc = 0
if nonsparse :
2019-05-04 22:11:49 +03:00
alloc = cap
2009-10-05 19:50:10 +04:00
2019-05-04 22:42:54 +03:00
vol = self . _make_stub_vol ( )
vol . name = volname
vol . capacity = ( cap * 1024 * 1024 * 1024 )
vol . allocation = ( alloc * 1024 * 1024 * 1024 )
if backing :
vol . backing_store = backing
if fmt :
vol . format = fmt
2019-05-04 22:11:49 +03:00
return vol
2009-10-05 19:50:10 +04:00
2019-05-04 22:42:54 +03:00
def _build_xmlobj ( self , check_xmleditor ) :
try :
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 ) )
2013-09-29 18:53:37 +04:00
2019-05-04 22:11:49 +03:00
##################
# Object install #
##################
2013-09-29 18:53:37 +04:00
2019-05-04 22:11:49 +03:00
def _pool_refreshed_cb ( self , pool , volname ) :
2020-09-01 19:35:26 +03:00
vol = pool . get_volume_by_name ( volname )
self . emit ( " vol-created " , pool , vol )
2015-04-09 21:42:25 +03:00
2019-05-04 22:11:49 +03:00
def _finish_cb ( self , error , details , vol ) :
2017-04-27 22:00:17 +03:00
self . reset_finish_cursor ( )
2013-09-07 04:59:01 +04:00
2020-08-22 19:07:57 +03:00
if error : # pragma: no cover
2013-09-07 04:59:01 +04:00
error = _ ( " Error creating vol: %s " ) % error
2019-05-04 22:11:49 +03:00
self . _show_err ( error , details = details )
2020-08-22 19:07:57 +03:00
return
self . _parent_pool . connect ( " refreshed " ,
self . _pool_refreshed_cb , vol . name )
self . idle_add ( self . _parent_pool . refresh )
self . close ( )
2013-09-07 04:59:01 +04:00
2019-05-04 22:11:49 +03:00
def _finish ( self ) :
2019-05-04 22:42:54 +03:00
vol = self . _build_xmlobj ( check_xmleditor = True )
2019-05-04 22:11:49 +03:00
if not vol :
return
2008-08-15 19:24:24 +04:00
try :
2019-05-04 22:11:49 +03:00
vol . validate ( )
2017-05-05 19:47:21 +03:00
except Exception as e :
2019-05-04 22:11:49 +03:00
return self . _show_err ( _ ( " Error validating volume: %s " ) % str ( e ) )
2008-08-15 19:24:24 +04:00
2017-04-27 22:00:17 +03:00
self . set_finish_cursor ( )
2019-05-04 22:11:49 +03:00
progWin = vmmAsyncJob ( self . _async_vol_create , [ vol ] ,
self . _finish_cb , [ vol ] ,
2010-12-10 17:57:42 +03:00
_ ( " Creating storage volume... " ) ,
_ ( " Creating the storage volume may take a "
2011-04-14 16:47:42 +04:00
" while... " ) ,
self . topwin )
2013-09-07 04:59:01 +04:00
progWin . run ( )
2008-08-15 19:24:24 +04:00
2019-05-04 22:11:49 +03:00
def _async_vol_create ( self , asyncjob , vol ) :
2013-07-05 16:59:58 +04:00
conn = self . conn . get_backend ( )
2008-08-15 19:24:24 +04:00
2010-12-10 17:57:42 +03:00
# Lookup different pool obj
2019-05-04 22:11:49 +03:00
newpool = conn . storagePoolLookupByName ( self . _parent_pool . get_name ( ) )
vol . pool = newpool
2008-08-15 19:24:24 +04:00
2012-02-10 19:24:43 +04:00
meter = asyncjob . get_meter ( )
2019-06-17 04:12:39 +03:00
log . debug ( " Starting background vol creation. " )
2019-05-04 22:11:49 +03:00
vol . install ( meter = meter )
2019-06-17 04:12:39 +03:00
log . debug ( " vol creation complete. " )
2008-08-15 19:24:24 +04:00
2019-05-04 22:11:49 +03:00
################
# UI listeners #
################
2019-05-04 22:42:54 +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 22:11:49 +03:00
def _vol_format_changed_cb ( self , src ) :
2020-09-20 23:44:52 +03:00
self . _show_sparse ( )
self . widget ( " vol-nonsparse " ) . set_active (
not self . _should_default_sparse ( ) )
2019-05-04 22:11:49 +03:00
self . _show_backing ( )
self . widget ( " vol-name " ) . emit ( " changed " )
def _vol_name_changed_cb ( self , src ) :
text = src . get_text ( )
2013-09-29 18:53:37 +04:00
2019-05-04 22:11:49 +03:00
suffix = self . _default_suffix ( )
if " . " in text :
suffix = " "
self . widget ( " vol-name-suffix " ) . set_text ( suffix )
def _browse_backing_clicked_cb ( self , src ) :
self . _browse_file ( )
def _create_clicked_cb ( self , src ) :
self . _finish ( )