Merge lp:~blake-rouse/maas/net-gateway-preseed into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 4252
Proposed branch: lp:~blake-rouse/maas/net-gateway-preseed
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~blake-rouse/maas/node-gateway-subnet
Diff against target: 351 lines (+97/-39)
4 files modified
src/maasserver/models/node.py (+6/-6)
src/maasserver/models/tests/test_node.py (+19/-18)
src/maasserver/preseed_network.py (+34/-3)
src/maasserver/tests/test_preseed_network.py (+38/-12)
To merge this branch: bzr merge lp:~blake-rouse/maas/net-gateway-preseed
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+270870@code.launchpad.net

Commit message

Set only one default gateway IP address per IP family in the node networking preseed.

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

LGTM. Just one nit below.

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Thanks for the review.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/models/node.py'
2--- src/maasserver/models/node.py 2015-09-14 00:12:14 +0000
3+++ src/maasserver/models/node.py 2015-09-14 00:12:14 +0000
4@@ -1858,9 +1858,9 @@
5 if interface.enabled:
6 interface.ensure_link_up()
7
8- def get_best_guess_for_default_gateway_ips(self):
9- """Return the best guess for the default gateway IP addresses. This is
10- either one IPv4 address, one IPv6 address, or both.
11+ def get_best_guess_for_default_gateways(self):
12+ """Return the best guess for the default gateways. This is
13+ either one IPv4 gateway, one IPv6 gateway, or both.
14
15 This is determined by looking at all interfaces on the node and
16 selecting the best possible default gateway IP. The criteria below
17@@ -1959,8 +1959,8 @@
18 return gateway
19 return None
20
21- def get_default_gateway_ips(self):
22- """Return the default gateway IP addresses.
23+ def get_default_gateways(self):
24+ """Return the default gateways.
25
26 :return: Return a tuple or tuples with IPv4 and IPv6 gateway
27 information.
28@@ -1987,7 +1987,7 @@
29 return (gateway_ipv4, gateway_ipv6)
30
31 # Get the best guesses for the missing IP families.
32- found_gateways = self.get_best_guess_for_default_gateway_ips()
33+ found_gateways = self.get_best_guess_for_default_gateways()
34 if not gateway_ipv4:
35 gateway_ipv4 = self._get_gateway_tuple_by_family(
36 found_gateways, IPADDRESS_FAMILY.IPv4)
37
38=== modified file 'src/maasserver/models/tests/test_node.py'
39--- src/maasserver/models/tests/test_node.py 2015-09-14 00:12:14 +0000
40+++ src/maasserver/models/tests/test_node.py 2015-09-14 00:12:14 +0000
41@@ -2614,7 +2614,8 @@
42 self.assertItemsEqual(enabled_interfaces, observed_interfaces)
43
44
45-class TestGetBestGuessForDefaultGatewayIPs(MAASServerTestCase):
46+class TestGetBestGuessForDefaultGateways(MAASServerTestCase):
47+ """Tests for `Node.get_best_guess_for_default_gateways`."""
48
49 def test__simple(self):
50 node = factory.make_Node_with_Interface_on_Subnet(
51@@ -2625,7 +2626,7 @@
52 gateway_ip = managed_subnet.gateway_ip
53 self.assertEquals(
54 [(boot_interface.id, managed_subnet.id, gateway_ip)],
55- node.get_best_guess_for_default_gateway_ips())
56+ node.get_best_guess_for_default_gateways())
57
58 def test__ipv4_and_ipv6(self):
59 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
60@@ -2653,7 +2654,7 @@
61 self.assertItemsEqual([
62 (interface.id, subnet_v4.id, subnet_v4.gateway_ip),
63 (interface.id, subnet_v6.id, subnet_v6.gateway_ip),
64- ], node.get_best_guess_for_default_gateway_ips())
65+ ], node.get_best_guess_for_default_gateways())
66
67 def test__only_one(self):
68 node = factory.make_Node_with_Interface_on_Subnet(
69@@ -2669,7 +2670,7 @@
70 gateway_ip = managed_subnet.gateway_ip
71 self.assertEquals(
72 [(boot_interface.id, managed_subnet.id, gateway_ip)],
73- node.get_best_guess_for_default_gateway_ips())
74+ node.get_best_guess_for_default_gateways())
75
76 def test__managed_subnet_over_unmanaged(self):
77 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
78@@ -2696,7 +2697,7 @@
79 gateway_ip = managed_subnet.gateway_ip
80 self.assertEquals(
81 [(interface.id, managed_subnet.id, gateway_ip)],
82- node.get_best_guess_for_default_gateway_ips())
83+ node.get_best_guess_for_default_gateways())
84
85 def test__bond_over_physical_interface(self):
86 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
87@@ -2727,7 +2728,7 @@
88 gateway_ip = bond_subnet.gateway_ip
89 self.assertEquals(
90 [(bond_interface.id, bond_subnet.id, gateway_ip)],
91- node.get_best_guess_for_default_gateway_ips())
92+ node.get_best_guess_for_default_gateways())
93
94 def test__physical_over_vlan_interface(self):
95 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
96@@ -2754,7 +2755,7 @@
97 gateway_ip = physical_subnet.gateway_ip
98 self.assertEquals(
99 [(physical_interface.id, physical_subnet.id, gateway_ip)],
100- node.get_best_guess_for_default_gateway_ips())
101+ node.get_best_guess_for_default_gateways())
102
103 def test__boot_interface_over_other_interfaces(self):
104 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
105@@ -2783,7 +2784,7 @@
106 gateway_ip = boot_subnet.gateway_ip
107 self.assertEquals(
108 [(boot_interface.id, boot_subnet.id, gateway_ip)],
109- node.get_best_guess_for_default_gateway_ips())
110+ node.get_best_guess_for_default_gateways())
111
112 def test__sticky_ip_over_user_reserved(self):
113 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
114@@ -2808,7 +2809,7 @@
115 gateway_ip = sticky_subnet.gateway_ip
116 self.assertEquals(
117 [(interface.id, sticky_subnet.id, gateway_ip)],
118- node.get_best_guess_for_default_gateway_ips())
119+ node.get_best_guess_for_default_gateways())
120
121 def test__user_reserved_ip_over_auto(self):
122 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
123@@ -2833,11 +2834,11 @@
124 gateway_ip = user_reserved_subnet.gateway_ip
125 self.assertEquals(
126 [(interface.id, user_reserved_subnet.id, gateway_ip)],
127- node.get_best_guess_for_default_gateway_ips())
128-
129-
130-class TestGetDefaultGatewayIP(MAASServerTestCase):
131- """Tests for `Node.get_default_gateway_ips`."""
132+ node.get_best_guess_for_default_gateways())
133+
134+
135+class TestGetDefaultGateways(MAASServerTestCase):
136+ """Tests for `Node.get_default_gateways`."""
137
138 def test__return_set_ipv4_and_ipv6(self):
139 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
140@@ -2880,7 +2881,7 @@
141 self.assertEquals((
142 (interface.id, subnet_v4_2.id, subnet_v4_2.gateway_ip),
143 (interface.id, subnet_v6_2.id, subnet_v6_2.gateway_ip),
144- ), node.get_default_gateway_ips())
145+ ), node.get_default_gateways())
146
147 def test__return_set_ipv4_and_guess_ipv6(self):
148 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
149@@ -2913,7 +2914,7 @@
150 self.assertEquals((
151 (interface.id, subnet_v4_2.id, subnet_v4_2.gateway_ip),
152 (interface.id, subnet_v6.id, subnet_v6.gateway_ip),
153- ), node.get_default_gateway_ips())
154+ ), node.get_default_gateways())
155
156 def test__return_set_ipv6_and_guess_ipv4(self):
157 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
158@@ -2946,7 +2947,7 @@
159 self.assertEquals((
160 (interface.id, subnet_v4.id, subnet_v4.gateway_ip),
161 (interface.id, subnet_v6_2.id, subnet_v6_2.gateway_ip),
162- ), node.get_default_gateway_ips())
163+ ), node.get_default_gateways())
164
165 def test__return_guess_ipv4_and_ipv6(self):
166 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ENABLED)
167@@ -2968,7 +2969,7 @@
168 self.assertEquals((
169 (interface.id, subnet_v4.id, subnet_v4.gateway_ip),
170 (interface.id, subnet_v6.id, subnet_v6.gateway_ip),
171- ), node.get_default_gateway_ips())
172+ ), node.get_default_gateways())
173
174
175 class TestDeploymentStatus(MAASServerTestCase):
176
177=== modified file 'src/maasserver/preseed_network.py'
178--- src/maasserver/preseed_network.py 2015-09-10 14:00:42 +0000
179+++ src/maasserver/preseed_network.py 2015-09-14 00:12:14 +0000
180@@ -18,6 +18,7 @@
181 from maasserver.dns.zonegenerator import get_dns_server_address
182 from maasserver.enum import (
183 INTERFACE_TYPE,
184+ IPADDRESS_FAMILY,
185 IPADDRESS_TYPE,
186 )
187 import yaml
188@@ -28,7 +29,9 @@
189
190 def __init__(self, node):
191 self.node = node
192- self.boot_interface = node.get_boot_interface()
193+ self.gateways = node.get_default_gateways()
194+ self.gateway_ipv4_set = False
195+ self.gateway_ipv6_set = False
196 self.operations = {
197 "physical": [],
198 "vlan": [],
199@@ -134,6 +137,35 @@
200 else:
201 return None
202
203+ def _get_default_gateway(self, iface, subnet):
204+ """Return True if this is the gateway that should be added to the
205+ interface configuration."""
206+ if subnet.gateway_ip:
207+ for gateway in self.gateways:
208+ if gateway is not None:
209+ iface_id, subnet_id, gateway_ip = gateway
210+ if (iface_id == iface.id and
211+ subnet_id and subnet.id and
212+ gateway_ip and subnet.gateway_ip):
213+ return subnet.gateway_ip
214+ return None
215+
216+ def _set_default_gateway(self, iface, subnet, subnet_operation):
217+ """Set the default gateway on the `subnet_operation` if it should
218+ be set."""
219+ ip_family = subnet.get_ipnetwork().version
220+ if ip_family == IPADDRESS_FAMILY.IPv4 and self.gateway_ipv4_set:
221+ return
222+ elif ip_family == IPADDRESS_FAMILY.IPv6 and self.gateway_ipv6_set:
223+ return
224+ gateway = self._get_default_gateway(iface, subnet)
225+ if gateway is not None:
226+ if ip_family == IPADDRESS_FAMILY.IPv4:
227+ self.gateway_ipv4_set = True
228+ elif ip_family == IPADDRESS_FAMILY.IPv6:
229+ self.gateway_ipv6_set = True
230+ subnet_operation["gateway"] = unicode(gateway)
231+
232 def _generate_addresses(self, iface):
233 """Generate the various addresses needed for this interface."""
234 addrs = []
235@@ -150,8 +182,7 @@
236 "type": "static",
237 "address": "%s/%s" % (unicode(address.ip), subnet_len)
238 }
239- if subnet.gateway_ip is not None:
240- subnet_operation["gateway"] = unicode(subnet.gateway_ip)
241+ self._set_default_gateway(iface, subnet, subnet_operation)
242 if subnet.dns_servers is not None:
243 subnet_operation["dns_nameservers"] = subnet.dns_servers
244 addrs.append(subnet_operation)
245
246=== modified file 'src/maasserver/tests/test_preseed_network.py'
247--- src/maasserver/tests/test_preseed_network.py 2015-09-10 14:00:42 +0000
248+++ src/maasserver/tests/test_preseed_network.py 2015-09-14 00:12:14 +0000
249@@ -19,6 +19,7 @@
250 from maasserver.dns.zonegenerator import get_dns_server_address
251 from maasserver.enum import (
252 INTERFACE_TYPE,
253+ IPADDRESS_FAMILY,
254 IPADDRESS_TYPE,
255 )
256 from maasserver.preseed_network import compose_curtin_network_config
257@@ -84,10 +85,33 @@
258 expected_equals = map(Equals, expected_network)
259 self.assertThat(output_network, MatchesListwise(expected_equals))
260
261- def collectInterfaceConfig(self, node, filter="physical"):
262+ def collect_interface_config(self, node, filter="physical"):
263 interfaces = node.interface_set.filter(enabled=True).order_by('id')
264 if filter:
265 interfaces = interfaces.filter(type=filter)
266+
267+ gateways = node.get_default_gateways()
268+ ipv4_gateway_set, ipv6_gateway_set = False, False
269+
270+ def set_gateway_ip(iface, subnet, ret, ipv4_set, ipv6_set):
271+ ip_family = subnet.get_ipnetwork().version
272+ if ip_family == IPADDRESS_FAMILY.IPv4 and ipv4_set:
273+ return (ret, ipv4_set, ipv6_set)
274+ elif ip_family == IPADDRESS_FAMILY.IPv6 and ipv6_set:
275+ return (ret, ipv4_set, ipv6_set)
276+ for gateway in gateways:
277+ if gateway is not None:
278+ iface_id, subnet_id, gateway_ip = gateway
279+ if (iface_id == iface.id and
280+ subnet_id == subnet.id and
281+ gateway_ip == subnet.gateway_ip):
282+ ret += " gateway: %s\n" % gateway_ip
283+ if ip_family == IPADDRESS_FAMILY.IPv4:
284+ ipv4_set = True
285+ elif ip_family == IPADDRESS_FAMILY.IPv6:
286+ ipv6_set = True
287+ return (ret, ipv4_set, ipv6_set)
288+
289 ret = ""
290 for iface in interfaces:
291 self.assertIn(iface.type, ["physical", "bond", "vlan"])
292@@ -120,8 +144,10 @@
293 ret += " - address: %s/%s\n" % (
294 unicode(address.ip), subnet_len)
295 ret += " type: static\n"
296- if subnet.gateway_ip is not None:
297- ret += " gateway: %s\n" % subnet.gateway_ip
298+ ret, ipv4_gateway_set, ipv6_gateway_set = (
299+ set_gateway_ip(
300+ iface, subnet, ret,
301+ ipv4_gateway_set, ipv6_gateway_set))
302 if subnet.dns_servers is not None:
303 ret += " dns_nameservers:\n"
304 for dns_server in subnet.dns_servers:
305@@ -164,7 +190,7 @@
306 sip.subnet = None
307 sip.save()
308 factory.make_Interface(node=node)
309- net_config = self.collectInterfaceConfig(node)
310+ net_config = self.collect_interface_config(node)
311 net_config += self.collectDNSConfig(node)
312 config = compose_curtin_network_config(node)
313 self.assertNetworkConfig(net_config, config)
314@@ -181,10 +207,10 @@
315 iftype=INTERFACE_TYPE.BOND, node=node, vlan=vlan,
316 parents=interfaces)
317 factory.make_StaticIPAddress(
318- interface=bond_iface,
319+ interface=bond_iface, alloc_type=IPADDRESS_TYPE.STICKY,
320 subnet=bond_iface.vlan.subnet_set.first())
321- net_config = self.collectInterfaceConfig(node, filter="physical")
322- net_config += self.collectInterfaceConfig(node, filter="bond")
323+ net_config = self.collect_interface_config(node, filter="physical")
324+ net_config += self.collect_interface_config(node, filter="bond")
325 net_config += self.collectDNSConfig(node)
326 config = compose_curtin_network_config(node)
327 self.assertNetworkConfig(net_config, config)
328@@ -200,8 +226,8 @@
329 iftype=INTERFACE_TYPE.VLAN, node=node, parents=interfaces)
330 subnet = factory.make_Subnet(vlan=vlan_iface.vlan)
331 factory.make_StaticIPAddress(interface=vlan_iface, subnet=subnet)
332- net_config = self.collectInterfaceConfig(node, filter="physical")
333- net_config += self.collectInterfaceConfig(node, filter="vlan")
334+ net_config = self.collect_interface_config(node, filter="physical")
335+ net_config += self.collect_interface_config(node, filter="vlan")
336 net_config += self.collectDNSConfig(node)
337 config = compose_curtin_network_config(node)
338 self.assertNetworkConfig(net_config, config)
339@@ -222,9 +248,9 @@
340 iftype=INTERFACE_TYPE.VLAN, node=node, parents=[bond_iface])
341 subnet = factory.make_Subnet(vlan=vlan_iface.vlan)
342 factory.make_StaticIPAddress(interface=vlan_iface, subnet=subnet)
343- net_config = self.collectInterfaceConfig(node, filter="physical")
344- net_config += self.collectInterfaceConfig(node, filter="bond")
345- net_config += self.collectInterfaceConfig(node, filter="vlan")
346+ net_config = self.collect_interface_config(node, filter="physical")
347+ net_config += self.collect_interface_config(node, filter="bond")
348+ net_config += self.collect_interface_config(node, filter="vlan")
349 net_config += self.collectDNSConfig(node)
350 config = compose_curtin_network_config(node)
351 self.assertNetworkConfig(net_config, config)