[node-patches] Change in ovirt-node[master]: network: Generate Node's specififc network model

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


Fabian Deutsch has uploaded a new change for review.

Change subject: network: Generate Node's specififc network model
......................................................................

network: Generate Node's specififc network model

Squashes the live and config information sof the current system into
Node's model (bridge, slave/vlan-slave).

Change-Id: I18bea9717f1c7438a4ec45c25814366a1cae5b37
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/ovirt/node/config/__init__.py
M scripts/tui/src/ovirt/node/config/network.py
A scripts/tui/src/ovirt/node/model.py
M scripts/tui/src/ovirt/node/plugins/network_page.py
M scripts/tui/src/ovirt/node/utils/__init__.py
M scripts/tui/src/ovirt/node/utils/fs.py
M scripts/tui/src/ovirt/node/utils/network.py
M scripts/tui/src/ovirt/node/utils/security.py
8 files changed, 366 insertions(+), 151 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/14/9914/1

diff --git a/scripts/tui/src/ovirt/node/config/__init__.py b/scripts/tui/src/ovirt/node/config/__init__.py
index c86265c..efba4d2 100644
--- a/scripts/tui/src/ovirt/node/config/__init__.py
+++ b/scripts/tui/src/ovirt/node/config/__init__.py
@@ -1,118 +1 @@
-#!/usr/bin/python
-#
-# __init__.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.
-
-"""
-Config functions
-"""
-
-import logging
-
-LOGGER = logging.getLogger(__name__)
-
-
-def configure_networking(iface, bootproto, ipaddr=None, netmask=None, gw=None,
-                         vlanid=None):
-    """Sets
-        - OVIRT_BOOTIF
-        - OVIRT_IP_ADDRESS, OVIRT_IP_NETMASK, OVIRT_IP_GATEWAY
-        - OVIRT_VLAN
-        - OVIRT_IPV6
-    """
-    if bootproto == "dhcp":
-        pass
-    elif bootproto == "static":
-        pass
-
-
-def disable_networking():
-    """Unsets
-        - OVIRT_BOOTIF
-        - OVIRT_IP_ADDRESS, OVIRT_IP_NETMASK, OVIRT_IP_GATEWAY
-        - OVIRT_VLAN
-        - OVIRT_IPV6
-    """
-    pass
-
-
-def nameservers(servers):
-    """Sets OVIRT_DNS
-
-    Args:
-        servers: List of servers (str)
-    """
-    pass
-
-
-def timeservers(servers):
-    """Sets OVIRT_NTP
-
-    Args:
-        servers: List of servers (str)
-    """
-    pass
-
-
-def syslog(server, port):
-    """Sets OVIRT_SYSLOG_{SERVER,PORT}
-    """
-    pass
-
-
-def collectd(server, port):
-    """Sets OVIRT_COLLECTD_{SERVER,PORT}
-    """
-    pass
-
-
-def rhn(rhntype, url, ca_cert, username, password, profile, activationkey, org,
-        proxy, proxyuser, proxypassword):
-    """Sets ...
-    """
-    pass
-
-
-def kdump(nfs, ssh):
-    """Sets ...
-    """
-    pass
-
-
-def iscsi(name, target_name, target_host, target_port):
-    """Sets ...
-    """
-    pass
-
-
-def snmp(password):
-    """Sets ...
-    """
-    pass
-
-
-def netconsole(server, port):
-    """Sets ...
-    """
-    pass
-
-
-def cim(enabled):
-    """Sets ...
-    """
-    pass
+# And ...
diff --git a/scripts/tui/src/ovirt/node/config/network.py b/scripts/tui/src/ovirt/node/config/network.py
index 499072e..110d460 100644
--- a/scripts/tui/src/ovirt/node/config/network.py
+++ b/scripts/tui/src/ovirt/node/config/network.py
@@ -63,15 +63,21 @@
 
     # VLAN
     info["is_vlan"] = aug.get(augdevicepath + "/VLAN", True) is not None
