Merge lp:~jtv/maas/bug-1379641-obtain-netmasks into lp:~maas-committers/maas/trunk

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 3236
Proposed branch: lp:~jtv/maas/bug-1379641-obtain-netmasks
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~jtv/maas/bug-1379641-pass-netmasks
Diff against target: 151 lines (+71/-6)
3 files modified
src/maasserver/models/macaddress.py (+1/-0)
src/maasserver/networking_preseed.py (+22/-3)
src/maasserver/tests/test_networking_preseed.py (+48/-3)
To merge this branch: bzr merge lp:~jtv/maas/bug-1379641-obtain-netmasks
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Gavin Panella (community) Approve
Review via email: mp+237927@code.launchpad.net

Commit message

Pass netmasks along with the parameters for generating /etc/network/interfaces.

This is one of a group of 4 branches that together implement support for arbitrary netmasks in IPv6. But the netmasks would also be useful in configuring static IPv4 addresses later.

Description of the change

I hope the main implementing function is clear enough. It's tempting to query for a StaticIPAddress—MACAddress—NodeGroupInterface relationship through the ORM, but that won't work: when a MAC address is connected to both IPv4 and IPv6 network interfaces, one connection will be direct through a foreign key; the other will be derived from the cluster and the network interface name.

Eventually we do want that connection to go into the schema as an m:n relationship.

Jeroen

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) :
review: Approve
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Thanks!

