[node-patches] Change in ovirt-node[master]: Update several pages and TUI

fabiand at fedoraproject.org fabiand at fedoraproject.org
Tue Dec 11 20:09:36 UTC 2012


Fabian Deutsch has uploaded a new change for review.

Change subject: Update several pages and TUI
......................................................................

Update several pages and TUI

… to reflect network changes and introduce a notice field in the main
TUI.

Change-Id: Id771105b46a37e56e88480fe0bb39404874a6f50
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/app.py
M scripts/tui/src/ovirt/node/plugins/network_page.py
M scripts/tui/src/ovirt/node/plugins/status_page.py
A scripts/tui/src/ovirt/node/plugins/support_page.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/network.py
A scripts/tui/src/ovirt/node/utils/security.py
10 files changed, 433 insertions(+), 123 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/08/9908/1

diff --git a/scripts/tui/src/ovirt/node/app.py b/scripts/tui/src/ovirt/node/app.py
index 9950ca3..a46c840 100644
--- a/scripts/tui/src/ovirt/node/app.py
+++ b/scripts/tui/src/ovirt/node/app.py
@@ -65,7 +65,7 @@
     def run(self):
         self.__load_plugins()
         self.ui.register_hotkey("f12", self.__drop_to_shell)
-        self.ui.footer = "Press ctrl+x or esc to quit."
+        self.ui.footer = "Press esc to quit."
         self.ui.run()
 
     def quit(self):
diff --git a/scripts/tui/src/ovirt/node/plugins/network_page.py b/scripts/tui/src/ovirt/node/plugins/network_page.py
index 1fe4321..257af73 100644
--- a/scripts/tui/src/ovirt/node/plugins/network_page.py
+++ b/scripts/tui/src/ovirt/node/plugins/network_page.py
@@ -36,7 +36,13 @@
     """This is the network page
     """
 
-    _model = None
+    _model = {
+        "hostname": "localhost.example.com",
+        "dns[0]": "192.168.122.1",
+        "dns[1]": "",
+        "ntp[0]": "fedora.pool.ntp.org",
+        "ntp[1]": "",
+    }
     _widgets = None
 
     def name(self):
@@ -46,15 +52,6 @@
         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
@@ -98,9 +95,6 @@
             ("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)
@@ -117,7 +111,10 @@
                     "p1p6     Unconfigured   bnx2     10:21:32:43:54:65"),
                 ]
         node_nics = []
+        first_nic = None
         for name, nic in ovirt.node.utils.network.node_nics().items():
+            if first_nic == None:
+                first_nic = name
             bootproto = "Configured" if nic["bootproto"] else "Unconfigured"
             description = " ".join([
                 justify(nic["name"], 8),
@@ -126,13 +123,90 @@
                 justify(nic["hwaddr"], 17)
                 ])
             node_nics.append((name, description))
+        self._model["nics"] = first_nic
         return node_nics
