[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