[node-patches] Change in ovirt-node[master]: setup: Add several pages
fabiand at fedoraproject.org
fabiand at fedoraproject.org
Tue Dec 11 20:09:35 UTC 2012
Fabian Deutsch has uploaded a new change for review.
Change subject: setup: Add several pages
......................................................................
setup: Add several pages
Change-Id: Ieed7880a31c250b03030cbaa6fbb3686776b4b19
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/.gitignore
A scripts/tui/src/ovirt/node/plugins/engine_page.py
M scripts/tui/src/ovirt/node/plugins/example.py
M scripts/tui/src/ovirt/node/plugins/features.py
R scripts/tui/src/ovirt/node/plugins/kdump_page.py
A scripts/tui/src/ovirt/node/plugins/keyboard_page.py
A scripts/tui/src/ovirt/node/plugins/logging_page.py
A scripts/tui/src/ovirt/node/plugins/monitoring_page.py
A scripts/tui/src/ovirt/node/plugins/network_page.py
M scripts/tui/src/ovirt/node/plugins/ping.py
A scripts/tui/src/ovirt/node/plugins/remote_storage_page.py
A scripts/tui/src/ovirt/node/plugins/security_page.py
A scripts/tui/src/ovirt/node/plugins/snmp_page.py
R scripts/tui/src/ovirt/node/plugins/status_page.py
M scripts/tui/src/ovirt/node/plugins/usage.py
M scripts/tui/src/ovirt/node/tui.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/widgets.py
M scripts/tui/src/ovirt/node/utils/__init__.py
A scripts/tui/src/ovirt/node/utils/network.py
M scripts/tui/src/ovirt/node/valid.py
22 files changed, 1,189 insertions(+), 26 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/98/9898/1
diff --git a/scripts/tui/.gitignore b/scripts/tui/.gitignore
index 171bbb9..a9d8d73 100644
--- a/scripts/tui/.gitignore
+++ b/scripts/tui/.gitignore
@@ -2,3 +2,7 @@
app.log
*.pyc
*.pyo
+MANIFEST
+scm_hash.txt
+dist
+build
diff --git a/scripts/tui/src/ovirt/node/plugins/engine_page.py b/scripts/tui/src/ovirt/node/plugins/engine_page.py
new file mode 100644
index 0000000..39b1ee9
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/engine_page.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python
+#
+# engine_page.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure Engine
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "oVirt Engine"
+
+ def rank(self):
+ return 100
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "vdsm.address": "",
+ "vdsm.port": "7634",
+ "vdsm.connect_and_validate": True,
+ "vdsm.password": "",
+ "vdsm.password_confirmation": "",
+ }
+ return self._model
+
+ def validators(self):
+ return {
+ "vdsm.address": ovirt.node.valid.FQDNOrIPAddress(),
+ "vdsm.port": ovirt.node.valid.Port(),
+ "vdsm.password": ovirt.node.valid.Text(),
+ "vdsm.password_confirmation": ovirt.node.valid.Text(),
+ }
+
+ def ui_content(self):
+ widgets = [
+ ("header", ovirt.node.ui.Header("oVirt Engine Configuration")),
+
+ ("vdsm.address", ovirt.node.ui.Entry("Server Address")),
+ ("vdsm.port", ovirt.node.ui.Entry("Server Port")),
+ ("vdsm.connect_and_validate", ovirt.node.ui.Options(
+ "Connect to oVirt Engine and Validate Certificate",
+ [("yes", "Yes"), ("no", "No")])),
+
+ ("vdsm.password._label", ovirt.node.ui.Label(
+ "Optional password for adding Node through oVirt " +
+ "Engine UI")),
+
+ ("vdsm.password", ovirt.node.ui.PasswordEntry("Password")),
+ ("vdsm.password_confirmation", ovirt.node.ui.PasswordEntry(
+ "Confirm Password")),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def on_change(self, changes):
+ self._model.update(changes)
+
+ if self._model["vdsm.password"] != \
+ self._model["vdsm.password_confirmation"]:
+ raise ovirt.node.exceptions.InvalidData("Passwords do not match.")
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/example.py b/scripts/tui/src/ovirt/node/plugins/example.py
index 7436c10..ffe6f87 100644
--- a/scripts/tui/src/ovirt/node/plugins/example.py
+++ b/scripts/tui/src/ovirt/node/plugins/example.py
@@ -38,6 +38,9 @@
def name(self):
return "Example Page"
+ def rank(self):
+ return 999
+
def model(self):
"""Returns the model of this plugin
This is expected to parse files and all stuff to build up the model.
diff --git a/scripts/tui/src/ovirt/node/plugins/features.py b/scripts/tui/src/ovirt/node/plugins/features.py
index 5816579..a022a9f 100644
--- a/scripts/tui/src/ovirt/node/plugins/features.py
+++ b/scripts/tui/src/ovirt/node/plugins/features.py
@@ -41,7 +41,7 @@
def name(self):
return "Features"
- rank = lambda self: 10
+ rank = lambda self: 999
def ui_content(self):
widgets = [
diff --git a/scripts/tui/src/ovirt/node/plugins/kdump.py b/scripts/tui/src/ovirt/node/plugins/kdump_page.py
similarity index 96%
rename from scripts/tui/src/ovirt/node/plugins/kdump.py
rename to scripts/tui/src/ovirt/node/plugins/kdump_page.py
index 88ca080..1cc8771 100644
--- a/scripts/tui/src/ovirt/node/plugins/kdump.py
+++ b/scripts/tui/src/ovirt/node/plugins/kdump_page.py
@@ -45,7 +45,7 @@
return "Kdump"
def rank(self):
- return 70
+ return 60
def model(self):
"""Returns the model of this plugin
@@ -63,9 +63,8 @@
def validators(self):
"""Validators validate the input on change and give UI feedback
"""
- options = dict(self._types).keys()
return {
- "kdump.type": ovirt.node.valid.Options(options),
+ "kdump.type": ovirt.node.valid.Options(self._types),
"kdump.ssh_location": ovirt.node.valid.NoSpaces(),
"kdump.nfs_location": ovirt.node.valid.NoSpaces(),
}
diff --git a/scripts/tui/src/ovirt/node/plugins/keyboard_page.py b/scripts/tui/src/ovirt/node/plugins/keyboard_page.py
new file mode 100644
index 0000000..20cfc0a
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/keyboard_page.py
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+#
+# keyboard_page.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure Keyboard Layout
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+import ovirt.node.utils.network
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Keyboard"
+
+ def rank(self):
+ return 30
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "layout": "en_US",
+ }
+
+ return self._model
+
+ def validators(self):
+ return {}
+
+ def ui_content(self):
+ """Describes the UI this plugin requires
+ This is an ordered list of (path, widget) tuples.
+ """
+ widgets = [
+ ("layout.label",
+ ovirt.node.ui.Label("Keyboard Layout Selection")),
+ ("layout", ovirt.node.ui.Table("", self._get_layouts())),
+
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def _get_layouts(self):
+ # FIXME load from somewhere
+ return [
+ ("en_US", "U.S. English"),
+ ("de_DE", "German"),
+ ]
+
+ def on_change(self, changes):
+ pass
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/logging_page.py b/scripts/tui/src/ovirt/node/plugins/logging_page.py
new file mode 100644
index 0000000..71e6b22
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/logging_page.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+#
+# logging.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure Logging
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Logging"
+
+ def rank(self):
+ return 50
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ # The target address
+ "max_log_size": "1024",
+ "rsyslog.address": "",
+ "rsyslog.port": "514",
+ "netconsole.address": "",
+ "netconsole.port": "6666",
+ }
+ return self._model
+
+ def validators(self):
+ """Validators validate the input on change and give UI feedback
+ """
+ return {
+ "max_log_size": ovirt.node.valid.Number(min=0),
+ "rsyslog.address": ovirt.node.valid.FQDNOrIPAddress(),
+ "rsyslog.port": ovirt.node.valid.Port(),
+ "netconsole.address": ovirt.node.valid.FQDNOrIPAddress(),
+ "netconsole.port": ovirt.node.valid.Port(),
+ }
+
+ def ui_content(self):
+ widgets = [
+ ("header", ovirt.node.ui.Header("Logging")),
+
+ ("max_log_size", ovirt.node.ui.Entry("Logrotate Max Log " +
+ "Size (KB)")),
+
+ ("rsyslog.header", ovirt.node.ui.Label(
+ "RSyslog is an enhanced multi-threaded " +
+ "syslogd")),
+ ("rsyslog.address", ovirt.node.ui.Entry("Server Address")),
+ ("rsyslog.port", ovirt.node.ui.Entry("Server Port")),
+
+ ("netconsole.header", ovirt.node.ui.Label(
+ "Netconsole service allows a remote sys" +
+ "log daemon to record printk() messages")),
+ ("netconsole.address", ovirt.node.ui.Entry("Server Address")),
+ ("netconsole.port", ovirt.node.ui.Entry("Server Port")),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def on_change(self, changes):
+ pass
+ self._model.update(changes)
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/monitoring_page.py b/scripts/tui/src/ovirt/node/plugins/monitoring_page.py
new file mode 100644
index 0000000..00f427c
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/monitoring_page.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+#
+# monitoring_page.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure Monitoring
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Monitoring"
+
+ def rank(self):
+ return 90
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "collectd.address": "",
+ "collectd.port": "7634",
+ }
+ return self._model
+
+ def validators(self):
+ return {
+ "collectd.address": ovirt.node.valid.FQDNOrIPAddress(),
+ "collectd.port": ovirt.node.valid.Port(),
+ }
+
+ def ui_content(self):
+ widgets = [
+ ("header", ovirt.node.ui.Header("Monitoring Configuration")),
+
+ ("label", ovirt.node.ui.Label("Collectd gathers statistics " +
+ "about the system and can be used to find " +
+ "performance bottlenecks and predict future " +
+ "system load.")),
+
+ ("collectd.address", ovirt.node.ui.Entry("Server Address")),
+ ("collectd.port", ovirt.node.ui.Entry("Server Port")),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def on_change(self, changes):
+ pass
+ self._model.update(changes)
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/network_page.py b/scripts/tui/src/ovirt/node/plugins/network_page.py
new file mode 100644
index 0000000..aee4fa5
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/network_page.py
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+#
+# status.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Network plugin
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+import ovirt.node.utils.network
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ """This is the network page
+ """
+
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Network"
+
+ def rank(self):
+ return 10
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "hostname": "localhost.example.com",
+ "dns[0]": "192.168.122.1",
+ "dns[1]": "",
+ "ntp[0]": "fedora.pool.ntp.org",
+ "ntp[1]": "",
+ }
+
+ nameservers = ovirt.node.utils.network.nameservers()
+ for idx, nameserver in enumerate(nameservers):
+ self._model["dns[%d]" % idx] = nameserver
+
+ timeservers = ovirt.node.utils.network.timeservers()
+ for idx, timeserver in enumerate(timeservers):
+ self._model["ntp[%d]" % idx] = timeserver
+
+ return self._model
+
+ def validators(self):
+ Empty = ovirt.node.valid.Empty
+ ip_or_empty = ovirt.node.valid.IPAddress() | Empty()
+ fqdn_ip_or_empty = ovirt.node.valid.FQDNOrIPAddress() | Empty()
+ return {
+ "hostname": ovirt.node.valid.FQDNOrIPAddress(),
+ "dns[0]": ovirt.node.valid.IPAddress(),
+ "dns[1]": ip_or_empty,
+ "ntp[0]": ovirt.node.valid.FQDNOrIPAddress(),
+ "ntp[1]": fqdn_ip_or_empty,
+ }
+
+ def ui_content(self):
+ """Describes the UI this plugin requires
+ This is an ordered list of (path, widget) tuples.
+ """
+ widgets = [
+ ("hostname",
+ ovirt.node.ui.Entry("Hostname")),
+ ("hostname._space", ovirt.node.ui.Divider()),
+
+ ("nics", ovirt.node.ui.Table(
+ "Device Status Model MAC Address",
+ self._get_nics())),
+ ("nics._space", ovirt.node.ui.Divider()),
+
+ ("dns[0]", ovirt.node.ui.Entry("DNS Server 1")),
+ ("dns[1]", ovirt.node.ui.Entry("DNS Server 2")),
+ ("dns._space", ovirt.node.ui.Divider()),
+
+ ("ntp[0]", ovirt.node.ui.Entry("NTP Server 1")),
+ ("ntp[1]", ovirt.node.ui.Entry("NTP Server 2")),
+ ("ntp._space", ovirt.node.ui.Divider()),
+
+# ("action", ovirt.node.ui.Buttons(["Lock", "Log Off", "Restart",
+# "Power Off"])),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def _get_nics(self):
+ justify = lambda txt, l: txt.ljust(l)[0:l]
+ node_nics = [
+ ("em1",
+ "em1 Configured e1000 00:11:22:33:44:55"),
+ ("p1p6",
+ "p1p6 Unconfigured bnx2 10:21:32:43:54:65"),
+ ]
+ node_nics = []
+ for name, nic in ovirt.node.utils.network.node_nics().items():
+ bootproto = "Configured" if nic["bootproto"] else "Unconfigured"
+ description = " ".join([
+ justify(nic["name"], 8),
+ justify(bootproto, 14),
+ justify(nic["driver"], 8),
+ justify(nic["hwaddr"], 17)
+ ])
+ node_nics.append((name, description))
+ return node_nics
+
+ def on_change(self, changes):
+ pass
+
+ def on_merge(self, effective_changes):
+ effective_model = self._model.update(changes)
+
+ if "dns[0]" in effective_changes or \
+ "dns[1]" in effective_changes:
+ new_servers = [v for k, v in effective_model \
+ if k.startswith("dns[")]
+ LOGGER.info("Setting new nameservers: %s" % new_servers)
+ ovirt.node.utils.network.nameservers(new_servers)
+
+ if "ntp[0]" in effective_changes or \
+ "ntp[1]" in effective_changes:
+ new_servers = [v for k, v in effective_model \
+ if k.startswith("ntp[")]
+ LOGGER.info("Setting new timeservers: %s" % new_servers)
+ ovirt.node.utils.network.timeservers(new_servers)
diff --git a/scripts/tui/src/ovirt/node/plugins/ping.py b/scripts/tui/src/ovirt/node/plugins/ping.py
index 855a11a..f40e7eb 100644
--- a/scripts/tui/src/ovirt/node/plugins/ping.py
+++ b/scripts/tui/src/ovirt/node/plugins/ping.py
@@ -39,7 +39,7 @@
return "Tools (ping)"
def rank(self):
- return 70
+ return 999
def model(self):
"""Returns the model of this plugin
diff --git a/scripts/tui/src/ovirt/node/plugins/remote_storage_page.py b/scripts/tui/src/ovirt/node/plugins/remote_storage_page.py
new file mode 100644
index 0000000..87fe0ef
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/remote_storage_page.py
@@ -0,0 +1,76 @@
+#!/usr/bin/python
+#
+# remote_storage_page.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure Remote Storage
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Remote Storage"
+
+ def rank(self):
+ return 70
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "iscsi.initiator_name": "",
+ }
+ return self._model
+
+ def validators(self):
+ is_initiator_name = lambda v: (None if len(v.split(":")) == 2
+ else "Invalid IQN.")
+ return {
+ "iscsi.initiator_name": is_initiator_name,
+ }
+
+ def ui_content(self):
+ widgets = [
+ ("header", ovirt.node.ui.Header("Remote Storage")),
+
+ ("iscsi.initiator_name", ovirt.node.ui.Entry("iSCSI Initiator " +
+ "Name")),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def on_change(self, changes):
+ pass
+ self._model.update(changes)
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/security_page.py b/scripts/tui/src/ovirt/node/plugins/security_page.py
new file mode 100644
index 0000000..7e7ba7e
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/security_page.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+#
+# security_page.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure Security
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "Security"
+
+ def rank(self):
+ return 20
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "ssh.enabled": "no",
+ "passwd.admin.password": "",
+ "passwd.admin.password_confirmation": "",
+ }
+ return self._model
+
+ def validators(self):
+ return {
+ "passwd.admin.password": ovirt.node.valid.Text(),
+ "passwd.admin.password_confirmation": ovirt.node.valid.Text(),
+ }
+
+ def ui_content(self):
+ widgets = [
+ ("ssh.address", ovirt.node.ui.Header("Remote Access")),
+ ("ssh.enabled", ovirt.node.ui.Options(
+ "Enable ssh password authentication",
+ [("yes", "Yes"), ("no", "No")])),
+ ("ssh._divider", ovirt.node.ui.Divider()),
+
+
+ ("passwd._label", ovirt.node.ui.Label("Local Access")),
+ ("passwd.admin.password", ovirt.node.ui.PasswordEntry("Password")),
+ ("passwd.admin.password_confirmation", ovirt.node.ui.PasswordEntry(
+ "Confirm Password")),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def on_change(self, changes):
+ self._model.update(changes)
+
+ if self._model["passwd.admin.password"] != \
+ self._model["passwd.admin.password_confirmation"]:
+ raise ovirt.node.exceptions.InvalidData("Passwords do not match.")
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/snmp_page.py b/scripts/tui/src/ovirt/node/plugins/snmp_page.py
new file mode 100644
index 0000000..29d15d4
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/snmp_page.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+#
+# snmp_page.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Configure SNMP
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.valid
+import ovirt.node.ui
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+ _model = None
+ _widgets = None
+
+ def name(self):
+ return "SNMP"
+
+ def rank(self):
+ return 40
+
+ def model(self):
+ if not self._model:
+ self._model = {
+ "snmp.enabled": "no",
+ "snmp.password": "",
+ "snmp.password_confirmation": "",
+ }
+ return self._model
+
+ def validators(self):
+ return {
+ "passwd.admin.password": ovirt.node.valid.Text(),
+ "passwd.admin.password_confirmation": ovirt.node.valid.Text(),
+ }
+
+ def ui_content(self):
+ widgets = [
+ ("snmp._header", ovirt.node.ui.Header("SNMP")),
+ ("snmp.enabled", ovirt.node.ui.Options("Enable SNMP",
+ [("yes", "Yes"), ("no", "No")])),
+ ("ssh._divider", ovirt.node.ui.Divider()),
+
+
+ ("snmp.password._label", ovirt.node.ui.Label("SNMP Password")),
+ ("snmp.password", ovirt.node.ui.PasswordEntry("Password")),
+ ("snmp.password_confirmation", ovirt.node.ui.PasswordEntry(
+ "Confirm Password")),
+ ]
+ # Save it "locally" as a dict, for better accessability
+ self._widgets = dict(widgets)
+
+ page = ovirt.node.ui.Page(widgets)
+ return page
+
+ def on_change(self, changes):
+ self._model.update(changes)
+
+ if self._model["snmp.password"] != \
+ self._model["snmp.password_confirmation"]:
+ raise ovirt.node.exceptions.InvalidData("Passwords do not match.")
+
+ def on_merge(self, effective_changes):
+ pass
diff --git a/scripts/tui/src/ovirt/node/plugins/status.py b/scripts/tui/src/ovirt/node/plugins/status_page.py
similarity index 99%
rename from scripts/tui/src/ovirt/node/plugins/status.py
rename to scripts/tui/src/ovirt/node/plugins/status_page.py
index e1c425b..550d503 100644
--- a/scripts/tui/src/ovirt/node/plugins/status.py
+++ b/scripts/tui/src/ovirt/node/plugins/status_page.py
@@ -44,7 +44,7 @@
return "Status"
def rank(self):
- return 10
+ return 0
def model(self):
if not self._model:
diff --git a/scripts/tui/src/ovirt/node/plugins/usage.py b/scripts/tui/src/ovirt/node/plugins/usage.py
index c3549f0..3da8cdd 100644
--- a/scripts/tui/src/ovirt/node/plugins/usage.py
+++ b/scripts/tui/src/ovirt/node/plugins/usage.py
@@ -43,7 +43,7 @@
def name(self):
return "Usage"
- rank = lambda self: 10
+ rank = lambda self: 999
def ui_content(self):
widgets = [
diff --git a/scripts/tui/src/ovirt/node/tui.py b/scripts/tui/src/ovirt/node/tui.py
index ff06a85..8198b7b 100644
--- a/scripts/tui/src/ovirt/node/tui.py
+++ b/scripts/tui/src/ovirt/node/tui.py
@@ -54,8 +54,10 @@
footer = u"Press ctrl+c to exit"
palette = [('header', 'white', 'dark blue'),
- ('menu.entry', '', ''),
- ('menu.entry:focus', 'white', 'light blue', 'standout'),
+ ('table', 'dark gray', ''),
+ ('table.header', 'bold', ''),
+ ('table.entry', 'dark gray', ''),
+ ('table.entry:focus', 'white', 'light blue', 'standout'),
('main.menu', 'black', ''),
('main.menu.frame', 'light gray', ''),
('plugin.widget.entry', 'dark gray', ''),
diff --git a/scripts/tui/src/ovirt/node/ui/__init__.py b/scripts/tui/src/ovirt/node/ui/__init__.py
index fc948fa..618a3e8 100644
--- a/scripts/tui/src/ovirt/node/ui/__init__.py
+++ b/scripts/tui/src/ovirt/node/ui/__init__.py
@@ -132,7 +132,7 @@
return self.children
@widgets.setter
- def widgets(self, v):
+ def set_widgets(self, v):
self.children = v
@@ -148,7 +148,7 @@
def __init__(self, title, children):
self.title = title
- self.close(False) # FIXME hack
+ self.close(False)
super(Dialog, self).__init__(children)
@Element.signal_change
@@ -236,6 +236,12 @@
class Options(Element):
+ """A selection of options
+
+ Args:
+ label: The caption of the options
+ options:
+ """
def __init__(self, label, options):
self.label = label
self.options = options
@@ -253,6 +259,12 @@
class ProgressBar(Element):
+ """A abstract progress bar.
+
+ Args:
+ current: The initial value
+ done: The maximum value
+ """
def __init__(self, current=0, done=100):
self.current(current)
self.done = done
@@ -260,6 +272,29 @@
@Element.signal_change
def current(self, current=None):
+ """Get/Set the current status
+
+ Args:
+ current: New value or None
+
+ Returns:
+ The current progress
+ """
if current is not None:
self._current = current
return self._current
+
+
+class Table(Element):
+ """Represents a simple Table with one column
+
+ Args:
+ header: A string
+ items: A list of tuples (key, label)
+ height: The height of the Table
+ """
+
+ def __init__(self, header, items, height=3):
+ self.header = header
+ self.items = items
+ self.height = height
diff --git a/scripts/tui/src/ovirt/node/ui/builder.py b/scripts/tui/src/ovirt/node/ui/builder.py
index 96aee29..7b4161c 100644
--- a/scripts/tui/src/ovirt/node/ui/builder.py
+++ b/scripts/tui/src/ovirt/node/ui/builder.py
@@ -93,6 +93,7 @@
ovirt.node.ui.Options: build_options,
ovirt.node.ui.Row: build_row,
ovirt.node.ui.ProgressBar: build_progressbar,
+ ovirt.node.ui.Table: build_table,
}
# Check if builder is available for UI Element
@@ -200,8 +201,10 @@
elif type(r) in [ovirt.node.ui.Dialog]:
w = build_page(tui, plugin, r)
dialog = tui.display_dialog(w, r.title)
+
def on_item_close_changed_cb(i, v):
dialog.close()
+
r.connect_signal("close", on_item_close_changed_cb)
else:
@@ -250,3 +253,20 @@
item.connect_signal("current", on_item_current_change_cb)
return widget
+
+
+def build_table(path, item, tui, plugin):
+ children = []
+ for key, label in item.items:
+ c = _build_tableitem(path, plugin, key, label)
+ children.append(c)
+ widget = ovirt.node.ui.widgets.TableWidget(item.header, children,
+ item.height)
+
+ return widget
+
+def _build_tableitem(path, plugin, key, label):
+ c = ovirt.node.ui.widgets.TableEntryWidget(label)
+ urwid.connect_signal(c, "click",
+ lambda w, d: plugin._on_ui_change(d), {path: key})
+ return c
diff --git a/scripts/tui/src/ovirt/node/ui/widgets.py b/scripts/tui/src/ovirt/node/ui/widgets.py
index fb358f6..bb6d4fa 100644
--- a/scripts/tui/src/ovirt/node/ui/widgets.py
+++ b/scripts/tui/src/ovirt/node/ui/widgets.py
@@ -37,20 +37,81 @@
return key
-class PluginMenuEntry(urwid.AttrMap):
- """An entry in the main menu
+class TableEntryWidget(urwid.AttrMap):
+ """An entry in a table
"""
- __text = None
+ _text = None
+ signals = ["click"]
+
+ def __init__(self, title):
+ self._text = SelectableText(title)
+# self._text = Button(title)
+# self._text.button_left = ""
+# self._text.button_right = ""
+ super(TableEntryWidget, self).__init__(self._text, 'table.entry',
+ 'table.entry:focus')
+
+ def keypress(self, size, key):
+ if self._command_map[key] != 'activate':
+ return key
+ self._emit('click')
+
+ def mouse_event(self, size, event, button, x, y, focus):
+ if button != 1 or not urwid.util.is_mouse_press(event):
+ return False
+
+ self._emit('click')
+ return True
+
+
+class TableWidget(urwid.WidgetWrap):
+ """A table, with a single column
+ """
+ __walker = None
+ __list = None
+ __list_attrmap = None
+ __linebox = None
+ __linebox_attrmap = None
+
+ signals = ['changed']
+
+ _table_attr = "table"
+ _header_attr = "table.header"
+
+ def __init__(self, header, items, height):
+ self.__label = urwid.Text(header)
+ self.__label_attrmap = urwid.AttrMap(self.__label, self._header_attr)
+ self.__items = items
+ self.__walker = urwid.SimpleListWalker(self.__items)
+ self.__list = urwid.ListBox(self.__walker)
+# self.__list_linebox = urwid.LineBox(self.__list)
+
+ def __on_item_change():
+ widget, position = self.__list.get_focus()
+ urwid.emit_signal(self, "changed", widget)
+ urwid.connect_signal(self.__walker, 'modified', __on_item_change)
+
+ self.__box = urwid.BoxAdapter(self.__list, height)
+ self.__box_attrmap = urwid.AttrMap(self.__box, self._table_attr)
+
+ self.__pile = urwid.Pile([self.__label_attrmap, self.__box])
+
+ super(TableWidget, self).__init__(self.__pile)
+
+ def set_focus(self, n):
+ self.__list.set_focus(n)
+
+
+class PluginMenuEntry(TableEntryWidget):
def __init__(self, title, plugin):
- self.__text = SelectableText(title)
- self.__text.plugin = plugin
- super(PluginMenuEntry, self).__init__(self.__text, 'menu.entry',
- 'menu.entry:focus')
+ super(PluginMenuEntry, self).__init__(title)
+ self._text.plugin = plugin
class PluginMenu(urwid.WidgetWrap):
"""The main menu listing all available plugins (which have a UI)
+ FIXME Use TableWidget
"""
__pages = None
__walker = None
@@ -236,6 +297,9 @@
selectable = lambda self: True
+ _button_attr = "plugin.widget.button"
+ _button_disabled_attr = "plugin.widget.button.disabled"
+
def __init__(self, label):
self._button = urwid.Button(label)
@@ -243,8 +307,7 @@
urwid.emit_signal(self, 'click', self)
urwid.connect_signal(self._button, 'click', on_click_cb)
- self._button_attrmap = urwid.AttrMap(self._button,
- "plugin.widget.button")
+ self._button_attrmap = urwid.AttrMap(self._button, self._button_attr)
self._padding = urwid.Padding(self._button_attrmap,
width=len(label) + 4)
@@ -254,10 +317,10 @@
def enable(self, is_enabled):
self.selectable = lambda: is_enabled
if is_enabled:
- self._button_attrmap.set_attr_map({None: ""})
+ self._button_attrmap.set_attr_map({None: self._button_attr})
else:
self._button_attrmap.set_attr_map({
- None: "plugin.widget.button.disabled"
+ None: self._button_disabled_attr
})
diff --git a/scripts/tui/src/ovirt/node/utils/__init__.py b/scripts/tui/src/ovirt/node/utils/__init__.py
index a1d2ecb..6c932cf 100644
--- a/scripts/tui/src/ovirt/node/utils/__init__.py
+++ b/scripts/tui/src/ovirt/node/utils/__init__.py
@@ -21,3 +21,33 @@
"""
Utility functions
"""
+
+import augeas as _augeas
+import logging
+
+LOGGER = logging.getLogger(__name__)
+
+
+class AugeasWrapper(object):
+ _aug = _augeas.Augeas()
+
+ def __init__(self):
+# self._aug = _augeas.Augeas() # Is broken
+ self._aug.set("/augeas/save/copy_if_rename_fails", "")
+
+ def get(self, p):
+ return self._aug.get(p)
+
+ def set(self, p, v):
+ self._aug.set(p, v)
+ self.save()
+
+ def remove(self, p):
+ self._aug.remove(p)
+ self.save()
+
+ def save(self):
+ return self._aug.save()
+
+ def match(self, p):
+ return self._aug.match(p)
diff --git a/scripts/tui/src/ovirt/node/utils/network.py b/scripts/tui/src/ovirt/node/utils/network.py
new file mode 100644
index 0000000..42d9a45
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/utils/network.py
@@ -0,0 +1,253 @@
+#!/usr/bin/python
+#
+# network.py - Copyright (C) 2012 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# 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.
+
+"""
+Some convenience functions related to networking
+"""
+
+import gudev
+import os.path
+import logging
+from ovirt.node.utils import AugeasWrapper as Augeas
+
+LOGGER = logging.getLogger(__name__)
+
+
+def _query_udev_nics():
+ client = gudev.Client(['net'])
+ devices = client.query_by_subsystem("net")
+ return [d.get_property("INTERFACE") for d in devices]
+
+
+def all_nics():
+ """Retuns all system NICs (via udev)
+
+ >>> "lo" in all_nics()
+ True
+
+ Returns:
+ Dict with NIC (name, info) mappings for all known NICS
+ """
+ return _collect_nic_informations(_query_udev_nics())
+
+
+def _collect_nic_informations(nics):
+ """Collects all NIC relevant informations for a list of NICs
+
+ >>> infos = _collect_nic_informations(_query_udev_nics())
+ >>> "lo" in infos
+ True
+ >>> "driver" in infos["lo"]
+ True
+ >>> infos["lo"]["driver"]
+ 'unknown'
+
+ Args:
+ nics: List of NIC names
+ Returns:
+ A dict of (nic-name, nic-infos-dict)
+ """
+ infos = {}
+
+ client = gudev.Client(['net'])
+ for d in client.query_by_subsystem("net"):
+# assert d.has_property("ID_VENDOR_FROM_DATABASE"), \
+# "udev informations are incomplete (udevadm re-trigger?)"
+
+ info = {"name": d.get_property("INTERFACE"),
+ "vendor": d.get_property("ID_VENDOR_FROM_DATABASE") or "unkown",
+ "devtype": d.get_property("DEVTYPE") or "unknown",
+ "devpath": d.get_property("DEVPATH")
+ }
+
+ infos[info["name"]] = info
+
+ # Check if we cover all req. NICs
+ unknown_nics = (set(nics) - set(infos))
+ if unknown_nics != set():
+ raise Exception("Couldn't gather informations for unknown NICs: %s" %
+ unknown_nics)
+
+ for name, info in infos.items():
+ LOGGER.debug("Getting additional information for '%s'" % name)
+
+ # Driver
+ driver_symlink = "/sys/class/net/%s/device/driver" % name
+ driver = "unknown"
+ if os.path.islink(driver_symlink):
+ try:
+ driver = os.path.basename(os.readlink(driver_symlink))
+ except Exception as e:
+ LOGGER.warning("Exception while reading driver " +
+ "of '%s' from '%s'" % (name, driver_symlink))
+ infos[name]["driver"] = driver
+
+
+ hwaddr = "unkown"
+ with open("/sys/class/net/%s/address" % name) as macfile:
+ hwaddr = macfile.read().strip()
+ infos[name]["hwaddr"] = hwaddr
+
+ aug = Augeas()
+ augbasepath = "/files/etc/sysconfig/network-scripts/ifcfg-%s"
+ augdevicepath = augbasepath % name
+
+ # Bootprotocol
+ info["type"] = aug.get(augdevicepath + "/TYPE")
+ if os.path.exists("/sys/class/net/%s/bridge" % name):
+ info["type"] = "bridge"
+
+ # Bootprotocol
+ info["bootproto"] = aug.get(augdevicepath + "/BOOTPROTO")
+
+ # Parent bridge
+ info["bridge"] = aug.get(augdevicepath + "/BRIDGE")
+
+ # VLAN
+ info["is_vlan"] = aug.get(augdevicepath + "/VLAN") is not None
+ if info["is_vlan"] != "." in name:
+ LOGGER.warning("NIC config says VLAN, name doesn't reflect " + \
+ "that: %s" % name)
+ if info["is_vlan"]:
+ parts = name.split(".")
+ info["vlanid"] = parts[-1:]
+ info["parent"] = ".".join(parts[:-1])
+
+ info["type"] = "vlan"
+
+
+ return infos
+
+
+def relevant_nics(filter_bridges=True, filter_vlans=True):
+ """Retuns relevant system NICs (via udev)
+
+ Filters out
+ - loop
+ - bonds
+ - vnets
+ - bridges
+ - sit
+ - vlans
+
+ >>> "lo" in relevant_nics()
+ False
+
+ >>> "eth0" in relevant_nics() or "em1" in relevant_nics()
+ True
+
+ Args:
+ filter_bridges: If bridges shall be filtered out too
+ filter_vlans: If vlans shall be filtered out too
+ Returns:
+ List of strings, the NIC names
+ """
+ is_irrelevant = lambda n, p: ( \
+ n == "lo" or \
+ n.startswith("bond") or \
+ n.startswith("sit") or \
+ n.startswith("vnet") or \
+ n.startswith("tun") or \
+ n.startswith("wlan") or \
+ (("." in n) and filter_vlans) or \
+ ((p["type"] == "bridge") and filter_bridges))
+
+ relevant_nics = {n: p for n, p in all_nics().items() \
+ if not is_irrelevant(n, p)}
+
+ irrelevant_names = set(all_nics().keys()) - set(relevant_nics.keys())
+ LOGGER.debug("Irrelevant interfaces: %s" % irrelevant_names)
+
+ return relevant_nics
+
+
+def node_nics():
+ """Returns Node's NIC model.
+ This squashes nic, bridge and vlan informations.
+
+ >>> node_nics() != None
+ True
+ """
+ all_nics = relevant_nics(filter_bridges=False, filter_vlans=False)
+
+ bridges = [nic for nic, info in all_nics.items() \
+ if info["type"] == "bridge"]
+ vlans = [nic for nic, info in all_nics.items() \
+ if info["type"] == "vlan"]
+ nics = [nic for nic, info in all_nics.items() \
+ if info["name"] not in bridges + vlans]
+
+ LOGGER.debug("Bridges: %s" % bridges)
+ LOGGER.debug("VLANs: %s" % vlans)
+ LOGGER.debug("NICs: %s" % nics)
+
+ node_nics = {}
+ for name in nics:
+ info = all_nics[name]
+ if info["bridge"]:
+ bridge = all_nics[info["bridge"]]
+ info["bootproto"] = bridge["bootproto"]
+ node_nics[name] = info
+
+ for name in vlans:
+ info = all_nics[name]
+ if info["vlanid"]:
+ node_nics[info["parent"]]["vlanid"] = info["vlanid"][0]
+
+ LOGGER.debug("Node NICs: %s" % node_nics)
+
+ return node_nics
+
+
+def _aug_get_or_set(augpath, new_servers=None):
+ """Get or set some servers
+ """
+ aug = Augeas()
+
+ servers = []
+ for path in aug.match(augpath):
+ servers.append(aug.get(path))
+
+ if new_servers:
+ itempath = lambda idx: "%s[%d]" % (augpath, idx+1)
+ for idx, server in enumerate(new_servers):
+ aug.set(itempath(idx), server)
+ if len(servers) > len(new_servers):
+ for idx in range(len(servers) + 1, len(new_servers)):
+ aug.remove(itempath(idx))
+ return servers
+
+
+def nameservers(new_servers=None):
+ """Get or set DNS servers
+ >>> len(nameservers()) > 0
+ True
+ """
+ augpath = "/files/etc/resolv.conf/nameserver"
+ return _aug_get_or_set(augpath, new_servers)
+
+
+def timeservers(new_servers=None):
+ """Get or set TIME servers
+ >>> len(nameservers()) > 0
+ True
+ """
+ augpath = "/files/etc/ntp.conf/server"
+ return _aug_get_or_set(augpath, new_servers)
diff --git a/scripts/tui/src/ovirt/node/valid.py b/scripts/tui/src/ovirt/node/valid.py
index 5965987..460ce6a 100644
--- a/scripts/tui/src/ovirt/node/valid.py
+++ b/scripts/tui/src/ovirt/node/valid.py
@@ -248,13 +248,13 @@
class IPAddress(Validator):
"""Allows any IPv4 or IPv6 address
- >>> FQDNOrIPAddress()("127.0.0.1")
+ >>> IPAddress()("127.0.0.1")
True
- >>> FQDNOrIPAddress()("::1")
+ >>> IPAddress()("::1")
True
- >>> FQDNOrIPAddress().validate("example.com")
+ >>> IPAddress().validate("example.com")
False
- >>> FQDNOrIPAddress().validate("")
+ >>> IPAddress().validate("")
False
"""
--
To view, visit http://gerrit.ovirt.org/9898
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ieed7880a31c250b03030cbaa6fbb3686776b4b19
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