[node-patches] Change in ovirt-node[master]: Add NetworkManager support if available and usable
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: Add NetworkManager support if available and usable
......................................................................
Add NetworkManager support if available and usable
If NetworkManager bindings are available use fast-path methods where
possible.
Change-Id: I97bd1236dafc5b416d132142689f143a1ffde16d
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/plugins/security_page.py
M scripts/tui/src/ovirt/node/utils/network.py
M scripts/tui/src/ovirt/node/utils/process.py
M scripts/tui/src/ovirt/node/utils/virt.py
4 files changed, 171 insertions(+), 18 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/06/9906/1
diff --git a/scripts/tui/src/ovirt/node/plugins/security_page.py b/scripts/tui/src/ovirt/node/plugins/security_page.py
index 947aba4..681e041 100644
--- a/scripts/tui/src/ovirt/node/plugins/security_page.py
+++ b/scripts/tui/src/ovirt/node/plugins/security_page.py
@@ -54,7 +54,8 @@
def validators(self):
return {
- "stringrng.bytes_used": ovirt.node.valid.Number(min=0) | ovirt.node.valid.Empty,
+ "stringrng.bytes_used": ovirt.node.valid.Number(min=0) | \
+ ovirt.node.valid.Empty,
"passwd.admin.password": ovirt.node.valid.Text(),
"passwd.admin.password_confirmation": ovirt.node.valid.Text(),
}
@@ -67,7 +68,8 @@
[("yes", "Yes"), ("no", "No")])),
("ssh._divider", ovirt.node.ui.Divider()),
- ("strongrng._label", ovirt.node.ui.Header("Strong Random Number Generator")),
+ ("strongrng._label", ovirt.node.ui.Header(
+ "Strong Random Number Generator")),
("strongrng.enabled", ovirt.node.ui.Options(
"Enable AES-NI",
[("yes", "Yes"), ("no", "No")])),
@@ -76,7 +78,8 @@
("passwd._label", ovirt.node.ui.Label("Local Access")),
- ("passwd.admin.password", ovirt.node.ui.PasswordEntry("Password:")),
+ ("passwd.admin.password", ovirt.node.ui.PasswordEntry(
+ "Password:")),
("passwd.admin.password_confirmation", ovirt.node.ui.PasswordEntry(
"Confirm Password:")),
]
diff --git a/scripts/tui/src/ovirt/node/utils/network.py b/scripts/tui/src/ovirt/node/utils/network.py
index 33b6dd8..bf2ffd0 100644
--- a/scripts/tui/src/ovirt/node/utils/network.py
+++ b/scripts/tui/src/ovirt/node/utils/network.py
@@ -22,18 +22,54 @@
Some convenience functions related to networking
"""
-import gudev
+
import os.path
import logging
+import re
from ovirt.node.utils import AugeasWrapper as Augeas
+import ovirt.node.utils.process as process
LOGGER = logging.getLogger(__name__)
-def _query_udev_nics():
+#
+# Try to use NM if available
+#
+_nm_client = None
+try:
+ from gi.repository import NetworkManager, NMClient
+ import socket
+ import struct
+ NetworkManager
+ _nm_client = NMClient.Client.new()
+except Exception as e:
+ LOGGER.warning("NetworkManager support disabled: " +
+ "NM Client not found (%s)" % e)
+import gudev
+
+
+class UnknownNicError(Exception):
+ pass
+
+
+def _query_udev_ifaces():
client = gudev.Client(['net'])
devices = client.query_by_subsystem("net")
return [d.get_property("INTERFACE") for d in devices]
+
+
+def _nm_ifaces():
+ return [d.get_iface() for d in _nm_client.get_devices()]
+
+
+def nm_managed(iface):
+ """Wether an intreface is managed by NM or not (if it's running)
+ """
+ return _nm_client and iface in _nm_ifaces()
+
+
+def all_ifaces():
+ return _query_udev_ifaces()
def all_nics():
@@ -45,13 +81,13 @@
Returns:
Dict with NIC (name, info) mappings for all known NICS
"""
- return _collect_nic_informations(_query_udev_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_nics())
+ >>> infos = _collect_nic_informations(_query_udev_ifaces())
>>> "lo" in infos
True
>>> "driver" in infos["lo"]
@@ -86,7 +122,7 @@
raise Exception("Couldn't gather informations for unknown NICs: %s" %
unknown_nics)
- for name, info in infos.items():
+ for name, info in {k: v for k, v in infos.items() if k in nics}.items():
LOGGER.debug("Getting additional information for '%s'" % name)
# Driver
@@ -166,13 +202,13 @@
n.startswith("vnet") or \
n.startswith("tun") or \
n.startswith("wlan") or \
- (("." in n) and filter_vlans) or \
- ((p["type"] == "bridge") and filter_bridges))
+ (filter_vlans and ("." in n)) or \
+ (filter_bridges and (p["type"] == "bridge")))
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())
+ irrelevant_names = set(all_ifaces()) - set(relevant_nics.keys())
LOGGER.debug("Irrelevant interfaces: %s" % irrelevant_names)
return relevant_nics
@@ -216,6 +252,23 @@
return node_nics
+def node_bridge():
+ """Returns the main bridge of this node
+
+ Returns:
+ Bridge of this node
+ """
+
+ all_nics = relevant_nics(filter_bridges=False, filter_vlans=False)
+
+ bridges = [nic for nic, info in all_nics.items() \
+ if info["type"] == "bridge"]
+
+ assert len(bridges) == 1, "Expected only one bridge: %s" % bridges
+
+ return bridges[0]
+
+
def _aug_get_or_set(augpath, new_servers=None):
"""Get or set some servers
"""
@@ -237,6 +290,7 @@
def nameservers(new_servers=None):
"""Get or set DNS servers
+
>>> len(nameservers()) > 0
True
"""
@@ -246,8 +300,94 @@
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)
+
+
+def nic_link_detected(iface):
+ """Determin if L1 is up on a given interface
+
+ >>> nic_link_detected("lo")
+ True
+
+ >>> iface = all_ifaces()[0]
+ >>> cmd = "ip link set dev {dev} up ; ip link show {dev}".format(dev=iface)
+ >>> has_carrier = "LOWER_UP" in process.pipe(cmd, without_retval=True)
+ >>> has_carrier == nic_link_detected(iface)
+ True
+
+ Args:
+ iface: The interface to be checked
+ Returns:
+ True if L1 (the-link-is-up) is detected (depends on driver support)
+ """
+
+ 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()
+
+ # Fallback
+ has_carrier = False
+ try:
+ with open("/sys/class/net/%s/carrier" % iface) as c:
+ content = c.read()
+ has_carrier = "1" in content
+ except:
+ LOGGER.debug("Carrier down for %s" % iface)
+ return has_carrier
+
+
+def nic_ip_addresses(iface, families=["inet", "inet6"]):
+ """Get IP addresses for an iface
+
+ FIXME NM client.get_device_by_iface(iface).get_ip?_config()
+ """
+ if iface not in all_ifaces():
+ raise UnknownNicError("Unknown network interface: '%s'" % iface)
+
+ addresses = {f: None for f in families}
+
+ if nm_managed(iface):
+ device = _nm_client.get_device_by_iface(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
+ 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]
+
+ return addresses
+
+
+def _nm_address_to_str(ipaddr):
+ packed = struct.pack('L', ipaddr)
+ return socket.inet_ntoa(packed)
+
+
+def networking_status():
+ status = "Not connected"
+
+ bridge = node_bridge()
+ addresses = nic_ip_addresses(bridge)
+ has_address = any([a != None for a in addresses.values()])
+
+ if nic_link_detected(bridge) and has_address:
+ status = "Connected"
+
+ return (status, bridge, addresses)
diff --git a/scripts/tui/src/ovirt/node/utils/process.py b/scripts/tui/src/ovirt/node/utils/process.py
index b433ef8..546a234 100644
--- a/scripts/tui/src/ovirt/node/utils/process.py
+++ b/scripts/tui/src/ovirt/node/utils/process.py
@@ -55,12 +55,21 @@
return popen(cmd, shell=True).wait()
-def pipe(cmd, stdin=None):
+def pipe(cmd, stdin=None, without_retval=False):
"""Run a command interactively and cath it's output.
This functions allows to pass smoe input to a running command.
+ >>> r = pipe("echo -n Hi")
+ >>> type(r[1])
+ <type 'str'>
+
+ >>> r
+ (True, 'Hi')
+
Args:
cmd: Commandline to be run
+ stdin: Optional string passed as stdin
+ without_retval: Optional if no retval should be passed
Returns:
A tuple (success, stdout)
@@ -74,6 +83,8 @@
LOGGER.debug("out '%s'" % stdout)
if stderr:
LOGGER.warning("error '%s'" % stderr)
+ if without_retval:
+ return stdout
return (system_cmd.returncode == 0, stdout)
diff --git a/scripts/tui/src/ovirt/node/utils/virt.py b/scripts/tui/src/ovirt/node/utils/virt.py
index 433b813..e99a527 100644
--- a/scripts/tui/src/ovirt/node/utils/virt.py
+++ b/scripts/tui/src/ovirt/node/utils/virt.py
@@ -25,7 +25,6 @@
import os.path
import logging
import libvirt
-import ovirt.node.utils.process as process
LOGGER = logging.getLogger(__name__)
@@ -41,10 +40,10 @@
has_module = False
with open("/proc/modules") as modules:
for line in modules:
- has_module = (line.startswith("kvm_intel") or \
- line.startswith("kvm_amd"))
- if has_module:
- break
+ has_module = (line.startswith("kvm_intel") or \
+ line.startswith("kvm_amd"))
+ if has_module:
+ break
if has_module and os.path.exists("/dev/kvm"):
has_virtualization = True
@@ -64,7 +63,7 @@
for line in cpuinfo:
if line.startswith("flags"):
if "vmx" in line or "svm" in line:
- is_enabled= True
+ is_enabled = True
return is_enabled
--
To view, visit http://gerrit.ovirt.org/9906
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I97bd1236dafc5b416d132142689f143a1ffde16d
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