[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