-    if info["is_vlan"] != "." in iface:
-        LOGGER.warning("NIC config says VLAN, name doesn't reflect " + \
-                       "that: %s" % iface)
-    if info["is_vlan"]:
+    name_says_vlan = "." in iface
+    if info["is_vlan"] != name_says_vlan:
+        LOGGER.warning("NIC config says the device is a VLAN, but the name" + \
+                       "doesn't reflect that: %s (%s vs %s)" % (iface,
+                                                            info["is_vlan"],
+                                                            name_says_vlan))
+
+    if info["is_vlan"] is True:
         parts = iface.split(".")
-        info["vlanid"] = parts[-1:]
+        vlanid = parts[-1:][0]
+        info["vlanid"] = vlanid
         info["vlan_parent"] = ".".join(parts[:-1])
 
         info["type"] = "vlan"
+        LOGGER.debug("Found VLAN %s on %s" % (str(vlanid), iface))
     else:
         info["vlanid"] = None
 
@@ -90,8 +96,10 @@
     if new_servers:
         itempath = lambda idx: "%s[%d]" % (augpath, idx + 1)
         for idx, server in enumerate(new_servers):
+            LOGGER.debug("Setting server: %s" % server)
             aug.set(itempath(idx), server)
         if len(servers) > len(new_servers):
+            LOGGER.debug("Less servers than before, removing old ones")
             for idx in range(len(servers) + 1, len(new_servers)):
                 aug.remove(itempath(idx))
     return servers
diff --git a/scripts/tui/src/ovirt/node/model.py b/scripts/tui/src/ovirt/node/model.py
new file mode 100644
index 0000000..68229fe
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/model.py
@@ -0,0 +1,165 @@
+#!/usr/bin/python
+#
+# model.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.
+
+"""
+oVirt Node Model functions
+"""
+
+import logging
+import glob
+
+import ovirt.node.utils
+
+LOGGER = logging.getLogger(__name__)
+
+
+def parse_defaults():
+    """Reads /etc/defaults/ovirt
+
+    Returns:
+        A dict
+    """
+    pass
+
+def configure_networking(iface, bootproto, ipaddr=None, netmask=None, gw=None,
+                         vlanid=None):
+    """Sets
+        - OVIRT_BOOTIF
+        - OVIRT_IP_ADDRESS, OVIRT_IP_NETMASK, OVIRT_IP_GATEWAY
+        - OVIRT_VLAN
+        - OVIRT_IPV6
+    """
+    if bootproto == "dhcp":
+        pass
+    elif bootproto == "static":
+        pass
+
+
+def disable_networking():
+    """Unsets
+        - OVIRT_BOOTIF
+        - OVIRT_IP_ADDRESS, OVIRT_IP_NETMASK, OVIRT_IP_GATEWAY
+        - OVIRT_VLAN
+        - OVIRT_IPV6
+    """
+    pass
+
+
+def nameservers(servers):
+    """Sets OVIRT_DNS
+
+    1. Parse nameservers from defaults
+    2. Update resolv.conf
+    3. Update ifcfg- (peerdns=no if manual resolv.conf)
+    4. Persist resolv.conf
+
+    Args:
+        servers: List of servers (str)
+    """
+    ovirt_config = parse_defaults()
+    if "OVIRT_DNS" not in ovirt_config:
+        LOGGER.debug("No DNS server entry in default config")
+        return
+
+    servers = ovirt_config["OVIRT_DNS"]
+    if servers is None or servers == "":
+        LOGGER.debug("No DNS servers configured in default config")
+
+    servers = servers.split(",")
+
+    aug = ovirt.node.utils.AugeasWrapper()
+    # Write resolv.conf any way, sometimes without servers
+    comment = ("Please make changes through the TUI. " + \
+               "Manual edits to this file will be " + \
+               "lost on reboot")
+    aug.set("/files/etc/resolv.conf/#comment[1]", comment)
+
+    # Now set the nameservers
+    ovirt.node.config.network.nameservers(servers)
+
+    # Set or remove PEERDNS for all ifcfg-*
+    for nic in glob.glob("/etc/sysconfig/network-scripts/ifcfg-*"):
+        if "ifcfg-lo" in nic:
+            continue
+        path = "/files%s/PEERDNS" % nic
+        if len(servers) > 0:
+            aug.set(path, "no")
+        else:
+            aug.remove(path)
+
+    ovirt.node.utils.fs.persist_config("/etc/resolv.conf")
+
+
+def timeservers(servers):
+    """Sets OVIRT_NTP
+
+    Args:
+        servers: List of servers (str)
+    """
+    pass
+
+
+def syslog(server, port):
+    """Sets OVIRT_SYSLOG_{SERVER,PORT}
+    """
+    pass
+
+
+def collectd(server, port):
+    """Sets OVIRT_COLLECTD_{SERVER,PORT}
+    """
+    pass
+
+
+def rhn(rhntype, url, ca_cert, username, password, profile, activationkey, org,
+        proxy, proxyuser, proxypassword):
+    """Sets ...
+    """
+    pass
+
+
+def kdump(nfs, ssh):
+    """Sets ...
+    """
+    pass
+
+
+def iscsi(name, target_name, target_host, target_port):
+    """Sets ...
+    """
+    pass
+
+
+def snmp(password):
+    """Sets ...
+    """
+    pass
+
+
+def netconsole(server, port):
+    """Sets ...
+    """
+    pass
+
+
+def cim(enabled):
+    """Sets ...
+    """
+    pass
diff --git a/scripts/tui/src/ovirt/node/plugins/network_page.py b/scripts/tui/src/ovirt/node/plugins/network_page.py
index 45c6f12..214faf7 100644
--- a/scripts/tui/src/ovirt/node/plugins/network_page.py
+++ b/scripts/tui/src/ovirt/node/plugins/network_page.py
@@ -136,22 +136,21 @@
         # Populate model with nic specific informations
         iface = self._model["nics"]
         LOGGER.debug("Getting informations for NIC details page")
