Merge lp:~blake-rouse/maas/net-gateway-preseed into lp:~maas-committers/maas/trunk
- net-gateway-preseed
- Merge into 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 |
Related bugs: |
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.
Description of the change
To post a comment you must log in.
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) |
LGTM. Just one nit below.