Files
virt-manager/virtManager/createpool.py
T

407 lines
13 KiB
Python
Raw Normal View History

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>
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
2008-08-15 11:22:20 -04:00
import os
from gi.repository import Gtk
2008-08-15 11:22:20 -04:00
from virtinst import log
2016-12-13 12:36:49 -05:00
from virtinst import StoragePool
from .lib import uiutil
2019-05-04 15:03:36 -04:00
from .asyncjob import vmmAsyncJob
from .baseclass import vmmGObjectUI
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,
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,
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
})
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):
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):
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)
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):
format_list = self.widget("pool-format")
format_model = Gtk.ListStore(str, str)
2008-08-15 11:22:20 -04:00
format_list.set_model(format_model)
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)
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)
source_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
2009-10-19 15:55:19 -04:00
source_list.set_model(source_model)
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)
self.widget("pool-name").grab_focus()
2019-06-16 20:10:37 -04:00
self.widget("pool-target-path").set_text("")
self.widget("pool-source-path").get_child().set_text("")
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()
source_list = self.widget("pool-source-path")
2019-06-16 20:10:37 -04:00
source_list.get_model().clear()
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]
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:
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):
scsi_hosts = self.conn.filter_nodedevs("scsi_host")
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):
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
log.exception("Pool enumeration failed")
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):
def show_row(base, do_show):
widget = self.widget(base + "-label")
2014-01-26 18:15:50 -05:00
uiutil.set_grid_row_visible(widget, do_show)
2019-05-04 14:37:56 -04:00
pool = self._make_stub_pool()
src = pool.supports_source_path()
2013-09-19 20:18:12 -04:00
src_b = src and not self.conn.is_remote()
tgt = pool.supports_target_path()
2013-09-19 20:18:12 -04:00
tgt_b = tgt and not self.conn.is_remote()
host = pool.supports_hosts()
fmt = pool.supports_format()
iqn = pool.supports_iqn()
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]:
src_b = False
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)
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:")
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-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
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(
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():
return None
2019-07-03 17:15:07 -04:00
if column is None:
return widget.get_text().strip()
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):
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
2019-05-04 14:37:56 -04:00
###################
# Object building #
###################
2019-05-04 15:03:36 -04:00
def _build_xmlobj_from_xmleditor(self):
xml = self._xmleditor.get_xml()
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
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()
2019-05-04 14:37:56 -04:00
def _async_pool_create(self, asyncjob, pool, build):
meter = asyncjob.get_meter()
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)
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:
2019-05-04 15:03:36 -04:00
if self._validate(pool) is False:
2019-05-04 14:37:56 -04:00
return
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):
source = self.err.browse_local(self.conn,
_("Choose source path"),
dialog_type=Gtk.FileChooserAction.OPEN,
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()
startfolder = None
if current:
startfolder = os.path.dirname(current)
2019-05-04 14:37:56 -04:00
target = self.err.browse_local(self.conn,
_("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())