-        cfg = ovirt.node.config.network.iface(iface)
         live = ovirt.node.utils.network.node_nics()[iface]
 
         self._model.update({
             "dialog.nic.iface": live["name"],
             "dialog.nic.driver": live["driver"],
-            "dialog.nic.protocol": cfg["bootproto"] or "N/A",
+            "dialog.nic.protocol": live["bootproto"] or "N/A",
             "dialog.nic.vendor": live["vendor"],
             "dialog.nic.link_status": "Connected" if live["link_detected"]
                                                   else "Disconnected",
             "dialog.nic.hwaddress": live["hwaddr"],
-            "dialog.nic.ipv4.bootproto": cfg["bootproto"],
-            "dialog.nic.ipv4.address": cfg["ipaddr"] or "",
-            "dialog.nic.ipv4.netmask": cfg["netmask"] or "",
-            "dialog.nic.ipv4.gateway": cfg["gateway"] or "",
-            "dialog.nic.vlanid": cfg["vlanid"] or "",
+            "dialog.nic.ipv4.bootproto": live["bootproto"],
+            "dialog.nic.ipv4.address": live["ipaddr"] or "",
+            "dialog.nic.ipv4.netmask": live["netmask"] or "",
+            "dialog.nic.ipv4.gateway": live["gateway"] or "",
+            "dialog.nic.vlanid": live["vlanid"] or "",
         })
 
         padd = lambda l: l.ljust(14)
