|
|
1064ba |
From 335d2b7270c151fd981d9e500f239ab75a59a4b3 Mon Sep 17 00:00:00 2001
|
|
|
1064ba |
From: Ryan Harper <ryan.harper@canonical.com>
|
|
|
1064ba |
Date: Wed, 25 Jan 2017 15:45:40 -0600
|
|
|
1064ba |
Subject: [PATCH] Fix eni rendering of multiple IPs per interface
|
|
|
1064ba |
|
|
|
1064ba |
The iface:alias syntax for eni rendering is brittle with ipv6.
|
|
|
1064ba |
Replace it with using multiple iface stanzas with the same iface
|
|
|
1064ba |
name which is supported. Side-effect is that one can no longer
|
|
|
1064ba |
do 'ifup $iface:$alias' but requires instead use of ip address
|
|
|
1064ba |
{add|delete} instead.
|
|
|
1064ba |
|
|
|
1064ba |
LP: #1657940
|
|
|
1064ba |
(cherry picked from commit 2de1c247e285cce0b25ab70abdc56ccd41019c27)
|
|
|
1064ba |
|
|
|
1064ba |
Signed-off-by: Ryan McCabe <rmccabe@redhat.com>
|
|
|
1064ba |
Resolves: rhbz#bz1497954
|
|
|
1064ba |
---
|
|
|
1064ba |
cloudinit/net/eni.py | 33 ++++++++++++++++++--------------
|
|
|
1064ba |
tests/unittests/test_net.py | 46 +++++++++++++++++++++++++++++++++------------
|
|
|
1064ba |
2 files changed, 53 insertions(+), 26 deletions(-)
|
|
|
1064ba |
|
|
|
1064ba |
diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py
|
|
|
1064ba |
index b06ffac9..5b249f1f 100644
|
|
|
1064ba |
--- a/cloudinit/net/eni.py
|
|
|
1064ba |
+++ b/cloudinit/net/eni.py
|
|
|
1064ba |
@@ -90,8 +90,6 @@ def _iface_add_attrs(iface, index):
|
|
|
1064ba |
|
|
|
1064ba |
def _iface_start_entry(iface, index, render_hwaddress=False):
|
|
|
1064ba |
fullname = iface['name']
|
|
|
1064ba |
- if index != 0:
|
|
|
1064ba |
- fullname += ":%s" % index
|
|
|
1064ba |
|
|
|
1064ba |
control = iface['control']
|
|
|
1064ba |
if control == "auto":
|
|
|
1064ba |
@@ -113,6 +111,16 @@ def _iface_start_entry(iface, index, render_hwaddress=False):
|
|
|
1064ba |
return lines
|
|
|
1064ba |
|
|
|
1064ba |
|
|
|
1064ba |
+def _subnet_is_ipv6(subnet):
|
|
|
1064ba |
+ # 'static6' or 'dhcp6'
|
|
|
1064ba |
+ if subnet['type'].endswith('6'):
|
|
|
1064ba |
+ # This is a request for DHCPv6.
|
|
|
1064ba |
+ return True
|
|
|
1064ba |
+ elif subnet['type'] == 'static' and ":" in subnet['address']:
|
|
|
1064ba |
+ return True
|
|
|
1064ba |
+ return False
|
|
|
1064ba |
+
|
|
|
1064ba |
+
|
|
|
1064ba |
def _parse_deb_config_data(ifaces, contents, src_dir, src_path):
|
|
|
1064ba |
"""Parses the file contents, placing result into ifaces.
|
|
|
1064ba |
|
|
|
1064ba |
@@ -354,21 +362,23 @@ class Renderer(renderer.Renderer):
|
|
|
1064ba |
sections = []
|
|
|
1064ba |
subnets = iface.get('subnets', {})
|
|
|
1064ba |
if subnets:
|
|
|
1064ba |
- for index, subnet in zip(range(0, len(subnets)), subnets):
|
|
|
1064ba |
+ for index, subnet in enumerate(subnets):
|
|
|
1064ba |
iface['index'] = index
|
|
|
1064ba |
iface['mode'] = subnet['type']
|
|
|
1064ba |
iface['control'] = subnet.get('control', 'auto')
|
|
|
1064ba |
subnet_inet = 'inet'
|
|
|
1064ba |
- if iface['mode'].endswith('6'):
|
|
|
1064ba |
- # This is a request for DHCPv6.
|
|
|
1064ba |
- subnet_inet += '6'
|
|
|
1064ba |
- elif iface['mode'] == 'static' and ":" in subnet['address']:
|
|
|
1064ba |
- # This is a static IPv6 address.
|
|
|
1064ba |
+ if _subnet_is_ipv6(subnet):
|
|
|
1064ba |
subnet_inet += '6'
|
|
|
1064ba |
iface['inet'] = subnet_inet
|
|
|
1064ba |
- if iface['mode'].startswith('dhcp'):
|
|
|
1064ba |
+ if subnet['type'].startswith('dhcp'):
|
|
|
1064ba |
iface['mode'] = 'dhcp'
|
|
|
1064ba |
|
|
|
1064ba |
+ # do not emit multiple 'auto $IFACE' lines as older (precise)
|
|
|
1064ba |
+ # ifupdown complains
|
|
|
1064ba |
+ if True in ["auto %s" % (iface['name']) in line
|
|
|
1064ba |
+ for line in sections]:
|
|
|
1064ba |
+ iface['control'] = 'alias'
|
|
|
1064ba |
+
|
|
|
1064ba |
lines = list(
|
|
|
1064ba |
_iface_start_entry(
|
|
|
1064ba |
iface, index, render_hwaddress=render_hwaddress) +
|
|
|
1064ba |
@@ -378,11 +388,6 @@ class Renderer(renderer.Renderer):
|
|
|
1064ba |
for route in subnet.get('routes', []):
|
|
|
1064ba |
lines.extend(self._render_route(route, indent=" "))
|
|
|
1064ba |
|
|
|
1064ba |
- if len(subnets) > 1 and index == 0:
|
|
|
1064ba |
- tmpl = " post-up ifup %s:%s\n"
|
|
|
1064ba |
- for i in range(1, len(subnets)):
|
|
|
1064ba |
- lines.append(tmpl % (iface['name'], i))
|
|
|
1064ba |
-
|
|
|
1064ba |
sections.append(lines)
|
|
|
1064ba |
else:
|
|
|
1064ba |
# ifenslave docs say to auto the slave devices
|
|
|
1064ba |
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
|
|
|
1064ba |
index ffa911cc..4c0e3ad3 100644
|
|
|
1064ba |
--- a/tests/unittests/test_net.py
|
|
|
1064ba |
+++ b/tests/unittests/test_net.py
|
|
|
1064ba |
@@ -376,11 +376,9 @@ NETWORK_CONFIGS = {
|
|
|
1064ba |
|
|
|
1064ba |
auto eth99
|
|
|
1064ba |
iface eth99 inet dhcp
|
|
|
1064ba |
- post-up ifup eth99:1
|
|
|
1064ba |
|
|
|
1064ba |
-
|
|
|
1064ba |
- auto eth99:1
|
|
|
1064ba |
- iface eth99:1 inet static
|
|
|
1064ba |
+ # control-alias eth99
|
|
|
1064ba |
+ iface eth99 inet static
|
|
|
1064ba |
address 192.168.21.3/24
|
|
|
1064ba |
dns-nameservers 8.8.8.8 8.8.4.4
|
|
|
1064ba |
dns-search barley.maas sach.maas
|
|
|
1064ba |
@@ -418,6 +416,27 @@ NETWORK_CONFIGS = {
|
|
|
1064ba |
- wark.maas
|
|
|
1064ba |
"""),
|
|
|
1064ba |
},
|
|
|
1064ba |
+ 'v4_and_v6': {
|
|
|
1064ba |
+ 'expected_eni': textwrap.dedent("""\
|
|
|
1064ba |
+ auto lo
|
|
|
1064ba |
+ iface lo inet loopback
|
|
|
1064ba |
+
|
|
|
1064ba |
+ auto iface0
|
|
|
1064ba |
+ iface iface0 inet dhcp
|
|
|
1064ba |
+
|
|
|
1064ba |
+ # control-alias iface0
|
|
|
1064ba |
+ iface iface0 inet6 dhcp
|
|
|
1064ba |
+ """).rstrip(' '),
|
|
|
1064ba |
+ 'yaml': textwrap.dedent("""\
|
|
|
1064ba |
+ version: 1
|
|
|
1064ba |
+ config:
|
|
|
1064ba |
+ - type: 'physical'
|
|
|
1064ba |
+ name: 'iface0'
|
|
|
1064ba |
+ subnets:
|
|
|
1064ba |
+ - {'type': 'dhcp4'}
|
|
|
1064ba |
+ - {'type': 'dhcp6'}
|
|
|
1064ba |
+ """).rstrip(' '),
|
|
|
1064ba |
+ },
|
|
|
1064ba |
'all': {
|
|
|
1064ba |
'expected_eni': ("""\
|
|
|
1064ba |
auto lo
|
|
|
1064ba |
@@ -455,11 +474,9 @@ iface br0 inet static
|
|
|
1064ba |
address 192.168.14.2/24
|
|
|
1064ba |
bridge_ports eth3 eth4
|
|
|
1064ba |
bridge_stp off
|
|
|
1064ba |
- post-up ifup br0:1
|
|
|
1064ba |
-
|
|
|
1064ba |
|
|
|
1064ba |
-auto br0:1
|
|
|
1064ba |
-iface br0:1 inet6 static
|
|
|
1064ba |
+# control-alias br0
|
|
|
1064ba |
+iface br0 inet6 static
|
|
|
1064ba |
address 2001:1::1/64
|
|
|
1064ba |
|
|
|
1064ba |
auto bond0.200
|
|
|
1064ba |
@@ -476,11 +493,9 @@ iface eth0.101 inet static
|
|
|
1064ba |
mtu 1500
|
|
|
1064ba |
vlan-raw-device eth0
|
|
|
1064ba |
vlan_id 101
|
|
|
1064ba |
- post-up ifup eth0.101:1
|
|
|
1064ba |
-
|
|
|
1064ba |
|
|
|
1064ba |
-auto eth0.101:1
|
|
|
1064ba |
-iface eth0.101:1 inet static
|
|
|
1064ba |
+# control-alias eth0.101
|
|
|
1064ba |
+iface eth0.101 inet static
|
|
|
1064ba |
address 192.168.2.10/24
|
|
|
1064ba |
|
|
|
1064ba |
post-up route add -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true
|
|
|
1064ba |
@@ -1007,6 +1022,13 @@ class TestEniRoundTrip(TestCase):
|
|
|
1064ba |
entry['expected_eni'].splitlines(),
|
|
|
1064ba |
files['/etc/network/interfaces'].splitlines())
|
|
|
1064ba |
|
|
|
1064ba |
+ def testsimple_render_v4_and_v6(self):
|
|
|
1064ba |
+ entry = NETWORK_CONFIGS['v4_and_v6']
|
|
|
1064ba |
+ files = self._render_and_read(network_config=yaml.load(entry['yaml']))
|
|
|
1064ba |
+ self.assertEqual(
|
|
|
1064ba |
+ entry['expected_eni'].splitlines(),
|
|
|
1064ba |
+ files['/etc/network/interfaces'].splitlines())
|
|
|
1064ba |
+
|
|
|
1064ba |
def test_routes_rendered(self):
|
|
|
1064ba |
# as reported in bug 1649652
|
|
|
1064ba |
conf = [
|
|
|
1064ba |
--
|
|
|
1064ba |
2.13.6
|
|
|
1064ba |
|