Merge ~raharper/cloud-init:net-dont-use-alias into cloud-init:master

Proposed by Ryan Harper
Status: Merged
Merged at revision: 2de1c247e285cce0b25ab70abdc56ccd41019c27
Proposed branch: ~raharper/cloud-init:net-dont-use-alias
Merge into: cloud-init:master
Diff against target: 161 lines (+53/-26)
2 files modified
cloudinit/net/eni.py (+19/-14)
tests/unittests/test_net.py (+34/-12)
Reviewer Review Type Date Requested Status
cloud-init Commiters Pending
Review via email: mp+315633@code.launchpad.net

Commit message

Fix eni rendering of multiple IPs per interface

The iface:alias syntax for eni rendering is brittle with ipv6.
Replace it with using multiple iface stanzas with the same iface
name which is supported. Side-effect is that one can no longer
do 'ifup $iface:$alias' but requires instead use of ip address
{add|delete} instead.

LP: #1657940

Description of the change

Fix eni rendering of multiple IPs per interface

The iface:alias syntax for eni rendering is brittle with ipv6.
Replace it with using multiple iface stanzas with the same iface
name which is supported. Side-effect is that one can no longer
do 'ifup $iface:$alias' but requires instead use of ip address
{add|delete} instead.

LP: #1657940

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py
2index b06ffac..5b249f1 100644
3--- a/cloudinit/net/eni.py
4+++ b/cloudinit/net/eni.py
5@@ -90,8 +90,6 @@ def _iface_add_attrs(iface, index):
6
7 def _iface_start_entry(iface, index, render_hwaddress=False):
8 fullname = iface['name']
9- if index != 0:
10- fullname += ":%s" % index
11
12 control = iface['control']
13 if control == "auto":
14@@ -113,6 +111,16 @@ def _iface_start_entry(iface, index, render_hwaddress=False):
15 return lines
16
17
18+def _subnet_is_ipv6(subnet):
19+ # 'static6' or 'dhcp6'
20+ if subnet['type'].endswith('6'):
21+ # This is a request for DHCPv6.
22+ return True
23+ elif subnet['type'] == 'static' and ":" in subnet['address']:
24+ return True
25+ return False
26+
27+
28 def _parse_deb_config_data(ifaces, contents, src_dir, src_path):
29 """Parses the file contents, placing result into ifaces.
30
31@@ -354,21 +362,23 @@ class Renderer(renderer.Renderer):
32 sections = []
33 subnets = iface.get('subnets', {})
34 if subnets:
35- for index, subnet in zip(range(0, len(subnets)), subnets):
36+ for index, subnet in enumerate(subnets):
37 iface['index'] = index
38 iface['mode'] = subnet['type']
39 iface['control'] = subnet.get('control', 'auto')
40 subnet_inet = 'inet'
41- if iface['mode'].endswith('6'):
42- # This is a request for DHCPv6.
43- subnet_inet += '6'
44- elif iface['mode'] == 'static' and ":" in subnet['address']:
45- # This is a static IPv6 address.
46+ if _subnet_is_ipv6(subnet):
47 subnet_inet += '6'
48 iface['inet'] = subnet_inet
49- if iface['mode'].startswith('dhcp'):
50+ if subnet['type'].startswith('dhcp'):
51 iface['mode'] = 'dhcp'
52
53+ # do not emit multiple 'auto $IFACE' lines as older (precise)
54+ # ifupdown complains
55+ if True in ["auto %s" % (iface['name']) in line
56+ for line in sections]:
57+ iface['control'] = 'alias'
58+
59 lines = list(
60 _iface_start_entry(
61 iface, index, render_hwaddress=render_hwaddress) +
62@@ -378,11 +388,6 @@ class Renderer(renderer.Renderer):
63 for route in subnet.get('routes', []):
64 lines.extend(self._render_route(route, indent=" "))
65
66- if len(subnets) > 1 and index == 0:
67- tmpl = " post-up ifup %s:%s\n"
68- for i in range(1, len(subnets)):
69- lines.append(tmpl % (iface['name'], i))
70-
71 sections.append(lines)
72 else:
73 # ifenslave docs say to auto the slave devices
74diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
75index 2c2bde9..b77d277 100644
76--- a/tests/unittests/test_net.py
77+++ b/tests/unittests/test_net.py
78@@ -219,11 +219,9 @@ NETWORK_CONFIGS = {
79
80 auto eth99
81 iface eth99 inet dhcp
82- post-up ifup eth99:1
83
84-
85- auto eth99:1
86- iface eth99:1 inet static
87+ # control-alias eth99
88+ iface eth99 inet static
89 address 192.168.21.3/24
90 dns-nameservers 8.8.8.8 8.8.4.4
91 dns-search barley.maas sach.maas
92@@ -261,6 +259,27 @@ NETWORK_CONFIGS = {
93 - wark.maas
94 """),
95 },
96+ 'v4_and_v6': {
97+ 'expected_eni': textwrap.dedent("""\
98+ auto lo
99+ iface lo inet loopback
100+
101+ auto iface0
102+ iface iface0 inet dhcp
103+
104+ # control-alias iface0
105+ iface iface0 inet6 dhcp
106+ """).rstrip(' '),
107+ 'yaml': textwrap.dedent("""\
108+ version: 1
109+ config:
110+ - type: 'physical'
111+ name: 'iface0'
112+ subnets:
113+ - {'type': 'dhcp4'}
114+ - {'type': 'dhcp6'}
115+ """).rstrip(' '),
116+ },
117 'all': {
118 'expected_eni': ("""\
119 auto lo
120@@ -298,11 +317,9 @@ iface br0 inet static
121 address 192.168.14.2/24
122 bridge_ports eth3 eth4
123 bridge_stp off
124- post-up ifup br0:1
125-
126
127-auto br0:1
128-iface br0:1 inet6 static
129+# control-alias br0
130+iface br0 inet6 static
131 address 2001:1::1/64
132
133 auto bond0.200
134@@ -319,11 +336,9 @@ iface eth0.101 inet static
135 mtu 1500
136 vlan-raw-device eth0
137 vlan_id 101
138- post-up ifup eth0.101:1
139-
140
141-auto eth0.101:1
142-iface eth0.101:1 inet static
143+# control-alias eth0.101
144+iface eth0.101 inet static
145 address 192.168.2.10/24
146
147 post-up route add -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true
148@@ -758,6 +773,13 @@ class TestEniRoundTrip(CiTestCase):
149 entry['expected_eni'].splitlines(),
150 files['/etc/network/interfaces'].splitlines())
151
152+ def testsimple_render_v4_and_v6(self):
153+ entry = NETWORK_CONFIGS['v4_and_v6']
154+ files = self._render_and_read(network_config=yaml.load(entry['yaml']))
155+ self.assertEqual(
156+ entry['expected_eni'].splitlines(),
157+ files['/etc/network/interfaces'].splitlines())
158+
159 def test_routes_rendered(self):
160 # as reported in bug 1649652
161 conf = [

Subscribers

People subscribed via source and target branches