+
+    def _build_dialog(self, path, txt, widgets):
+        self._widgets.update(dict(widgets))
+        self._widgets[path] = ovirt.node.ui.Dialog(txt, widgets)
+        return self._widgets[path]
+
+    def _build_nic_details_dialog(self):
+        # Populate model with nic specific informations
+        iface = self._model["nics"]
+        LOGGER.debug("Getting informations for NIC details page")
+        info = ovirt.node.utils.network.node_nics(with_live=True)[iface]
+
+        self._model.update({
+            "dialog.nic.iface": info["name"],
+            "dialog.nic.driver": info["driver"],
+            "dialog.nic.protocol": info["bootproto"] or "N/A",
+            "dialog.nic.vendor": info["vendor"],
+            "dialog.nic.link_status": "Connected" if info["link_detected"]
+                                                  else "Disconnected",
+            "dialog.nic.hwaddress": info["hwaddr"],
+            "dialog.nic.ipv4.bootproto": info["bootproto"],
+            "dialog.nic.ipv4.address": info["ipaddr"] or "",
+            "dialog.nic.ipv4.netmask": info["netmask"] or "",
+            "dialog.nic.ipv4.gateway": info["gateway"] or "",
+            "dialog.nic.vlanid": "none",
+        })
+
+        padd = lambda l: l.ljust(14)
+        return self._build_dialog("dialog.nic", "NIC Details: %s" % iface, [
+            ("dialog.nic._row[0]", ovirt.node.ui.Row([
+                ("dialog.nic.iface",
+                    ovirt.node.ui.KeywordLabel(padd("Interface: "))),
+                ("dialog.nic.driver",
+                    ovirt.node.ui.KeywordLabel(padd("Driver: "))),
+                ])),
+
+            ("dialog.nic._row[1]", ovirt.node.ui.Row([
+                ("dialog.nic.protocol",
+                    ovirt.node.ui.KeywordLabel(padd("Protocol: "))),
+                ("dialog.nic.vendor",
+                    ovirt.node.ui.KeywordLabel(padd("Vendor: "))),
+                ])),
+
+            ("dialog.nic._row[2]", ovirt.node.ui.Row([
+                ("dialog.nic.link_status",
+                    ovirt.node.ui.KeywordLabel(padd("Link Status: "))),
+                ("dialog.nic.hwaddress",
+                    ovirt.node.ui.KeywordLabel(padd("MAC Address: "))),
+                ])),
+
+            ("dialog.nic._divider[0]", ovirt.node.ui.Divider()),
+
+            ("dialog.nic.ipv4._header", ovirt.node.ui.Header("IPv4 Settings")),
+            ("dialog.nic.ipv4.bootproto", ovirt.node.ui.Options(
+                "Bootprotocol: ", [
+                    ("none", "Disabled"),
+                    ("dhcp", "DHCP"),
+                    ("static", "Static")
+                ])),
+            ("dialog.nic.ipv4.address",
+                    ovirt.node.ui.Entry(padd("IP Address: "))),
+            ("dialog.nic.ipv4.netmask",
+                    ovirt.node.ui.Entry(padd("Netmask: "))),
+            ("dialog.nic.ipv4.gateway",
+                    ovirt.node.ui.Entry(padd("Gateway: "))),
+
+            ("dialog.nic._divider[1]", ovirt.node.ui.Divider()),
+
+            ("dialog.nic.vlanid",
+                    ovirt.node.ui.Entry(padd("VLAN ID: "))),
+        ])
 
     def on_change(self, changes):
         pass
 
     def on_merge(self, effective_changes):
-        effective_model = self._model.update(effective_changes)
+        changes = self.pending_changes(False)
+        effective_model = dict(self._model)
+        effective_model.update(effective_changes)
+        LOGGER.info("effm %s" % effective_model)
+        LOGGER.info("effc %s" % effective_changes)
+        LOGGER.info("allc %s" % changes)
 
         if "dns[0]" in effective_changes or \
            "dns[1]" in effective_changes:
@@ -147,3 +221,8 @@
                              if k.startswith("ntp[")]
             LOGGER.info("Setting new timeservers: %s" % new_servers)
             ovirt.node.utils.network.timeservers(new_servers)
+
+        if "nics" in changes:
+            iface = changes["nics"]
+            LOGGER.debug("Opening NIC Details dialog for '%s'" % iface)
+            return self._build_nic_details_dialog()
diff --git a/scripts/tui/src/ovirt/node/plugins/status_page.py b/scripts/tui/src/ovirt/node/plugins/status_page.py
index 550d503..5c08068 100644
--- a/scripts/tui/src/ovirt/node/plugins/status_page.py
+++ b/scripts/tui/src/ovirt/node/plugins/status_page.py
@@ -22,11 +22,14 @@
 Status plugin
 """
 import logging
+import textwrap
 
 import ovirt.node.plugins
 import ovirt.node.valid
 import ovirt.node.ui
-import ovirt.node.utils
+import ovirt.node.utils as utils
+import ovirt.node.utils.virt as virt
+import ovirt.node.utils.security
 
 LOGGER = logging.getLogger(__name__)
 
@@ -47,15 +50,20 @@
         return 0
 
     def model(self):
-        if not self._model:
-            self._model = {
-                "status": "Virtualization hardware was not detected",
-                "networking": "On",
-                "networking.bridge": "breth0: 192.168.122.1",
-                "logs": "Local Only",
-                "libvirt.num_guests": "42",
-            }
-        return self._model
+        net_status, net_br, net_addrs = utils.network.networking_status()
+        net_addrs_str = "\nIPv4: {inet}\nIPv6: {inet6}".format(**net_addrs)
+
+        num_domains = "N/A"
+        with virt.LibvirtConnection() as con:
+            num_domains = str(con.numOfDomains())
+
+        return {
+            "status": virt.virtualization_hardware_status(),
+            "networking": net_status,
+            "networking.bridge": "%s %s" % (net_br, net_addrs_str),
+            "logs": "Local Only",
+            "libvirt.num_guests": num_domains,
+        }
 
     def ui_content(self):
         """Describes the UI this plugin requires
