[node-patches] Change in ovirt-node[master]: Add ping example page
fabiand at fedoraproject.org
fabiand at fedoraproject.org
Tue Dec 11 20:09:32 UTC 2012
Fabian Deutsch has uploaded a new change for review.
Change subject: Add ping example page
......................................................................
Add ping example page
Change-Id: I6610230bd32a8602b3fdde135a5b5827337633a0
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/plugins/example.py
A scripts/tui/src/ovirt/node/plugins/ping.py
M scripts/tui/src/ovirt/node/tui.py
M scripts/tui/src/ovirt/node/utils.py
M scripts/tui/src/ovirt/node/valid.py
M scripts/tui/src/ovirt/node/widgets.py
6 files changed, 194 insertions(+), 53 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/69/9869/1
diff --git a/scripts/tui/src/ovirt/node/plugins/example.py b/scripts/tui/src/ovirt/node/plugins/example.py
index fbb28a8..83ccac7 100644
--- a/scripts/tui/src/ovirt/node/plugins/example.py
+++ b/scripts/tui/src/ovirt/node/plugins/example.py
@@ -35,7 +35,7 @@
nospace = lambda v: "No space allowed." if " " in v else None
return {
- "foo.hostname": ovirt.node.valid.Hostname(),
+ "foo.hostname": ovirt.node.valid.FQDN(),
"foo.port": ovirt.node.valid.Number(),
"foo.password": nospace
}
diff --git a/scripts/tui/src/ovirt/node/plugins/ping.py b/scripts/tui/src/ovirt/node/plugins/ping.py
new file mode 100644
index 0000000..6b884f2
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/ping.py
@@ -0,0 +1,84 @@
+"""
+A ping tool page
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+from ovirt.node.plugins import Header, Label, Entry, PasswordEntry
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Tools (ping)"
+
+ def model(self):
+ """Returns the model of this plugin
+ This is expected to parse files and all stuff to build up the model.
+ """
+ if not self._model:
+ self._model = {
+ # The target address
+ "ping.address": "127.0.0.1",
+ "ping.count": "3",
+ # The result field
+ "ping.result": ""
+ }
+ return self._model
+
+ def validators(self):
+ """Validators validate the input on change and give UI feedback
+ """
+ return {
+ # The address must be fqdn, ipv4 or ipv6 address
+ "ping.address": ovirt.node.valid.FQDNOrIPAddress(),
+ "ping.count": ovirt.node.valid.Number(min=1, max=20),
+ }
+
+ def ui_content(self):
+ """Describes the UI this plugin requires
+ This is an ordered list of (path, widget) tuples.
+ """
+ widgets = [
+ ("ping.header", Header("Ping a remote host")),
+ ("ping.address", Entry("Address")),
+ ("ping.count", Entry("Count")),
+ ("ping.result", Label("Result:")),
+ ]
+ self._widgets = dict(widgets)
+ return widgets
+
+ def on_change(self, changes):
+ """Applies the changes to the plugins model, will do all required logic
+ """
+ LOGGER.debug("New (valid) address: %s" % changes)
+ if "ping.address" in changes:
+ self._model.update(changes)
+ if "ping.count" in changes:
+ self._model.update(changes)
+
+ def on_merge(self, changes):
+ """Applies the changes to the plugins model, will do all required logic
+ """
+
+ if "ping.address" in self._model:
+ addr = self._model["ping.address"]
+ count = self._model["ping.count"]
+ LOGGER.debug("Pinging %s" % addr)
+
+ cmd = "ping"
+ if ovirt.node.valid.IPv6Address().validate(addr):
+ cmd = "ping6"
+
+ cmd = "%s -c %s %s" % (cmd, count, addr)
+ out = cmd
+ for line in ovirt.node.utils.pipe_async(cmd):
+ LOGGER.debug("xx" + line)
+ out += line
+ self._widgets["ping.result"].text("Result:\n\n%s" % out)
diff --git a/scripts/tui/src/ovirt/node/tui.py b/scripts/tui/src/ovirt/node/tui.py
index 6ac711c..fb6e0ad 100644
--- a/scripts/tui/src/ovirt/node/tui.py
+++ b/scripts/tui/src/ovirt/node/tui.py
@@ -83,7 +83,8 @@
widget = widget_class(item.label, value)
def on_item_enabled_change_cb(w, v):
- LOGGER.debug("Model changed, updating widget '%s': %s" % (w, v))
+ LOGGER.debug("Model changed, updating widget '%s': %s" % (w,
+ v))
if widget.selectable() != v:
widget.enable(v)
item.connect_signal("enabled[change]", on_item_enabled_change_cb)
@@ -102,6 +103,7 @@
except ovirt.node.plugins.InvalidData as e:
widget.notice = e.message
LOGGER.error("Invalid data when updating: %s" % e)
+ self.__loop.draw_screen()
urwid.connect_signal(widget, 'change', on_widget_value_change)
elif type(item) in [ovirt.node.plugins.Header, \
@@ -109,9 +111,10 @@
widget = widget_class(item.text())
def on_item_text_change_cb(w, v):
- LOGGER.debug("Model changed, updating widget '%s': %s" % (w, v))
-# widget.text(v)
- self.popup("foo")
+ LOGGER.debug("Model changed, updating widget '%s': %s" % (w,
+ v))
+ widget.text(v)
+ self.__loop.draw_screen()
item.connect_signal("text[change]", on_item_text_change_cb)
return widget
@@ -159,11 +162,12 @@
self.register_hotkey(["esc"], self.quit)
self.register_hotkey(["q"], self.quit)
- def popup(self, msg=None, buttons=None):
+ def popup(self, title, msg, buttons=None):
LOGGER.debug("Launching popup")
- dialog = ovirt.node.widgets.ModalDialog(urwid.Filler(urwid.Text(msg)), "Title",
- "esc", self.__loop.widget)
+ dialog = ovirt.node.widgets.ModalDialog(urwid.Filler(urwid.Text(msg)),
+ title, "esc",
+ self.__loop.widget)
self.__loop.widget = dialog
def suspended(self):
diff --git a/scripts/tui/src/ovirt/node/utils.py b/scripts/tui/src/ovirt/node/utils.py
index bd6b070..b2274be 100644
--- a/scripts/tui/src/ovirt/node/utils.py
+++ b/scripts/tui/src/ovirt/node/utils.py
@@ -55,3 +55,23 @@
if stderr:
LOGGER.warning("error '%s'" % stderr)
return (system_cmd.returncode == 0, stdout)
+
+
+def pipe_async(cmd, stdin=None):
+ """Run a command interactively and yields the process output.
+ This functions allows to pass smoe input to a running command.
+
+ Args:
+ cmd: Commandline to be run
+ stdin: Data to be written to cmd's stdin
+
+ Yields:
+ Lines read from stdout
+ """
+ LOGGER.debug("run async '%s'" % cmd)
+ process = popen_closefds(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ if stdin:
+ process.stdin.write(stdin)
+ while process.poll() != 0:
+ yield process.stdout.readline()
diff --git a/scripts/tui/src/ovirt/node/valid.py b/scripts/tui/src/ovirt/node/valid.py
index b59f551..602c03f 100644
--- a/scripts/tui/src/ovirt/node/valid.py
+++ b/scripts/tui/src/ovirt/node/valid.py
@@ -2,6 +2,7 @@
import re
import logging
+import socket
import ovirt.node.plugins
@@ -10,16 +11,39 @@
LOGGER = logging.getLogger(__name__)
-class RegexValidator(str):
- # pattern defined by subclass
- # description defined by subclass
+class Validator(object):
__exception_msg = "The field must contain {description}."
+ description = None
+
+ def validate(self, value):
+ """Validate a given value, return true if valid.
+
+ Args:
+ value: The value to be validated
+
+ Returns:
+ True if valid
+ """
+ raise Exception("To be implemented by subclass")
def __call__(self, value):
- if re.search(self.pattern, value) == None:
- msg = self.__exception_msg.format(description=self.description)
- raise ovirt.node.plugins.InvalidData(msg)
+ if not self.description:
+ self.description = self.__doc__
+ if not self.validate(value):
+ self.raise_exception()
return True
+
+ def raise_exception(self):
+ msg = self.__exception_msg.format(description=self.description)
+ raise ovirt.node.plugins.InvalidData(msg)
+
+class RegexValidator(Validator):
+ # pattern defined by subclass
+
+ def validate(self, value):
+ if type(self.pattern) in [str, unicode]:
+ self.pattern = (self.pattern, )
+ return re.compile(*self.pattern).search(value) != None
class Text(RegexValidator):
@@ -35,58 +59,65 @@
class Number(RegexValidator):
description = "a number"
pattern = "^\d+$"
+ minmax = None
+ def __init__(self, min=None, max=None):
+ if min or max:
+ self.minmax = (min, max)
+ self.description = "a number (%s<%s)" % (min, max)
+
+ def validate(self, value):
+ valid = True
+ RegexValidator.validate(self, value)
+ try:
+ value = int(value)
+ LOGGER.debug("val %d" % value)
+ min, max = self.minmax
+ if min and value < min:
+ LOGGER.debug("min %s" % min)
+ self.raise_exception()
+ if max and value > max:
+ LOGGER.debug("max %s" % max)
+ self.raise_exception()
+ except:
+ valid = False
+ return valid
class NoSpaces(RegexValidator):
description = "a string without spaces"
pattern = "^\S*$"
-class Hostname(RegexValidator):
- description = "a valid hostname"
- pattern = ("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)" +
- "*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$")
+class FQDN(RegexValidator):
+ description = "a valid FQDN"
+ pattern = ("^(([a-z]|[a-z][a-z0-9\-]*[a-z0-9])\.)" +
+ "*([a-z]|[a-z][a-z0-9\-]*[a-z0-9])$", re.I)
-class IPv4Address(RegexValidator):
+class IPv4Address(Validator):
description = "a valid IPv4 address"
- pattern = ("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)" +
- "{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
+ family = socket.AF_INET
+ def validate(self, value):
+ valid = True
+ try:
+ socket.inet_pton(self.family, value)
+ except:
+ valid = False
+ return valid
-class IPv6Address(RegexValidator):
+class IPv6Address(IPv4Address):
description = "a valid IPv6 address"
- pattern = ("/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$" +
- ")){7,})((?1)(?>:(?1)){0,5})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}" +
- ":|(?!(?:.*[a-f0-9]:){5,})(?3)?::(?>((?1)(?>:(?1)){0,3}):)?)?" +
- "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?" +
- "4)){3}))$/iD")
+ family = socket.AF_INET6
-class OrCombinedValidator(str):
- _validators = None
+class FQDNOrIPAddress(Validator):
+ """Allows any FQDN, IPv4 or IPv6 address
+ """
+ description = " or ".join([FQDN.description, IPv4Address.description,
+ IPv6Address.description])
- def __init__(self, validators):
- self._validators = validators
-
- def __call__(self, value):
- is_valid = False
- msgs = []
-
- for v in self._validators:
- LOGGER.debug(v)
- try:
- msg = v(value)
- if msg:
- msgs.append(msg)
- else:
- is_valid = True
- break
- except ovirt.node.plugins.InvalidData as e:
- msgs.append(str(e))
-
- if not is_valid:
- msg = ", ".join(msgs)
- raise ovirt.node.plugins.InvalidData(msg)
-
- return True
+ def validate(self, value):
+ return (FQDN().validate(value) or \
+ IPv4Address().validate(value) or \
+ IPv6Address().validate(value))
diff --git a/scripts/tui/src/ovirt/node/widgets.py b/scripts/tui/src/ovirt/node/widgets.py
index 471841d..3a4e9d4 100644
--- a/scripts/tui/src/ovirt/node/widgets.py
+++ b/scripts/tui/src/ovirt/node/widgets.py
@@ -134,6 +134,7 @@
self._label.set_text(value)
return self._label.get_text()
+
class Header(Label):
"""A read only widget representing a header
"""
@@ -185,6 +186,7 @@
super(Entry, self).__init__(self._pile)
+
class PasswordEntry(Entry):
def __init__(self, label, value=None):
super(PasswordEntry, self).__init__(label, value, mask="*")
--
To view, visit http://gerrit.ovirt.org/9869
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6610230bd32a8602b3fdde135a5b5827337633a0
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