summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Moser <smoser@ubuntu.com>2016-05-31 17:17:39 -0400
committerScott Moser <smoser@ubuntu.com>2016-05-31 17:17:39 -0400
commit1b8a09389654a29af7e618b803bffaed0185e9e8 (patch)
treed1cbd33fd5bfbbe7658957f8f9bcfe1545dd530f
parentb16533714e02fc71d463ca73abee5c9f6237f115 (diff)
downloadvyos-cloud-init-1b8a09389654a29af7e618b803bffaed0185e9e8.tar.gz
vyos-cloud-init-1b8a09389654a29af7e618b803bffaed0185e9e8.zip
add renaming code for renaming interfaces
currently does not work in lxc https://github.com/lxc/lxd/issues/2063
-rwxr-xr-xbin/cloud-init6
-rw-r--r--cloudinit/distros/__init__.py4
-rw-r--r--cloudinit/net/__init__.py86
-rw-r--r--cloudinit/stages.py10
4 files changed, 101 insertions, 5 deletions
diff --git a/bin/cloud-init b/bin/cloud-init
index 29e9b521..21c3a684 100755
--- a/bin/cloud-init
+++ b/bin/cloud-init
@@ -280,11 +280,7 @@ def main_init(name, args):
LOG.debug("[%s] %s will now be targeting instance id: %s. new=%s",
mode, name, iid, init.is_new_instance())
- if init.is_new_instance():
- # on new instance, apply network config.
- # in network mode 'bring_up' must be passed in as the OS
- # has already brought up networking.
- init.apply_network_config(bring_up=bool(mode != sources.DSMODE_LOCAL))
+ init.apply_network_config(bring_up=bool(mode != sources.DSMODE_LOCAL))
if mode == sources.DSMODE_LOCAL:
if init.datasource.dsmode != mode:
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 3bfbc484..5c29c804 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -31,6 +31,7 @@ import stat
from cloudinit import importer
from cloudinit import log as logging
+from cloudinit import net
from cloudinit import ssh_util
from cloudinit import type_utils
from cloudinit import util
@@ -145,6 +146,9 @@ class Distro(object):
return self._bring_up_interfaces(dev_names)
return False
+ def apply_network_config_names(self, netconfig):
+ net.apply_network_config_names(netconfig)
+
@abc.abstractmethod
def apply_locale(self, locale, out_fn=None):
raise NotImplementedError()
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index 40d330b5..ec1b3835 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -813,4 +813,90 @@ def _ifaces_to_net_config_data(ifaces):
'config': [devs[d] for d in sorted(devs)]}
+def apply_network_config_names(netcfg, strict_present=True, strict_busy=True):
+ """read the network config and rename devices accordingly.
+ if strict_present is false, then do not raise exception if no devices
+ match. if strict_busy is false, then do not raise exception if the
+ device cannot be renamed because it is currently configured."""
+ renames = []
+ for ent in netcfg.get('config', {}):
+ if ent.get('type') != 'physical':
+ continue
+ mac = ent.get('mac_address')
+ name = ent.get('name')
+ if not mac:
+ continue
+ renames.append([mac, name])
+
+ return rename_interfaces(renames)
+
+
+def rename_interfaces(renames, strict_present=True, strict_busy=True):
+ cur_bymac = {get_interface_mac(n): n for n in get_devicelist()}
+ expected = {mac: name for mac, name in renames}
+ cur_byname = {v: k for k, v in cur_bymac.items()}
+
+ tmpname_fmt = "cirename%d"
+ tmpi = -1
+
+ moves = []
+ changes = []
+ errors = []
+ for mac, new_name in expected.items():
+ cur_name = cur_bymac.get(mac)
+ if cur_name == new_name:
+ # nothing to do
+ continue
+
+ if not cur_name:
+ if strict_present:
+ errors.append(
+ "[nic not present] Cannot rename mac=%s to %s"
+ ", not available." % (mac, new_name))
+ elif is_up(cur_name):
+ if strict_busy:
+ errors.append("[busy] Error renaming mac=%s from %s to %s." %
+ (mac, cur_name, new_name))
+ elif new_name in cur_byname:
+ if is_up(new_name):
+ if strict_busy:
+ errors.append(
+ "[busy-target] Error renaming mac=%s from %s to %s." %
+ (mac, cur_name, new_name))
+ else:
+ tmp_name = None
+ while tmp_name is None or tmp_name in cur_byname:
+ tmpi += 1
+ tmp_name = tmpname_fmt % tmpi
+ moves.append((mac, cur_name, tmp_name))
+ changes.append((mac, tmp_name, new_name))
+ else:
+ changes.append((mac, cur_name, new_name))
+
+ def rename_dev(cur, new):
+ cmd = ["ip", "link", "set", cur, "name", new]
+ util.subp(cmd)
+
+ for mac, cur, new in moves + changes:
+ try:
+ rename_dev(cur, new)
+ except util.ProcessExecutionError as e:
+ errors.append(
+ "[unknown] Error renaming mac=%s from %s to %s. (%s)" %
+ (mac, cur, new, e))
+
+ if len(errors):
+ raise Exception('\n'.join(errors))
+
+
+def get_interface_mac(ifname):
+ """Returns the string value of an interface's MAC Address"""
+ return read_sys_net(ifname, "address", enoent=False)
+
+
+def get_ifname_mac_pairs():
+ """Build a list of tuples (ifname, mac)"""
+ return [(ifname, get_interface_mac(ifname)) for ifname in get_devicelist()]
+
+
# vi: ts=4 expandtab syntax=python
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index f164d6f6..211d2286 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -632,6 +632,16 @@ class Init(object):
LOG.info("network config is disabled by %s", src)
return
+ try:
+ LOG.debug("applying net config names for %s" % netcfg)
+ self.distro.apply_network_config_names(netcfg)
+ except Exception as e:
+ LOG.warn("Failed to rename devices: %s", e)
+
+ if not self.is_new_instance():
+ LOG.debug("not a new instance. network config is not applied.")
+ return
+
LOG.info("Applying network configuration from %s bringup=%s: %s",
src, bring_up, netcfg)
try: