[node-patches] Change in ovirt-node[master]: utils: Add and integrate transaction mechanism
fabiand at fedoraproject.org
fabiand at fedoraproject.org
Tue Dec 11 20:09:40 UTC 2012
Fabian Deutsch has uploaded a new change for review.
Change subject: utils: Add and integrate transaction mechanism
......................................................................
utils: Add and integrate transaction mechanism
Change-Id: Ifda1b1ab62e717f5602e6be5e733ec5768772f77
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/config/defaults.py
M scripts/tui/src/ovirt/node/plugins.py
M scripts/tui/src/ovirt/node/setup/keyboard_page.py
M scripts/tui/src/ovirt/node/setup/network_page.py
M scripts/tui/src/ovirt/node/utils/__init__.py
M scripts/tui/src/ovirt/node/utils/network.py
6 files changed, 187 insertions(+), 46 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/42/9942/1
diff --git a/scripts/tui/src/ovirt/node/config/defaults.py b/scripts/tui/src/ovirt/node/config/defaults.py
index 2121cb5..6bf73a2 100644
--- a/scripts/tui/src/ovirt/node/config/defaults.py
+++ b/scripts/tui/src/ovirt/node/config/defaults.py
@@ -169,11 +169,25 @@
"""
raise NotImplementedError
- def apply(self, *args, **kwargs):
- """This method updates the to this subclass specific configuration
- files according to the config keys set with configure.
+ def transaction(self):
+ """This method returns a transaction which needs to be performed
+ to activate the defaults config (so e.g. update cfg files and restart
+ services).
+
+ This can be used to update the UI when the transaction has many steps
"""
raise NotImplementedError
+
+ def commit(self, *args, **kwargs):
+ """This method updates the to this subclass specific configuration
+ files according to the config keys set with configure.
+
+ A shortcut for:
+ tx = obj.ransaction()
+ tx()
+ """
+ tx = self.transaction()
+ tx()
def retrieve(self):
"""Returns the config keys of the current component
@@ -305,7 +319,7 @@
"servers": cfg["servers"].split(",")
}
- def apply(self):
+ def transaction(self):
"""Derives the nameserver config from OVIRT_DNS
1. Parse nameservers from defaults
@@ -316,6 +330,7 @@
Args:
servers: List of servers (str)
"""
+ aug = utils.AugeasWrapper()
ovirt_config = self.defaults.get_dict()
if "OVIRT_DNS" not in ovirt_config:
self.logger.debug("No DNS server entry in default config")
@@ -323,31 +338,40 @@
servers = ovirt_config["OVIRT_DNS"]
if servers is None or servers == "":
- self.logger.debug("No DNS servers configured in default config")
-
+ self.logger.debug("No DNS servers configured " +
+ "in default config")
servers = servers.split(",")
- aug = utils.AugeasWrapper()
- # Write resolv.conf any way, sometimes without servers
- comment = ("Please make changes through the TUI. " + \
- "Manual edits to this file will be " + \
- "lost on reboot")
- aug.set("/files/etc/resolv.conf/#comment[1]", comment)
+ class UpdateResolvConf(utils.Transaction.Element):
+ title = "Updateing resolv.conf"
- # Now set the nameservers
- ovirt.node.config.network.nameservers(servers)
+ def commit(self):
+ # Write resolv.conf any way, sometimes without servers
+ comment = ("Please make changes through the TUI. " + \
+ "Manual edits to this file will be " + \
+ "lost on reboot")
+ aug.set("/files/etc/resolv.conf/#comment[1]", comment)
+ # Now set the nameservers
+ ovirt.node.config.network.nameservers(servers)
+ utils.fs.persist_config("/etc/resolv.conf")
- # Set or remove PEERDNS for all ifcfg-*
- for nic in glob.glob("/etc/sysconfig/network-scripts/ifcfg-*"):
- if "ifcfg-lo" in nic:
- continue
- path = "/files%s/PEERDNS" % nic
- if len(servers) > 0:
- aug.set(path, "no")
- else:
- aug.remove(path)
+ class UpdatePeerDNS(utils.Transaction.Element):
+ title = "Update PEERDNS statement in ifcfg-* files"
- utils.fs.persist_config("/etc/resolv.conf")
+ def commit(self):
+ # Set or remove PEERDNS for all ifcfg-*
+ for nic in glob.glob("/etc/sysconfig/network-scripts/ifcfg-*"):
+ if "ifcfg-lo" in nic:
+ continue
+ path = "/files%s/PEERDNS" % nic
+ if len(servers) > 0:
+ aug.set(path, "no")
+ else:
+ aug.remove(path)
+
+ return utils.Transaction("Configuring DNS", [
+ UpdateResolvConf(),
+ UpdatePeerDNS()])
class Timeservers(NodeConfigFileSection):
@@ -379,6 +403,9 @@
"servers": cfg["servers"].split(",")
}
+ def transaction(self):
+ return utils.Transaction("Configuring timeserver")
+
class Syslog(NodeConfigFileSection):
"""Configure rsyslog
diff --git a/scripts/tui/src/ovirt/node/plugins.py b/scripts/tui/src/ovirt/node/plugins.py
index a1d01f2..66e949e 100644
--- a/scripts/tui/src/ovirt/node/plugins.py
+++ b/scripts/tui/src/ovirt/node/plugins.py
@@ -253,7 +253,6 @@
self.logger.debug("Request to discard model changes: %s" % changes)
self.__changes = {}
-
def pending_changes(self, only_effective_changes=True):
"""Return all changes which happened since the last on_merge call
@@ -365,4 +364,4 @@
"""Enable or disable all widgets of this group
"""
self.logger.debug("Enabling widget group: %s" % self)
- map(lambda w: w.enabled(is_enable), self.widgethelper.subset(self))
\ No newline at end of file
+ map(lambda w: w.enabled(is_enable), self.widgethelper.subset(self))
diff --git a/scripts/tui/src/ovirt/node/setup/keyboard_page.py b/scripts/tui/src/ovirt/node/setup/keyboard_page.py
index df6ffcf..66099cd 100644
--- a/scripts/tui/src/ovirt/node/setup/keyboard_page.py
+++ b/scripts/tui/src/ovirt/node/setup/keyboard_page.py
@@ -25,6 +25,7 @@
from ovirt.node import plugins, ui, utils
+
class Plugin(plugins.NodePlugin):
_model = None
_widgets = None
diff --git a/scripts/tui/src/ovirt/node/setup/network_page.py b/scripts/tui/src/ovirt/node/setup/network_page.py
index 3e44f89..19ebae5 100644
--- a/scripts/tui/src/ovirt/node/setup/network_page.py
+++ b/scripts/tui/src/ovirt/node/setup/network_page.py
@@ -22,13 +22,10 @@
Network page plugin
"""
-import time
-
-from ovirt.node import ui
+from ovirt.node import plugins, ui, valid, utils
from ovirt.node.config import defaults
-from ovirt.node import plugins
import ovirt.node.utils.network
-from ovirt.node import valid
+import time
class Plugin(ovirt.node.plugins.NodePlugin):
@@ -262,31 +259,45 @@
("dialog.dia.text[0]", progress),
]))
+ # This object will contain all transaction elements to be executed
+ txs = utils.Transaction("DNS and NTP configuration")
+
+ e_changes_h = plugins.ChangesHelper(effective_changes)
+ e_model_h = plugins.ChangesHelper(effective_model)
+
nameservers = []
- for key in ["dns[0]", "dns[1]"]:
- if key in effective_changes:
- nameservers.append(effective_model[key])
+ dns_keys = ["dns[0]", "dns[1]"]
+ if e_changes_h.any_key_in_change(dns_keys):
+ nameservers += e_model_h.get_key_values(dns_keys)
if nameservers:
- set_progress("Applying DNS changes.")
self.logger.info("Setting new nameservers: %s" % nameservers)
model = defaults.Nameservers()
model.update(nameservers)
+ txs += model.transaction()
timeservers = []
- for key in ["ntp[0]", "ntp[1]"]:
- if key in effective_changes:
- timeservers.append(effective_model[key])
+ ntp_keys = ["ntp[0]", "ntp[1]"]
+ if e_changes_h.any_key_in_change(ntp_keys):
+ timeservers += e_model_h.get_key_values(ntp_keys)
if timeservers:
- set_progress("Applying NTP changes.")
self.logger.info("Setting new timeservers: %s" % timeservers)
model = defaults.Timeservers()
model.update(timeservers)
+ txs += model.transaction()
- change_helper = plugins.ChangesHelper(effective_changes)
- if change_helper.any_key_in_change(self._nic_details_group):
+ # For the NIC details dialog:
+ if e_changes_h.any_key_in_change(self._nic_details_group):
# If any networking related key was changed, reconfigure networking
helper = plugins.ChangesHelper(effective_model)
- self._configure_nic(*helper.get_key_values(self._nic_details_group))
+ # Fetch the values for the nic keys, they are used as arguments
+ args = helper.get_key_values(self._nic_details_group)
+ txs += self._configure_nic(*args)
+
+ # Commit all outstanding transactions
+ txs.prepare()
+ for e in txs:
+ set_progress(e.title)
+ #e.commit()
set_progress("All changes were applied.")
time.sleep(3)
@@ -306,3 +317,5 @@
model.update(iface, "none", ipaddr, netmask, gateway, vlanid)
else:
self.logger.debug("No interface configuration found")
+ # Return the resulting transaction
+ return model.transaction()
diff --git a/scripts/tui/src/ovirt/node/utils/__init__.py b/scripts/tui/src/ovirt/node/utils/__init__.py
index 5c7304f..9ce9c8d 100644
--- a/scripts/tui/src/ovirt/node/utils/__init__.py
+++ b/scripts/tui/src/ovirt/node/utils/__init__.py
@@ -166,4 +166,108 @@
layoutgen = ((details[0], kid)
for kid, details in kbd.modelDict.items())
layouts = [(kid, name) for name, kid in sorted(layoutgen)]
- return layouts
\ No newline at end of file
+ return layouts
+
+
+class Transaction(list, base.Base):
+ """A very simple transaction mechanism.
+
+ >>> class StepA(Transaction.Element):
+ ... def commit(self):
+ ... print "Step A"
+ ... return "Stepped A"
+
+ >>> class StepB(Transaction.Element):
+ ... def commit(self):
+ ... print "Step B"
+ ... return "Stepped B"
+
+ >>> class StepC(Transaction.Element):
+ ... def commit(self):
+ ... raise Exception("Step C")
+
+ >>> tx = Transaction("Steps", [StepA(), StepB()])
+ >>> tx()
+ Step A
+ Step B
+ True
+
+ >>> len(tx)
+ 2
+
+ >>> tx.prepare()
+ True
+ >>> for e in tx:
+ ... e.commit()
+ Step A
+ 'Stepped A'
+ Step B
+ 'Stepped B'
+
+>>> tx = Transaction("Steps", [StepA(), StepB(), StepC()])
+ >>> tx()
+ Traceback (most recent call last):
+ ...
+ RuntimeError: Transaction failed: Step C
+ """
+ def __init__(self, title, elements=[]):
+ super(Transaction, self).__init__()
+ base.Base.__init__(self)
+ self.title = title
+ self._prepared_elements = []
+ self.extend(elements)
+
+ def prepare(self):
+ for element in self:
+ self.logger.debug("Preparing element '%s'" % element)
+ if Transaction.Element not in element.__class__.mro():
+ raise Exception("%s is no Transaction.Element" % element)
+ self._prepared_elements.append(element)
+ element.prepare()
+ return True
+
+ def commit(self):
+ for element in self:
+ self.logger.debug("Committing element '%s'" % element)
+ element.commit()
+ return True
+
+ def abort(self):
+ for element in self._prepared_elements:
+ self.logger.debug("Aborting element '%s'" % element)
+ element.abort()
+ self._prepared_elements = []
+ return True
+
+ def __call__(self):
+ self.logger.debug("Running transaction '%s'" % self)
+ try:
+ self.prepare()
+ self.commit()
+ except Exception as e:
+ self.logger.warning("Transaction failed: %s" % e.message)
+ self.abort()
+ raise RuntimeError("Transaction failed: %s" % e.message)
+ self.logger.info("Transaction '%s' succeeded" % self)
+ return True
+
+ class Element(base.Base):
+ title = None
+
+ def __repr__(self):
+ return "<%s '%s'>" % (self.__class__.__name__, self.title)
+
+ def prepare(self):
+ """Is expected to be short running and not changing anything
+ """
+ pass
+
+ def commit(self):
+ """Is expected to run and change stuff
+ """
+ pass
+
+ def abort(self):
+ """Is run in case that one commit of a transaction fails.
+ """
+ pass
diff --git a/scripts/tui/src/ovirt/node/utils/network.py b/scripts/tui/src/ovirt/node/utils/network.py
index 17c0ef3..72bc868 100644
--- a/scripts/tui/src/ovirt/node/utils/network.py
+++ b/scripts/tui/src/ovirt/node/utils/network.py
@@ -273,9 +273,6 @@
def node_bridge():
"""Returns the main bridge of this node
- >>> node_bridge() is not None
- True
-
Returns:
Bridge of this node
"""
--
To view, visit http://gerrit.ovirt.org/9942
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifda1b1ab62e717f5602e6be5e733ec5768772f77
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>
More information about the node-patches
mailing list