diff --git a/scripts/tui/src/ovirt/node/utils/__init__.py b/scripts/tui/src/ovirt/node/utils/__init__.py
index 1586367..1f486ba 100644
--- a/scripts/tui/src/ovirt/node/utils/__init__.py
+++ b/scripts/tui/src/ovirt/node/utils/__init__.py
@@ -22,8 +22,10 @@
 Utility functions
 """
 
-import augeas as _augeas
 import logging
+import hashlib
+import re
+import augeas as _augeas
 
 LOGGER = logging.getLogger(__name__)
 
@@ -54,3 +56,35 @@
 
     def match(self, p):
         return self._aug.match(p)
+
+
+
+def checksum(filename, algo="md5"):
+    """Calculcate the checksum for a file.
+    """
+    # FIXME switch to some other later on
+    m = hashlib.md5()
+    with open(filename) as f:
+        data = f.read(4096)
+        while data:
+            m.update(data)
+            data = f.read(4096)
+        return m.hexdigest()
+
+
+
+def is_bind_mount(filename, fsprefix="ext"):
+    """Checks if a given file is bind mounted
+
+    Args:
+        filename: File to be checked
+    Returns:
+        True if the file is a bind mount target
+    """
+    bind_mount_found = False
+    with open("/proc/mounts") as mounts:
+        pattern = "%s %s" % (filename, fsprefix)
+        for mount in mounts:
+            if pattern in mount:
+                bind_mount_found = True
+    return bind_mount_found
diff --git a/scripts/tui/src/ovirt/node/utils/fs.py b/scripts/tui/src/ovirt/node/utils/fs.py
index b782559..89822e1 100644
--- a/scripts/tui/src/ovirt/node/utils/fs.py
+++ b/scripts/tui/src/ovirt/node/utils/fs.py
@@ -25,6 +25,8 @@
 import logging
 import shutil
 import os
+import ovirt.node.utils
+from ovirt.node.utils import checksum, is_bind_mount
 
 LOGGER = logging.getLogger(__name__)
 
@@ -102,3 +104,103 @@
         """Restore contens of a previously backupe file
         """
         copy_contents(self.of(fn), fn)
+
+
+def persist_config(filename):
+    LOGGER.info("Persisting: %s" % filename)
+    filenames = []
+
+#    if is_stateless():
+#        return True
+    if not os.path.ismount(persist_path()):
+        LOGGER.warning("/config is not mounted")
+        return False
+    if type(filename) in [str, unicode]:
+        filenames.append(filename)
+    elif type(filename) is list:
+        filenames = filename
+    else:
+        LOGGER.error("Unknown type: %s" % filename)
+        return False
+
+    persist_failed = False
+    for f in filenames:
+        filename = os.path.abspath(f)
+
+        if os.path.isdir(filename):
+            # ensure that, if this is a directory
+            # that it's not already persisted
+            if os.path.isdir(persist_path(filename)):
+                LOGGER.warn("Directory already persisted: %s" % filename)
+                LOGGER.warn("You need to unpersist its child directories " +
+                            "and/or files and try again.")
+                continue
+
+        elif os.path.isfile(filename):
+            # if it's a file then make sure it's not already persisted
+            persist_filename = persist_path(filename)
+            if os.path.isfile(persist_filename):
+                if checksum(filename) == checksum(persist_filename):
+                    # FIXME yes, there could be collisions ...
+                    LOGGER.info("Persisted file is equal: %s" % filename)
+                    continue
+                else:
+                    # Remove persistent copy - needs refresh
+                    if system("umount -n %s 2> /dev/null" % filename):
+                        system("rm -f %s" % persist_filename)
+
+        else:
+            # skip if file does not exist
+            logger.warn("Skipping, file '%s' does not exist" % filename)
+            continue
+
+        # At this poitn we know that we want to persist the file.
+
+        # skip if already bind-mounted
+        if is_bind_mount(filename):
+            logger.warn("%s is already persisted" % filename)
+        else:
+            dirname = os.path.dirname(filename)
+            system("mkdir -p %s" %s persist_path(dirname))
+            persist_filename = persist_path(filename)
+            if system("cp -a %s %s" % (filename, persist_filename)):
+                if not system("mount -n --bind %s %s" % (persist_filename,
+                                                         filename)):
+                    LOGGER.error("Failed to persist: " + filename)
+                    persist_failed = True
+                else:
+                    logger.info("Persisted: $s" % filename)
+
+        with open(persist_path("files"), "r") as files:
+            if filename not in files.read().split("\n"):
+                # register in /config/files used by rc.sysinit
+            system_closefds("echo "+filename+" >> /config/files")
+            logger.info("Successfully persisted (reg): %s" % filename)
+
+
+    return not persist_failed
+
+
+def persist_path(filename=""):
+    """Returns the path a file will be persisted in
+
+    Returns:
+        Path to the persisted variant of the file.
+    """
+    return os.path.join("/config", os.path.abspath(filename))
+
+
+def is_persisted(filename):
+    """Check if the file is persisted
+
+    Args:
+        filename: Filename to be checked
+    Returns:
+        True if the file exists in the /config hierarchy
+    """
+    return os.path.exists(persist_path(filename))
+
+
+def unpersist_config(filename):
+    LOGGER.info("Unpersisting: %s" % filename)
+    # FIXME
diff --git a/scripts/tui/src/ovirt/node/utils/network.py b/scripts/tui/src/ovirt/node/utils/network.py
index ce68961..b3d62fa 100644
--- a/scripts/tui/src/ovirt/node/utils/network.py
+++ b/scripts/tui/src/ovirt/node/utils/network.py
@@ -125,10 +125,11 @@
         info["type"] = "bridge"
 
     # Check vlan
-    if len(glob.glob("/proc/net/vlan/%s.*" % iface)) > 0:
+    if len(glob.glob("/proc/net/vlan/%s" % iface)) > 0:
         info["type"] = "vlan"
 
     if "type" not in info:
+        LOGGER.warning("Type of %s still unknown, using devtype" % iface)
         info["type"] = info["devtype"]
 
     if with_slow:
@@ -198,6 +199,13 @@
     """Returns Node's NIC model.
     This squashes nic, bridge and vlan informations.
 