@@ -69,8 +77,16 @@
                 ("networking",
                     ovirt.node.ui.KeywordLabel(aligned("Networking: "))),
                 ("networking.bridge",
-                    ovirt.node.ui.Label("N/A")),
+                    ovirt.node.ui.KeywordLabel("Bridge: ")),
             ]
+
+        action_widgets = [
+            ("action.lock", ovirt.node.ui.Button("Lock")),
+            ("action.logoff", ovirt.node.ui.Button("Log Off")),
+            ("action.restart", ovirt.node.ui.Button("Restart")),
+            ("action.poweroff", ovirt.node.ui.Button("Poweroff")),
+        ]
+
         widgets = [
             ("status",
                 ovirt.node.ui.KeywordLabel(aligned("Status: "))),
@@ -91,8 +107,8 @@
             ("support._space", ovirt.node.ui.Divider()),
 
             ("action.hostkey", ovirt.node.ui.Button("View Host Key")),
-#            ("action", ovirt.node.ui.Buttons(["Lock", "Log Off", "Restart",
-#                                              "Power Off"])),
+
+            ("action._row", ovirt.node.ui.Row(action_widgets)),
         ]
         # Save it "locally" as a dict, for better accessability
         self._widgets = dict(widgets)
@@ -100,3 +116,51 @@
         page = ovirt.node.ui.Page(widgets)
         page.has_save_button = False
         return page
+
+    def on_change(self, changes):
+        pass
+
+    def on_merge(self, changes):
+        # Handle button presses
+        if "action.lock" in changes:
+            LOGGER.info("Locking screen")
+
+        elif "action.logoff" in changes:
+            LOGGER.info("Logging off")
+            self.application.quit()
+
+        elif "action.restart" in changes:
+            LOGGER.info("Restarting")
+
+        elif "action.poweroff" in changes:
+            LOGGER.info("Shutting down")
+
+        elif "action.hostkey" in changes:
+            LOGGER.info("Showing hostkey")
+            return self._build_hostkey_dialog()
+
+        elif "_save" in changes:
+            self._widgets["dialog.hostkey"].close()
+
+
+    def _build_dialog(self, path, txt, widgets):
+        self._widgets.update(dict(widgets))
+        self._widgets[path] = ovirt.node.ui.Dialog(txt, widgets)
+        return self._widgets[path]
+
+
+    def _build_hostkey_dialog(self):
+        fp, hk = ovirt.node.utils.security.get_ssh_hostkey()
+        return self._build_dialog("dialog.hostkey", "Host Key", [
+            ("hostkey.fp._label",
+                ovirt.node.ui.Label("RSA Host Key Fingerprint:")),
+            ("hostkey.fp",
+                ovirt.node.ui.Label(fp)),
+
+            ("hostkey._divider", ovirt.node.ui.Divider()),
+
+            ("hostkey._label",
+                ovirt.node.ui.Label("RSA Host Key:")),
+            ("hostkey",
+                ovirt.node.ui.Label("\n".join(textwrap.wrap(hk, 64)))),
+        ])
diff --git a/scripts/tui/src/ovirt/node/plugins/support_page.py b/scripts/tui/src/ovirt/node/plugins/support_page.py
new file mode 100644
index 0000000..0b1ed0b
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/plugins/support_page.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+#
+# support_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.
+
+"""
+A plugin for a support page
+"""
+import logging
+
+import ovirt.node.plugins
+import ovirt.node.ui
+
+
+LOGGER = logging.getLogger(__name__)
+
+
+class Plugin(ovirt.node.plugins.NodePlugin):
+    def __init__(self, application):
+        # Register F8: Display this plugin when F( is pressed
+        application.ui.register_hotkey(["f8"], 
+                                lambda: application.ui.display_plugin(self))
+
+    def name(self):
+        return "Support"
+
+    rank = lambda self: 999
+
+    has_ui = lambda self: False
+
+    def ui_content(self):
+        widgets = [
+            ("features.info", ovirt.node.ui.Label("FIXME Support info"))
+        ]
+
+        page = ovirt.node.ui.Page(widgets)
+        page.has_save_button = False
+        return page
+
+    def model(self):
+        return {}
diff --git a/scripts/tui/src/ovirt/node/tui.py b/scripts/tui/src/ovirt/node/tui.py
index 0fcd2db..dc5c1d5 100644
--- a/scripts/tui/src/ovirt/node/tui.py
+++ b/scripts/tui/src/ovirt/node/tui.py
@@ -49,7 +49,7 @@
     __menu = None
     __page_frame = None
 
