summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Moser <smoser@ubuntu.com>2016-06-01 17:14:50 -0400
committerScott Moser <smoser@ubuntu.com>2016-06-01 17:14:50 -0400
commitf67e8f104b199c9402cf047637b939516526e0ac (patch)
treeb9b9b90e3ce35940da0d643bfb86869165203c6c
parent1b8a09389654a29af7e618b803bffaed0185e9e8 (diff)
downloadvyos-cloud-init-f67e8f104b199c9402cf047637b939516526e0ac.tar.gz
vyos-cloud-init-f67e8f104b199c9402cf047637b939516526e0ac.zip
support renaming and fix logic in rename_interfaces
The one issue i'm aware of currently is that tap devices (ip tuntap add mode tap user root mytap1) do not work correctly with 'is_up' which means the check does not bring them down and the rename fails. The LOG.debug message should be cleaned up too, as it currently references the function rather function.__name__ for nicer message.
-rw-r--r--cloudinit/net/__init__.py133
1 files changed, 98 insertions, 35 deletions
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index ec1b3835..f5ae7705 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -831,19 +831,65 @@ def apply_network_config_names(netcfg, strict_present=True, strict_busy=True):
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()}
+def _get_current_rename_info(check_downable=True):
+ """Collect information necessary for rename_interfaces."""
+ names = get_devicelist()
+ bymac = {}
+ for n in names:
+ bymac[get_interface_mac(n)] = {
+ 'name': n, 'up': is_up(n), 'downable': None}
+ if check_downable:
+ nmatch = re.compile(r"[0-9]+:\s+(\w+)[@:]")
+ ipv6, _err = util.subp(['ip', '-6', 'addr', 'show', 'permanent',
+ 'scope', 'global'], capture=True)
+ ipv4, _err = util.subp(['ip', '-4', 'addr', 'show'], capture=True)
+
+ nics_with_addresses = set()
+ for bytes_out in (ipv6, ipv4):
+ nics_with_addresses.update(nmatch.findall(bytes_out))
+
+ for d in bymac.values():
+ d['downable'] = (d['up'] is False or
+ d['name'] not in nics_with_addresses)
+
+ return bymac
+
+
+def rename_interfaces(renames, strict_present=True, strict_busy=True,
+ current_info=None):
+ if current_info is None:
+ current_info = _get_current_rename_info()
+
+ cur_bymac = {}
+ for mac, data in current_info.items():
+ cur = data.copy()
+ cur['mac'] = mac
+ cur_bymac[mac] = cur
+
+ def update_byname(bymac):
+ return {data['name']: data for data in bymac.values()}
+
+ def rename(cur, new):
+ util.subp(["ip", "link", "set", cur, "name", new], capture=True)
+
+ def down(name):
+ util.subp(["ip", "link", "set", name, "down"], capture=True)
+
+ def up(name):
+ util.subp(["ip", "link", "set", name, "up"], capture=True)
+
+ ops = []
+ errors = []
+ ups = []
+ cur_byname = update_byname(cur_bymac)
tmpname_fmt = "cirename%d"
tmpi = -1
- moves = []
- changes = []
- errors = []
- for mac, new_name in expected.items():
- cur_name = cur_bymac.get(mac)
+ for mac, new_name in renames:
+ cur = cur_bymac.get(mac, {})
+ cur_name = cur.get('name')
+ cur_ops = []
if cur_name == new_name:
# nothing to do
continue
@@ -853,37 +899,54 @@ def rename_interfaces(renames, strict_present=True, strict_busy=True):
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):
+ continue
+
+ if cur['up']:
+ msg = "[busy] Error renaming mac=%s from %s to %s"
+ if not cur['downable']:
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))
+ errors.append(msg % (mac, cur_name, new_name))
+ continue
+ cur['up'] = False
+ cur_ops.append((down, mac, new_name, (cur_name,)))
+ ups.append((up, mac, new_name, (new_name,)))
+
+ if new_name in cur_byname:
+ target = cur_byname[new_name]
+ if target['up']:
+ msg = "[busy-target] Error renaming mac=%s from %s to %s."
+ if not target['downable']:
+ if strict_busy:
+ errors.append(msg % (mac, cur_name, new_name))
+ continue
+ else:
+ cur_ops.append((down, mac, new_name, (new_name,)))
+
+ tmp_name = None
+ while tmp_name is None or tmp_name in cur_byname:
+ tmpi += 1
+ tmp_name = tmpname_fmt % tmpi
+
+ cur_ops.append((rename, mac, new_name, (new_name, tmp_name)))
+ target['name'] = tmp_name
+ cur_byname = update_byname(cur_bymac)
+ if target['up']:
+ ups.append((up, mac, new_name, (tmp_name,)))
+
+ cur_ops.append((rename, mac, new_name, (cur['name'], new_name)))
+ cur['name'] = new_name
+ cur_byname = update_byname(cur_bymac)
+ ops += cur_ops
- def rename_dev(cur, new):
- cmd = ["ip", "link", "set", cur, "name", new]
- util.subp(cmd)
+ LOG.debug("achieving renaming of %s with ops %s", renames, ops + ups)
- for mac, cur, new in moves + changes:
+ for op, mac, new_name, params in ops + ups:
try:
- rename_dev(cur, new)
- except util.ProcessExecutionError as e:
+ op(*params)
+ except Exception as e:
errors.append(
- "[unknown] Error renaming mac=%s from %s to %s. (%s)" %
- (mac, cur, new, e))
+ "[unknown] Error performing %s%s for %s, %s: %s" %
+ (op.__name__, params, mac, new_name, e))
if len(errors):
raise Exception('\n'.join(errors))