Revision history for this message
Raphaël Badin (rvb) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/models/macaddress.py'
2--- src/maasserver/models/macaddress.py 2014-09-24 14:20:51 +0000
3+++ src/maasserver/models/macaddress.py 2014-10-10 11:59:22 +0000
4@@ -13,6 +13,7 @@
5
6 __metaclass__ = type
7 __all__ = [
8+ 'find_cluster_interface_responsible_for_ip',
9 'MACAddress',
10 ]
11
12
13=== modified file 'src/maasserver/networking_preseed.py'
14--- src/maasserver/networking_preseed.py 2014-10-10 11:59:22 +0000
15+++ src/maasserver/networking_preseed.py 2014-10-10 11:59:22 +0000
16@@ -35,6 +35,9 @@
17 from maasserver.clusterrpc.osystems import compose_curtin_network_preseed
18 from maasserver.dns.zonegenerator import get_dns_server_address
19 from maasserver.exceptions import UnresolvableHost
20+from maasserver.models.macaddress import (
21+ find_cluster_interface_responsible_for_ip,
22+ )
23 from maasserver.models.nodeprobeddetails import get_probed_details
24 from maasserver.models.staticipaddress import StaticIPAddress
25 from netaddr import (
26@@ -279,7 +282,7 @@
27
28
29 def map_static_ips(node):
30- """Return a `defaultdict` mapping node's MAC addresses to their static IPs.
31+ """Return a dict mapping node's MAC addresses to their static IPs.
32
33 :param node: A `Node`.
34 :return: A dict mapping normalised MAC address strings to sets of
35@@ -320,6 +323,23 @@
36 return normalise_mac(unicode(pxe_mac.mac_address))
37
38
39+def map_netmasks(node):
40+ """Return respective netmasks for node's configured IP addresses."""
41+ mapping = {}
42+ for mac in node.macaddress_set.filter(cluster_interface__isnull=False):
43+ interfaces = mac.get_cluster_interfaces()
44+ for sip in StaticIPAddress.objects.filter(macaddress=mac):
45+ interface = find_cluster_interface_responsible_for_ip(
46+ interfaces, IPAddress(sip.ip))
47+ if interface is not None:
48+ if valid_ipv4(sip.ip):
49+ netmask = interface.subnet_mask
50+ else:
51+ netmask = '%d' % interface.network.prefixlen
52+ mapping[normalise_ip(sip.ip)] = netmask
53+ return mapping
54+
55+
56 def compose_curtin_network_preseed_for(node):
57 """Compose OS-dependent preseed for configuring networking on `node`.
58
59@@ -332,8 +352,7 @@
60 'ips_mapping': map_static_ips(node),
61 'gateways_mapping': map_gateways(node),
62 'nameservers': list_dns_servers(node),
63- # XXX jtv 2014-10-10, bug=1379641: Pass netmasks.
64- 'netmasks': {}
65+ 'netmasks': map_netmasks(node),
66 }
67 preseed = compose_curtin_network_preseed(node, config)
68 return [json.dumps(item) for item in preseed]
69
70=== modified file 'src/maasserver/tests/test_networking_preseed.py'
71--- src/maasserver/tests/test_networking_preseed.py 2014-10-10 11:59:22 +0000
72+++ src/maasserver/tests/test_networking_preseed.py 2014-10-10 11:59:22 +0000
73@@ -38,6 +38,7 @@
74 get_mac_for_automatic_interfaces,
75 list_dns_servers,
76 map_gateways,
77+ map_netmasks,
78 map_static_ips,
79 normalise_ip,
80 normalise_mac,
81@@ -45,7 +46,10 @@
82 from maasserver.testing.factory import factory
83 from maasserver.testing.testcase import MAASServerTestCase
84 from maastesting.matchers import MockCalledOnceWith
85-from netaddr import IPAddress
86+from netaddr import (
87+ IPAddress,
88+ IPNetwork,
89+ )
90 from testtools.matchers import HasLength
91
92
93@@ -748,6 +752,49 @@
94 self.assertEqual(result, extract_mac_string(mac))
95
96
97+class TestMapNetmasks(MAASServerTestCase):
98+
99+ def test__maps_ipv4_netmask(self):
100+ network = factory.make_ipv4_network()
101+ netmask = unicode(IPNetwork(network).netmask)
102+ node = factory.make_node_with_mac_attached_to_nodegroupinterface(
103+ network=network)
104+ mac = node.get_primary_mac()
105+ ip = factory.pick_ip_in_network(network)
106+ factory.make_StaticIPAddress(mac=mac, ip=ip)
107+ self.assertEqual({normalise_ip(ip): netmask}, map_netmasks(node))
108+
109+ def test__maps_ipv6_netmask_as_prefix_bits(self):
110+ network = factory.make_ipv6_network(slash=randint(16, 127))
111+ netmask = '%d' % IPNetwork(network).prefixlen
112+ node = factory.make_node_with_mac_attached_to_nodegroupinterface()
113+ [ipv4_interface] = node.nodegroup.nodegroupinterface_set.all()
114+ factory.make_NodeGroupInterface(
115+ node.nodegroup, network=network,
116+ interface=ipv4_interface.interface)
117+ mac = node.get_primary_mac()
118+ ip = factory.pick_ip_in_network(network)
119+ factory.make_StaticIPAddress(mac=mac, ip=ip)
120+ self.assertEqual({normalise_ip(ip): netmask}, map_netmasks(node))
121+
122+ def test__ignores_network_interface_without_cluster_interface(self):
123+ network = factory.make_ipv4_network()
124+ node = factory.make_node_with_mac_attached_to_nodegroupinterface(
125+ network=network)
126+ mac = node.get_primary_mac()
127+ mac.cluster_interface = None
128+ mac.save()
129+ ip = factory.pick_ip_in_network(network)
130+ factory.make_StaticIPAddress(mac=mac, ip=ip)
131+ self.assertEqual({}, map_netmasks(node))
132+
133+ def test__ignores_network_interface_without_static_IP(self):
134+ network = factory.make_ipv4_network()
135+ node = factory.make_node_with_mac_attached_to_nodegroupinterface(
136+ network=network)
137+ self.assertEqual({}, map_netmasks(node))
138+
139+
140 class TestComposeCurtinNetworkPreseedFor(MAASServerTestCase):
141
142 def test__composes_config(self):
143@@ -782,8 +829,6 @@
144 'ips_mapping': {},
145 'gateways_mapping': {mac.mac_address: [router]},
146 'nameservers': [dns],
147- # XXX jtv 2014-10-10, bug=1379641: empty for now, but to be
148- # populated soon.
149 'netmasks': {},
150 }
151 self.assertThat(fake, MockCalledOnceWith(node, expected_config))