-    __dialogs = []
+    __widget_stack = []
 
     header = u"\n Configuration TUI\n"
     footer = u"Press ctrl+c to exit"
@@ -61,6 +61,7 @@
                ('table.entry:focus', 'white', 'light blue', 'standout'),
                ('main.menu', 'black', ''),
                ('main.menu.frame', 'light gray', ''),
+               ('notice', 'light red', ''),
                ('plugin.widget.entry', 'dark gray', ''),
                ('plugin.widget.entry.disabled', 'dark gray', 'light gray'),
                ('plugin.widget.entry.label', 'dark gray, bold', ''),
@@ -87,21 +88,31 @@
         self.__menu = ovirt.node.ui.widgets.PluginMenu(self.__pages)
 
         def menu_item_changed(plugin):
-            self.__change_to_plugin(plugin)
+            self.display_plugin(plugin)
         urwid.connect_signal(self.__menu, 'changed', menu_item_changed)
 
     def __create_screen(self):
         self.__build_menu()
         self.__page_frame = urwid.Frame(urwid.Filler(urwid.Text("")))
         self.__menu.set_focus(0)
-        body = urwid.Columns([("weight", 0.5, self.__menu),
+
+        self.__notice = urwid.Text("Note: ")
+        self.__notice_filler = urwid.Filler(self.__notice)
+        self.__notice_attrmap = urwid.AttrMap(self.__notice_filler, "notice")
+
+        menu_frame_columns = urwid.Columns([("weight", 0.5, self.__menu),
                               self.__page_frame], 4)
+
+        body = urwid.Pile([("fixed", 3, self.__notice_attrmap),
+                           menu_frame_columns
+                        ])
+
         header = urwid.Text(self.header, wrap='clip')
         header = urwid.AttrMap(header, 'header')
         footer = urwid.Text(self.footer, wrap='clip')
         return urwid.Frame(body, header, footer)
 
-    def __change_to_plugin(self, plugin):
+    def display_plugin(self, plugin):
         timer = timeit.Timer()
         page = ovirt.node.ui.builder.page_from_plugin(self, plugin)
         self.display_page(page)
@@ -114,17 +125,24 @@
         self.__page_frame.body = filler
 
     def display_dialog(self, body, title):
+        LOGGER.debug("Displaying dialog: %s / %s" % (body, title))
         filler = urwid.Filler(body, ("fixed top", 1), height=20)
         dialog = ovirt.node.ui.widgets.ModalDialog(title, filler, "esc",
                                                    self.__loop.widget)
-        urwid.connect_signal(dialog, "close", lambda: self.close_dialog())
+        urwid.connect_signal(dialog, "close", lambda: self.close_dialog(dialog))
         self.__loop.widget = dialog
+        self.__widget_stack.append(dialog)
         return dialog
 
-    def close_dialog(self):
+    def close_dialog(self, dialog):
         # FIXME stack to allow more than one dialog
         if type(self.__loop.widget) is ovirt.node.ui.widgets.ModalDialog:
-            self.__loop.widget = self.__loop.widget.previous_widget
+            if dialog == self.__widget_stack[-1]:
+                self.__widget_stack.pop()
+                if len(self.__widget_stack) > 0:
+                    self.__loop.widget = self.__widget_stack[:-1]
+                else:
+                    self.__loop.widget = self.__main_frame
             LOGGER.debug("Dialog closed")
 
     def popup(self, title, msg, buttons=None):
@@ -137,10 +155,9 @@
 
         if type(self.__loop.widget) is ovirt.node.ui.widgets.ModalDialog:
             LOGGER.debug("Modal dialog escape: %s" % key)
-            dialog = self.__loop.widget
-            if dialog.escape_key in keys:
-                self.close_dialog()
-#            return
+            if self.__loop.widget.escape_key in keys:
+                self.close_dialog(self.__widget_stack[-1])
+                return
 
         if key in self.__hotkeys.keys():
             LOGGER.debug("Running hotkeys: %s" % key)
diff --git a/scripts/tui/src/ovirt/node/ui/__init__.py b/scripts/tui/src/ovirt/node/ui/__init__.py
index 20c650c..aac852c 100644
--- a/scripts/tui/src/ovirt/node/ui/__init__.py
+++ b/scripts/tui/src/ovirt/node/ui/__init__.py
@@ -290,7 +290,7 @@
         height: The height of the Table
     """
 
-    def __init__(self, header, items, height=3):
+    def __init__(self, header, items, height=5):
         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 a2948d5..38f74e1 100644
--- a/scripts/tui/src/ovirt/node/ui/builder.py
+++ b/scripts/tui/src/ovirt/node/ui/builder.py
@@ -57,7 +57,7 @@
     # Always create the SaveButton, but only display it if requested
     #save = ovirt.node.ui.widgets.Button("Save")
     #urwid.connect_signal(save, 'click', lambda x: plugin._on_ui_save())
-    save = build_button("", ovirt.node.ui.SaveButton(), tui, plugin)
+    save = build_button("_save", ovirt.node.ui.SaveButton(), tui, plugin)
     plugin._save_button = save
 
     for path, item in container.children:
@@ -187,28 +187,16 @@
     widget = ovirt.node.ui.widgets.Button(item.text())
 
     def on_widget_click_cb(widget, data=None):
-        LOGGER.debug("Button click: %s" % widget)
-        if type(item) is ovirt.node.ui.SaveButton:
-            r = plugin._on_ui_save()
-            LOGGER.debug("SaveButton clicked: %s" % r)
+        LOGGER.debug("Button click: %s %s" % (path, widget))
+#        if type(item) is ovirt.node.ui.SaveButton:
+        plugin._on_ui_change({path: True})
+        r = plugin._on_ui_save()
+        parse_plugin_result(tui, plugin, r)
 
-            if type(r) in [ovirt.node.ui.Page]:
-                w = build_page(tui, plugin, r)
-                tui.display_page(w)
-
-            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:
+#        else:
 #           Not propagating the signal as a signal to the plugin
 #           item.emit_signal("click", widget)
-            plugin._on_ui_change({path: True})
+#            plugin._on_ui_change({path: True})
     urwid.connect_signal(widget, "click", on_widget_click_cb)
 
     return widget
@@ -255,16 +243,41 @@
 def build_table(path, item, tui, plugin):
     children = []
     for key, label in item.items:
-        c = _build_tableitem(path, plugin, key, label)
+        c = _build_tableitem(tui, path, plugin, key, label)
         children.append(c)
     widget = ovirt.node.ui.widgets.TableWidget(item.header, children,
                                                item.height)
+    urwid.connect_signal(widget, "changed",
+                         lambda w: plugin._on_ui_change({path: w._key}))
 
     return widget
 
 
-def _build_tableitem(path, plugin, key, label):
+def _build_tableitem(tui, 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})
+    c._key = key
+
+    def on_click_cb(widget, data):
+        parse_plugin_result(tui, plugin, plugin._on_ui_save())
+    urwid.connect_signal(c, "click", on_click_cb)
     return c
+
+
+def parse_plugin_result(tui, plugin, result):
+        LOGGER.debug("Parsing: %s" % result)
+
+        if type(result) in [ovirt.node.ui.Page]:
+            LOGGER.debug("Page requested.")
+            w = build_page(tui, plugin, result)
+            tui.display_page(w)
+
+        elif type(result) in [ovirt.node.ui.Dialog]:
+            LOGGER.debug("Dialog requested.")
+            w = build_page(tui, plugin, result)
+            dialog = tui.display_dialog(w, result.title)
+
+            def on_item_close_changed_cb(i, v):
+                dialog.close()
+            result.connect_signal("close", on_item_close_changed_cb)
+
+        return result
diff --git a/scripts/tui/src/ovirt/node/ui/widgets.py b/scripts/tui/src/ovirt/node/ui/widgets.py
index defe838..455705e 100644
--- a/scripts/tui/src/ovirt/node/ui/widgets.py
+++ b/scripts/tui/src/ovirt/node/ui/widgets.py
@@ -55,7 +55,7 @@
     def keypress(self, size, key):
         if self._command_map[key] != 'activate':
             return key
-        self._emit('click')
+        self._emit('click', None)
 
     def mouse_event(self, size, event, button, x, y, focus):
         if button != 1 or not urwid.util.is_mouse_press(event):
diff --git a/scripts/tui/src/ovirt/node/utils/network.py b/scripts/tui/src/ovirt/node/utils/network.py
index bf2ffd0..22726f7 100644
--- a/scripts/tui/src/ovirt/node/utils/network.py
+++ b/scripts/tui/src/ovirt/node/utils/network.py
@@ -26,6 +26,7 @@
 import os.path
 import logging
 import re
+
 from ovirt.node.utils import AugeasWrapper as Augeas
 import ovirt.node.utils.process as process
 
@@ -62,7 +63,7 @@
     return [d.get_iface() for d in _nm_client.get_devices()]
 
 
-def nm_managed(iface):
+def is_nm_managed(iface):
     """Wether an intreface is managed by NM or not (if it's running)
     """
     return _nm_client and iface in _nm_ifaces()
@@ -72,20 +73,8 @@
     return _query_udev_ifaces()
 
 
-def all_nics():
+def iface_informations(ifaces, with_live=False):
     """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_ifaces())
-
-
-def _collect_nic_informations(nics):
-    """Collects all NIC relevant informations for a list of NICs
 
     >>> infos = _collect_nic_informations(_query_udev_ifaces())
     >>> "lo" in infos
@@ -117,12 +106,13 @@
         infos[info["name"]] = info
 
     # Check if we cover all req. NICs
-    unknown_nics = (set(nics) - set(infos))
-    if unknown_nics != set():
+    unknown_ifaces = (set(ifaces) - set(infos))
+    if unknown_ifaces != set():
         raise Exception("Couldn't gather informations for unknown NICs: %s" %
-                        unknown_nics)
+                        unknown_ifaces)
 
-    for name, info in {k: v for k, v in infos.items() if k in nics}.items():
+    _infos = {}
+    for name, info in {k: v for k, v in infos.items() if k in ifaces}.items():
         LOGGER.debug("Getting additional information for '%s'" % name)
 
         # Driver
@@ -135,24 +125,28 @@
                 LOGGER.warning(("Exception %s while reading driver " +
                                 "of '%s' from '%s'") % (e, name,
                                                         driver_symlink))
-        infos[name]["driver"] = driver
+        info["driver"] = driver
 
         hwaddr = "unkown"
         with open("/sys/class/net/%s/address" % name) as macfile:
             hwaddr = macfile.read().strip()
-        infos[name]["hwaddr"] = hwaddr
+        info["hwaddr"] = hwaddr
 
         aug = Augeas()
         augbasepath = "/files/etc/sysconfig/network-scripts/ifcfg-%s"
         augdevicepath = augbasepath % name
 
-        # Bootprotocol
+        # Type
         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")
+        for p in ["IPADDR", "NETMASK", "GATEWAY"]:
+            info[p.lower()] = aug.get(augdevicepath + "/" + p)
+
+        # FIXME IPv6
 
         # Parent bridge
         info["bridge"] = aug.get(augdevicepath + "/BRIDGE")
@@ -169,10 +163,28 @@
 
             info["type"] = "vlan"
 
-    return infos
+        if with_live:
+            info.update(_collect_live_informations(name))
+
+        _infos[name] = info
+
+    return _infos
 
 
-def relevant_nics(filter_bridges=True, filter_vlans=True):
+def _collect_live_informations(iface):
+    LOGGER.debug("Gathering live informations for '%s'" % iface)
+    info = {}
+
+    # Current IP addresses
+    info["addresses"] = nic_ip_addresses(iface)
+
+    # Current link state
+    info["link_detected"] = nic_link_detected(iface)
+
+    return info
+
+
+def relevant_ifaces(filter_bridges=True, filter_vlans=True):
     """Retuns relevant system NICs (via udev)
 
     Filters out
@@ -183,10 +195,10 @@
     - sit
     - vlans
 
-    >>> "lo" in relevant_nics()
+    >>> "lo" in relevant_ifaces()
     False
 
-    >>> "eth0" in relevant_nics() or "em1" in relevant_nics()
+    >>> "eth0" in relevant_ifaces() or "em1" in relevant_ifaces()
     True
 
     Args:
@@ -195,33 +207,37 @@
     Returns:
         List of strings, the NIC names
     """
-    is_irrelevant = lambda n, p: ( \
+    valid_name = lambda n: not ( \
             n == "lo" or \
             n.startswith("bond") or \
             n.startswith("sit") or \
             n.startswith("vnet") or \
             n.startswith("tun") or \
             n.startswith("wlan") or \
-            (filter_vlans and ("." in n)) or \
-            (filter_bridges and (p["type"] == "bridge")))
+            (filter_vlans and ("." in n)))
+    valid_props = lambda i, p: (filter_bridges and (p["type"] == "bridge"))
 
-    relevant_nics = {n: p for n, p in all_nics().items() \
-                          if not is_irrelevant(n, p)}
+    relevant_ifaces = [iface for iface in all_ifaces() if valid_name(iface)]
+#    relevant_ifaces = {iface: props for iface, props \
+#                     in _collect_nic_informations(relevant_ifaces).items() \
+#                     if valid_props(iface, props)}
 
-    irrelevant_names = set(all_ifaces()) - set(relevant_nics.keys())
+    irrelevant_names = set(all_ifaces()) - set(relevant_ifaces)
     LOGGER.debug("Irrelevant interfaces: %s" % irrelevant_names)
+    LOGGER.debug("Relevant interfaces: %s" % relevant_ifaces)
 
-    return relevant_nics
+    return relevant_ifaces
 
 
-def node_nics():
+def node_nics(with_live=False):
     """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)
+    all_nics = relevant_ifaces(filter_bridges=False, filter_vlans=False)
+    all_nics = iface_informations(all_nics, with_live)
 
     bridges = [nic for nic, info in all_nics.items() \
                if info["type"] == "bridge"]
@@ -239,7 +255,9 @@
         info = all_nics[name]
         if info["bridge"]:
             bridge = all_nics[info["bridge"]]
-            info["bootproto"] = bridge["bootproto"]
+            for k in ["bootproto", "ipaddr", "netmask", "gateway"]:
+                if k in bridge:
+                    info[k] = bridge[k]
         node_nics[name] = info
 
     for name in vlans:
@@ -252,19 +270,21 @@
     return node_nics
 
 
-def node_bridge():
+def node_bridge(with_live=False):
     """Returns the main bridge of this node
 
     Returns:
         Bridge of this node
     """
 
-    all_nics = relevant_nics(filter_bridges=False, filter_vlans=False)
+    all_nics = relevant_ifaces(filter_bridges=False, filter_vlans=False)
+    all_nics = iface_informations(all_nics, with_live)
 
     bridges = [nic for nic, info in all_nics.items() \
                if info["type"] == "bridge"]
 
-    assert len(bridges) == 1, "Expected only one bridge: %s" % bridges
+    if len(bridges) != 1:
+        LOGGER.warning("Expected exactly one bridge: %s" % bridges)
 
     return bridges[0]
 
@@ -329,10 +349,13 @@
     if iface not in all_ifaces():
         raise UnknownNicError("Unknown network interface: '%s'" % iface)
 
-    if nm_managed(iface):
-        device = _nm_client.get_device_by_iface(iface)
-        if device:
-            return device.get_carrier()
+    if is_nm_managed(iface):
+        try:
+            device = _nm_client.get_device_by_iface(iface)
+            if device:
+                return device.get_carrier()
+        except:
+            LOGGER.debug("Failed to retrieve carrier with NM")
 
     # Fallback
     has_carrier = False
@@ -355,39 +378,52 @@
 
     addresses = {f: None for f in families}
 
-    if nm_managed(iface):
+    if False: # FIXME to hackish to convert addr - is_nm_managed(iface):
         device = _nm_client.get_device_by_iface(iface)
+        LOGGER.debug("Got '%s' for '%s'" % (device, iface))
         if device:
-            for family, addrs in [
-                ("inet", device.get_ipv4_config().get_addresses()),
-                ("inet6", device.get_ipv6_config().get_addresses())]:
-                addr = addrs[0] if len(addrs) > 0 else None
-                addresses[family] = _nm_address_to_str(addr) if addr else None
+            for family, cfgfunc, sf in [
+                ("inet", device.get_ip4_config, socket.AF_INET),
+                ("inet6", device.get_ip6_config, socket.AF_INET6)]:
+                cfg = cfgfunc()
+                if not cfg:
+                    LOGGER.debug("No %s configuration for %s" % (family,
+                                                                 iface))
+                    break
+                addrs = cfg.get_addresses()
+                addr = addrs[0].get_address() if len(addrs) > 0 else None
+                addresses[family] = _nm_address_to_str(sf, addr) if addr \
+                                                                 else None
         return addresses
 
     # Fallback
     cmd = "ip -o addr show {dev}".format(dev=iface)
     for line in process.pipe(cmd, without_retval=True).split("\n"):
         token = re.split("\s+", line)
-        if re.search("\sinet[6]\s", line):
-            addresses[token[1]] = token[3]
+        if re.search("\sinet[6]?\s", line):
+            addresses[token[2]] = token[3]
 
     return addresses
 
 
-def _nm_address_to_str(ipaddr):
-    packed = struct.pack('L', ipaddr)
-    return socket.inet_ntoa(packed)
+def _nm_address_to_str(family, ipaddr):
+    if family == socket.AF_INET:
+        packed = struct.pack('L', ipaddr)
+    elif family == socket.AF_INET6:
+        packed = ipaddr
+    return socket.inet_ntop(family, packed)
 
 
-def networking_status():
+def networking_status(iface=None):
     status = "Not connected"
 
-    bridge = node_bridge()
-    addresses = nic_ip_addresses(bridge)
+    iface = iface or node_bridge()
+    addresses = nic_ip_addresses(iface)
     has_address = any([a != None for a in addresses.values()])
 
-    if nic_link_detected(bridge) and has_address:
+    if nic_link_detected(iface) and has_address:
         status = "Connected"
 
-    return (status, bridge, addresses)
+    summary = (status, iface, addresses)
+    LOGGER.debug(summary)
+    return summary
diff --git a/scripts/tui/src/ovirt/node/utils/security.py b/scripts/tui/src/ovirt/node/utils/security.py
new file mode 100644
index 0000000..2259955
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/utils/security.py
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+#
+# virt.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 security
+"""
+
+import os.path
+import logging
+import ovirt.node.utils.process as process
+
+LOGGER = logging.getLogger(__name__)
+
+
+def get_ssh_hostkey(variant="rsa"):
+    fn_hostkey = "/etc/ssh/ssh_host_%s_key.pub" % variant
+    if not os.path.exists(fn_hostkey):
+        raise Exception("SSH hostkey does not yet exist.")
+
+    hostkey = None
+    with open(fn_hostkey) as hkf:
+        hostkey = hkf.read()
+
+
+    hostkey_fp_cmd = "ssh-keygen -l -f '%s'" % fn_hostkey
+    stdout = process.pipe(hostkey_fp_cmd, without_retval=True)
+    fingerprint = stdout.strip().split(" ")[1]
+    return (fingerprint, hostkey)


--
To view, visit http://gerrit.ovirt.org/9908
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id771105b46a37e56e88480fe0bb39404874a6f50
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