+    All valid NICs of the system are returned, live and cfg informations merged
+    into one dict.
+    A NIC is "Configured" if itself or a vlan child is a member of a bridge.
+    If a NIC is configured, merge the info+cfg of the bridge into the slave.
+    If the slave is a vlan NIC set the vlanidof the parent device according to
+    this vlan NICs id.
+
     >>> node_nics() != None
     True
     """
@@ -217,26 +225,41 @@
     LOGGER.debug("NICs: %s" % nics)
 
     node_infos = {}
-    bridge_found = False
-    for name in nics:
-        info = all_infos[name]
-        cfg = all_cfgs[name]
-        bridge = cfg["bridge"]
-        if bridge:
-            bridge_found = True
-            bridge_cfg = all_cfgs[bridge]
-            for k in ["bootproto", "ipaddr", "netmask", "gateway"]:
-                if k in bridge_cfg:
-                    info[k] = bridge_cfg[k]
-        node_infos[name] = info
-    assert bridge_found
+    slaves = []
+    # Build dict with all NICs
+    for iface in nics:
+        LOGGER.debug("Adding physical NIC: %s" % iface)
+        info = all_infos[iface]
+        info.update(all_cfgs[iface])
+        node_infos[iface] = info
+        if info["bridge"]:
+            LOGGER.debug("Physical NIC '%s' is slave of '%s'" % (iface,
+                                                            info["bridge"]))
+            slaves.append(iface)
 
-    for name in vlans:
-        info = all_infos[name]
-        cfg = all_cfgs[name]
-        if info["vlanid"]:
-            parent = info["vlan_parent"]
-            node_infos[parent]["vlanid"] = info["vlanid"][0]
+    # Merge informations of VLANs into parent
+    for iface in vlans:
+        info = all_infos[iface]
+        info.update(all_cfgs[iface])
+        parent = info["vlan_parent"]
+        LOGGER.debug("Updating VLANID of '%s': %s" % (parent, info["vlanid"]))
+        node_infos[parent]["vlanid"] = info["vlanid"]
+        if info["bridge"]:
+            LOGGER.debug("VLAN NIC '%s' is slave of '%s'" % (iface,
+                                                            info["bridge"]))
+            slaves.append(iface)
+
+    for slave in slaves:
+        info = all_infos[slave]
+        info.update(all_cfgs[slave])
+        bridge = info["bridge"]
+        LOGGER.debug("Found slave for bridge '%s': %s" % (bridge, slave))
+        bridge_cfg = all_cfgs[bridge]
+        dst = slave
+        if info["is_vlan"]:
+            dst = info["vlan_parent"]
+        for k in ["bootproto", "ipaddr", "netmask", "gateway"]:
+            node_infos[dst][k] = bridge_cfg[k] if k in bridge_cfg else None
 
     LOGGER.debug("Node NICs: %s" % node_infos)
 
diff --git a/scripts/tui/src/ovirt/node/utils/security.py b/scripts/tui/src/ovirt/node/utils/security.py
index 6148ff7..6cd0c45 100644
--- a/scripts/tui/src/ovirt/node/utils/security.py
+++ b/scripts/tui/src/ovirt/node/utils/security.py
@@ -24,6 +24,7 @@
 
 import os.path
 import logging
+
 import ovirt.node.utils.process as process
 
 LOGGER = logging.getLogger(__name__)


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

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