Fabian Deutsch has uploaded a new change for review. Change subject: ui: Add and use TransactionProgressDialog ......................................................................
ui: Add and use TransactionProgressDialog To easily track the progress of a transaction relies on proper Transaction.Elements. Change-Id: I7c70f83e8c7705e38eb0cc6f81e46bbba1a42f44 Signed-off-by: Fabian Deutsch <[email protected]> --- M scripts/tui/src/ovirt/node/config/defaults.py M scripts/tui/src/ovirt/node/setup/engine_page.py M scripts/tui/src/ovirt/node/setup/kdump_page.py M scripts/tui/src/ovirt/node/setup/keyboard_page.py M scripts/tui/src/ovirt/node/setup/logging_page.py M scripts/tui/src/ovirt/node/setup/monitoring_page.py M scripts/tui/src/ovirt/node/setup/network_page.py M scripts/tui/src/ovirt/node/setup/remote_storage_page.py M scripts/tui/src/ovirt/node/setup/security_page.py M scripts/tui/src/ovirt/node/setup/snmp_page.py M scripts/tui/src/ovirt/node/ui/__init__.py M scripts/tui/src/ovirt/node/ui/builder.py M scripts/tui/src/ovirt/node/ui/tui.py M scripts/tui/src/ovirt/node/ui/widgets.py M scripts/tui/src/ovirt/node/utils/system.py 15 files changed, 131 insertions(+), 65 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/76/9976/1 diff --git a/scripts/tui/src/ovirt/node/config/defaults.py b/scripts/tui/src/ovirt/node/config/defaults.py index b6084eb..d22bb65 100644 --- a/scripts/tui/src/ovirt/node/config/defaults.py +++ b/scripts/tui/src/ovirt/node/config/defaults.py @@ -323,7 +323,6 @@ def commit(self): utils.AugeasWrapper.force_reload() - tx = utils.Transaction("Applying new network configuration") tx.append(ConfigureNIC()) tx.append(ReloadNetworkConfiguration()) @@ -369,6 +368,8 @@ def __legacy_transaction(self): class ConfigureNameservers(utils.Transaction.Element): + title = "Setting namservers" + def commit(self): import ovirtnode.network as onet net = onet.Network() @@ -405,7 +406,7 @@ servers = servers.split(",") class UpdateResolvConf(utils.Transaction.Element): - title = "Updateing resolv.conf" + title = "Updating resolv.conf" def commit(self): # Write resolv.conf any way, sometimes without servers @@ -474,6 +475,8 @@ def __legacy_transaction(self): class ConfigureTimeservers(utils.Transaction.Element): + title = "Setting timeservers" + def commit(self): import ovirtnode.network as onet net = onet.Network() @@ -512,6 +515,8 @@ server, port = (cfg["server"], cfg["port"]) class CreateRsyslogConfig(utils.Transaction.Element): + title = "Setting syslog server and port" + def commit(self): import ovirtnode.log as olog olog.ovirt_rsyslog(server, port, "udp") @@ -549,6 +554,8 @@ server, port = (cfg["server"], cfg["port"]) class ConfigureCollectd(utils.Transaction.Element): + title = "Setting collect server and port" + def commit(self): import ovirt_config_setup.collectd as ocollectd if ocollectd.write_collectd_config(server, port): @@ -621,6 +628,8 @@ nfs, ssh, restore = (cfg["nfs"], cfg["ssh"], cfg["local"]) class BackupKdumpConfig(utils.Transaction.Element): + title = "Backing up config files" + def __init__(self): self.backups = utils.fs.BackupedFiles(["/etc/kdump.conf"]) @@ -628,16 +637,22 @@ self.backups.create() class RestoreKdumpConfig(utils.Transaction.Element): + title = "Restoring default kdump config" + def commit(self): import ovirtnode.kdump as okdump okdump.restore_kdump_config() class CreateNfsKdumpConfig(utils.Transaction.Element): + title = "Creating kdump NFS config" + def commit(self): import ovirtnode.kdump as okdump okdump.write_kdump_config(nfs) class CreateSshKdumpConfig(utils.Transaction.Element): + title = "Creating kdump SSH config" + def commit(self): import ovirtnode.kdump as okdump from ovirtnode.ovirtfunctions import ovirt_store_config @@ -662,6 +677,8 @@ "SSH: %s" % stdout) class RemoveKdumpConfig(utils.Transaction.Element): + title = "Removing kdump backup" + def __init__(self, backups): self.backups = backups @@ -675,6 +692,8 @@ self.backups.remove() class RestartKdumpService(utils.Transaction.Element): + title = "Restarting kdump service" + def __init__(self, backups): self.backups = backups @@ -705,7 +724,7 @@ tx.append(CreateNfsKdumpConfig()) elif ssh: tx.append(CreateSshKdumpConfig()) - elif restore: + elif restore in [True, False]: tx.append(RestoreKdumpConfig()) else: final_txe = RemoveKdumpConfig(backup_txe.backups) @@ -747,6 +766,8 @@ initiator_name = cfg["name"] class ConfigureIscsiInitiator(utils.Transaction.Element): + title = "Setting the iSCSI initiator name" + def commit(self): iscsi = utils.storage.iSCSI() iscsi.initiator_name(initiator_name) @@ -778,6 +799,8 @@ password = cfg["password"] class ConfigureSNMP(utils.Transaction.Element): + title = "Enabling/Disabling SNMP and setting the password" + def commit(self): # FIXME snmp plugin needs to be placed somewhere else (in src) import ovirt_config_setup.snmp as osnmp @@ -816,6 +839,8 @@ server, port = (cfg["server"], cfg["port"]) class CreateNetconsoleConfig(utils.Transaction.Element): + title = "Setting netconsole server and port" + def commit(self): import ovirtnode.log as olog olog.ovirt_netconsole(server, port, "udp") @@ -848,6 +873,8 @@ max_size = cfg["max_size"] class CreateLogrotateConfig(utils.Transaction.Element): + title = "Setting logrotate maximum logfile size" + def commit(self): import ovirtnode.log as olog olog.set_logrotate_size(max_size) @@ -899,7 +926,7 @@ # FIXME setting password is missing - tx = utils.Transaction("Configuring SNMP") + tx = utils.Transaction("Configuring CIM") tx.append(ConfigureCIM()) return tx @@ -928,6 +955,8 @@ layout = cfg["layout"] class CreateKeyboardConfig(utils.Transaction.Element): + title = "Setting keyboard layout" + def commit(self): from ovirtnode.ovirtfunctions import ovirt_store_config kbd = utils.Keyboard() @@ -964,6 +993,8 @@ domain = cfg["domain"] class ConfigureNfsv4(utils.Transaction.Element): + title = "Setting NFSv4 domain" + def commit(self): from ovirtnode.network import set_nfsv4_domain set_nfsv4_domain(domain) @@ -1019,16 +1050,19 @@ class ConfigurePasswordAuthentication(utils.Transaction.Element): title = "Configuring SSH password authentication" + def commit(self): ssh.password_authentication(pwauth) class ConfigureStrongRNG(utils.Transaction.Element): - title = "Configuring strong RNG" + title = "Configuring SSH strong RNG" + def commit(self): ssh.strong_rng(num_bytes) class ConfigureAESNI(utils.Transaction.Element): - title = "Configuring AES NI" + title = "Configuring SSH AES NI" + def commit(self): ssh.disable_aesni(disable_aesni) diff --git a/scripts/tui/src/ovirt/node/setup/engine_page.py b/scripts/tui/src/ovirt/node/setup/engine_page.py index a522d86..2f461b9 100644 --- a/scripts/tui/src/ovirt/node/setup/engine_page.py +++ b/scripts/tui/src/ovirt/node/setup/engine_page.py @@ -91,3 +91,8 @@ def on_merge(self, effective_changes): pass + + txs = utils.Transaction("Configuring oVirt Engine") + + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/kdump_page.py b/scripts/tui/src/ovirt/node/setup/kdump_page.py index 846e05b..0cd93de 100644 --- a/scripts/tui/src/ovirt/node/setup/kdump_page.py +++ b/scripts/tui/src/ovirt/node/setup/kdump_page.py @@ -139,5 +139,5 @@ model.update(None, None, None) txs += model.transaction() - txs.prepare() # Just to display something in dry mode - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/keyboard_page.py b/scripts/tui/src/ovirt/node/setup/keyboard_page.py index 89e8cfc..5ae835c 100644 --- a/scripts/tui/src/ovirt/node/setup/keyboard_page.py +++ b/scripts/tui/src/ovirt/node/setup/keyboard_page.py @@ -86,5 +86,5 @@ model.update(*effective_model.get_key_values(layout_keys)) txs += model.transaction() - txs.prepare() # Just to display something in dry mode - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/logging_page.py b/scripts/tui/src/ovirt/node/setup/logging_page.py index ee25e88..7147e19 100644 --- a/scripts/tui/src/ovirt/node/setup/logging_page.py +++ b/scripts/tui/src/ovirt/node/setup/logging_page.py @@ -133,5 +133,5 @@ model.update(*effective_model.get_key_values(netconsole_keys)) txs += model.transaction() - txs.prepare() # Just to display something in dry mode - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/monitoring_page.py b/scripts/tui/src/ovirt/node/setup/monitoring_page.py index 14f35e8..4967517 100644 --- a/scripts/tui/src/ovirt/node/setup/monitoring_page.py +++ b/scripts/tui/src/ovirt/node/setup/monitoring_page.py @@ -91,5 +91,5 @@ model.update(*effective_model.get_key_values(collectd_keys)) txs += model.transaction() - txs.prepare() - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/network_page.py b/scripts/tui/src/ovirt/node/setup/network_page.py index 4cd9d91..5f502e2 100644 --- a/scripts/tui/src/ovirt/node/setup/network_page.py +++ b/scripts/tui/src/ovirt/node/setup/network_page.py @@ -25,7 +25,6 @@ from ovirt.node import plugins, ui, valid, utils from ovirt.node.config import defaults import ovirt.node.utils.network -import time class Plugin(ovirt.node.plugins.NodePlugin): @@ -274,19 +273,6 @@ self.logger.debug("Save and close NIC") self._nic_dialog.close() - def set_progress(txt): - set_progress.txt += txt + "\n" - progress.set_text(set_progress.txt) - set_progress.txt = "Applying changes ...\n" - - progress = ui.Label(set_progress.txt) - _d = self._build_dialog("dialog.dia", - "fooo", [ - ("dialog.dia.text[0]", progress), - ]) - _d.buttons = [] - d = self.application.ui.show_dialog(_d) - # This object will contain all transaction elements to be executed txs = utils.Transaction("DNS and NTP configuration") @@ -321,16 +307,8 @@ args = helper.get_key_values(self._nic_details_group) txs += self._configure_nic(*args) - # Commit all outstanding transactions - txs.prepare() # Just to display something in dry mode - for idx, e in enumerate(txs): - n = "(%s/%s) " % (idx + 1, len(txs)) - set_progress(n + e.title) - self.dry_or(lambda: e.commit()) - - set_progress("All changes were applied.") - time.sleep(3) - d.close() + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() # Behaves like a page reload return self.ui_content() diff --git a/scripts/tui/src/ovirt/node/setup/remote_storage_page.py b/scripts/tui/src/ovirt/node/setup/remote_storage_page.py index 55801c0..57c4823 100644 --- a/scripts/tui/src/ovirt/node/setup/remote_storage_page.py +++ b/scripts/tui/src/ovirt/node/setup/remote_storage_page.py @@ -96,5 +96,5 @@ model.update(*args) txs += model.transaction() - txs.prepare() # Just to display something in dry mode - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/security_page.py b/scripts/tui/src/ovirt/node/setup/security_page.py index 47d88fd..b58ddee 100644 --- a/scripts/tui/src/ovirt/node/setup/security_page.py +++ b/scripts/tui/src/ovirt/node/setup/security_page.py @@ -124,5 +124,5 @@ passwd.set_password("admin", pw) txs += [SetAdminPasswd()] - txs.prepare() # Just to display something in dry mode - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/setup/snmp_page.py b/scripts/tui/src/ovirt/node/setup/snmp_page.py index d2fc9ab..0e8cb5d 100644 --- a/scripts/tui/src/ovirt/node/setup/snmp_page.py +++ b/scripts/tui/src/ovirt/node/setup/snmp_page.py @@ -105,5 +105,5 @@ model.update(*args) txs += model.transaction() - txs.prepare() - self.dry_or(lambda: txs()) + progress_dialog = ui.TransactionProgressDialog(txs, self) + progress_dialog.run() diff --git a/scripts/tui/src/ovirt/node/ui/__init__.py b/scripts/tui/src/ovirt/node/ui/__init__.py index dddc8e4..359b059 100644 --- a/scripts/tui/src/ovirt/node/ui/__init__.py +++ b/scripts/tui/src/ovirt/node/ui/__init__.py @@ -18,12 +18,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. A copy of the GNU General Public License is # also available at http://www.gnu.org/copyleft/gpl.html. +from ovirt.node import base """ This contains abstract UI Elements """ - -from ovirt.node import base # http://stackoverflow.com/questions/739654/understanding-python-decorators @@ -76,10 +75,12 @@ """An abstract container Element containing other Elements """ children = [] + title = None - def __init__(self, children): + def __init__(self, children, title=None): super(ContainerElement, self).__init__() self.children = children + self.title = title def children(self, v=None): if v: @@ -92,8 +93,8 @@ """ buttons = [] - def __init__(self, children): - super(Page, self).__init__(children) + def __init__(self, children, title=None): + super(Page, self).__init__(children, title) self.buttons = self.buttons or [ (None, SaveButton()), (None, ResetButton()) @@ -107,8 +108,7 @@ escape_key = "esc" def __init__(self, title, children): - super(Dialog, self).__init__(children) - self.title = title + super(Dialog, self).__init__(children, title) self.close(False) @Element.signal_change @@ -354,3 +354,39 @@ def run(self): raise NotImplementedError + + +class TransactionProgressDialog(Dialog): + def __init__(self, transaction, plugin, initial_text=""): + self.transaction = transaction + self.texts = [initial_text, ""] + self.plugin = plugin + + self._close_button = CloseButton() + self.buttons = [(None, self._close_button)] + self._progress_label = Label(initial_text) + widgets = [("dialog.progress", self._progress_label)] + super(TransactionProgressDialog, self).__init__(self.transaction.title, + widgets) + + def add_update(self, txt): + self.texts.append(txt) + self._progress_label.set_text("\n".join(self.texts)) + + def run(self): + self.plugin.application.ui.show_dialog(self) + self._close_button.enabled(False) + try: + self.transaction.prepare() # Just to display something in dry mode + for idx, e in enumerate(self.transaction): + txt = "(%s/%s) %s" % (idx + 1, len(self.transaction), e.title) + self.add_update(txt) + self.plugin.dry_or(lambda: e.commit()) + self.add_update("\nAll changes were applied successfully.") + except Exception as e: + self.add_update("\nAn error occurred when applying the changes:") + self.add_update(e.message) + self.logger.warning("Exception '%s' on transaction " + + "'%s': %s - %s" % (self.transaction, type(e), + e, e.message)) + self._close_button.enabled(True) diff --git a/scripts/tui/src/ovirt/node/ui/builder.py b/scripts/tui/src/ovirt/node/ui/builder.py index 1b502a1..2ebc855 100644 --- a/scripts/tui/src/ovirt/node/ui/builder.py +++ b/scripts/tui/src/ovirt/node/ui/builder.py @@ -72,7 +72,7 @@ except: tui.notify("error", "Initial model validation failed.") - page = ui.widgets.PageWidget(widgets) + page = ui.widgets.PageWidget(widgets, container.title) page.plugin = plugin return page @@ -217,6 +217,10 @@ # plugin._on_ui_change({path: True}) urwid.connect_signal(widget, "click", on_widget_click_cb) + def on_item_enabled_change_cb(w, v): + widget.enable(v) + item.connect_signal("enabled", on_item_enabled_change_cb) + return widget diff --git a/scripts/tui/src/ovirt/node/ui/tui.py b/scripts/tui/src/ovirt/node/ui/tui.py index 8592f5e..b86a1d0 100644 --- a/scripts/tui/src/ovirt/node/ui/tui.py +++ b/scripts/tui/src/ovirt/node/ui/tui.py @@ -32,6 +32,10 @@ import ovirt.node.ui.widgets +def inherits(obj, t): + return t in type(obj).mro() + + class UrwidTUI(ovirt.node.ui.Window): app = None @@ -94,6 +98,7 @@ ('plugin.widget.options.label', element_styles["label"]), ('plugin.widget.dialog', None), ('plugin.widget.page', None), + ('plugin.widget.page.header', element_styles["label"]), ('plugin.widget.page.frame', None), ('plugin.widget.checkbox.label', element_styles["label"]), ('plugin.widget.checkbox', element_styles["label"]), @@ -107,7 +112,7 @@ def show_body(self, body): """ """ - assert type(body) is ui.Page + assert inherits(body, ui.Page) widget = ui.builder.build_page(self, self._current_plugin, body) self.__display_as_body(widget) @@ -116,7 +121,7 @@ This transforms the abstract ui.Page to a urwid specififc version and displays it. """ - assert type(page) is ui.Page + assert inherits(page, ui.Page) widget = ui.builder.build_page(self, self._current_plugin, page) self.__display_as_page(widget) @@ -125,14 +130,15 @@ This transforms the abstract ui.Dialog to a urwid specififc version and displays it. """ - assert type(dialog) is ui.Dialog + if not inherits(dialog, ui.Dialog): + raise Exception("'%s' does not inherit from ui.Dialog" % dialog) widget = ui.builder.build_page(self, self._current_plugin, dialog) return self.__display_as_dialog(widget, dialog.title, dialog.escape_key) def topmost_dialog(self): dialog = [w for w in self.__widget_stack - if type(w) is ovirt.node.ui.widgets.ModalDialog][-1:] + if inherits(w, ovirt.node.ui.widgets.ModalDialog)][-1:] if dialog: dialog = dialog[0] else: @@ -262,7 +268,7 @@ def __filter_hotkeys(self, keys, raw): key = str(keys) - if type(self.__loop.widget) is ovirt.node.ui.widgets.ModalDialog: + if inherits(self.__loop.widget, ovirt.node.ui.widgets.ModalDialog): self.logger.debug("Modal dialog escape: %s" % key) if self.__loop.widget.escape_key is None: self.logger.debug("Dialog can not be closed with magic key") diff --git a/scripts/tui/src/ovirt/node/ui/widgets.py b/scripts/tui/src/ovirt/node/ui/widgets.py index 1273ac4..cc56648 100644 --- a/scripts/tui/src/ovirt/node/ui/widgets.py +++ b/scripts/tui/src/ovirt/node/ui/widgets.py @@ -371,11 +371,10 @@ def enable(self, is_enabled): self.selectable = lambda: is_enabled if is_enabled: - self._button_attrmap.set_attr_map({None: self._button_attr}) + amap = {None: self._button_attr} else: - self._button_attrmap.set_attr_map({ - None: self._button_disabled_attr - }) + amap = {None: self._button_disabled_attr} + self._button_attrmap.set_attr_map(amap) class Divider(urwid.WidgetWrap): @@ -430,7 +429,6 @@ def set_text(self, txt): self.select(txt) - # FIXME and disabling class Checkbox(urwid.WidgetWrap): signals = ['change'] @@ -463,13 +461,16 @@ class PageWidget(urwid.WidgetWrap): save_button = None - def __init__(self, widgets): + def __init__(self, widgets, title=None): # self._listwalker = urwid.SimpleListWalker(widgets) # self._container = urwid.ListBox(self._listwalker) self._container = urwid.Pile(widgets) self._container_attrmap = urwid.AttrMap(self._container, "plugin.widget.page") self._header = None + if title: + self._header = urwid.AttrMap(urwid.Text(title), + "plugin.widget.page.header") self._frame = urwid.Frame(self._container_attrmap, self._header) self._box = urwid.Padding(self._frame, width=("relative", 97)) super(PageWidget, self).__init__(self._box) diff --git a/scripts/tui/src/ovirt/node/utils/system.py b/scripts/tui/src/ovirt/node/utils/system.py index 6702896..d10c7f4 100644 --- a/scripts/tui/src/ovirt/node/utils/system.py +++ b/scripts/tui/src/ovirt/node/utils/system.py @@ -20,14 +20,16 @@ # also available at http://www.gnu.org/copyleft/gpl.html. """ -A module to access system wide stuff +A module to access system wide stuff e.g. services, reboot ... """ from ovirt.node.utils import process + def reboot(): process.system("reboot") + def poweroff(): - process.system("poweroff") \ No newline at end of file + process.system("poweroff") -- To view, visit http://gerrit.ovirt.org/9976 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I7c70f83e8c7705e38eb0cc6f81e46bbba1a42f44 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-node Gerrit-Branch: master Gerrit-Owner: Fabian Deutsch <[email protected]> _______________________________________________ node-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/node-patches
