Merge lp:~julian-edwards/maas/consider-static-range into lp:~maas-committers/maas/trunk

Proposed by Julian Edwards
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: 2696
Proposed branch: lp:~julian-edwards/maas/consider-static-range
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 107 lines (+33/-9)
2 files modified
src/maasserver/api.py (+12/-3)
src/maasserver/tests/test_api_nodegroup.py (+21/-6)
To merge this branch: bzr merge lp:~julian-edwards/maas/consider-static-range
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) Approve
Review via email: mp+230760@code.launchpad.net

Commit message

Consider the static IP range, if configured, when linking MAC addresses to networks and cluster interfaces. This ensures that pre-existing nodes already using the static range will get linked.

Description of the change

The update_mac_cluster_interfaces() function is getting a little big, but it's just inside bigjools rule-of-thumb size for a function which is a full page of my terminal.

I hesitated to break it up anyway because everything in there is closely tied. Ideally it would be namespaced in a class to indicate that fact.

Anyway, api.py is 4000 lines long now. If we're going to split things up ...

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

"Everything is closely tied" is not a reason not to break things up; it's a reason to put more effort into breaking them up! Such irredeemable patches of code tend to spread like oil slicks. There's clearly stuff here that could be extracted, and make the code cleaner for it. I see loops that could do with a name, a docstring, or at least a comment.

One question about the design of this branch: why would you look just at the static range, and not at the network's full address range? Does it matter for the purpose of linking a node's network interface to a subnet whether the address is in the static range? If I reduced the static range after a node had already acquired a static address, so that the address is now outside the static range, should that affect whether this could makes the link? Wouldn't be a check against the network be more robust, as well as faster (because IPRange is so awful about “in”) and simpler?

review: Approve
Revision history for this message
Julian Edwards (julian-edwards) wrote :

Thank you for the review.

On Thursday 14 Aug 2014 09:41:01 you wrote:
> Review: Approve
>
> "Everything is closely tied" is not a reason not to break things up; it's a
> reason to put more effort into breaking them up! Such irredeemable patches
> of code tend to spread like oil slicks. There's clearly stuff here that
> could be extracted, and make the code cleaner for it. I see loops that
> could do with a name, a docstring, or at least a comment.

Oh I do agree, believe me. What I meant by closely tied is that I want to
namespace it. I *really* dislike interdependent functions scattered around a
module. But right now I don't have the headspace to tackle this in a way that
I would like. It's not fun having an illness that makes you feel stupid :(

> One question about the design of this branch: why would you look just at the
> static range, and not at the network's full address range? Does it matter
> for the purpose of linking a node's network interface to a subnet whether
> the address is in the static range? If I reduced the static range after a
> node had already acquired a static address, so that the address is now
> outside the static range, should that affect whether this could makes the
> link? Wouldn't be a check against the network be more robust, as well as

The existing ranges are definitive in terms of what we are serving on this
cluster. You cannot reduce a range and leave an existing address outside that
range; it is checked for and disallowed.

The point is that we can (and will) have machines appearing on this network
that we're not meant to service, so a tighter check is warranted.

> faster (because IPRange is so awful about “in”) and simpler?

Actually IPRange is ok, it's IPSet that's slow.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api.py'
2--- src/maasserver/api.py 2014-08-12 03:05:45 +0000
3+++ src/maasserver/api.py 2014-08-14 09:21:28 +0000
4@@ -1717,15 +1717,21 @@
5 for interface in interfaces:
6 ip_range = netaddr.IPRange(
7 interface.ip_range_low, interface.ip_range_high)
8- interface_ranges[interface] = ip_range
9+ if interface.static_ip_range_low and interface.static_ip_range_high:
10+ static_range = netaddr.IPRange(
11+ interface.static_ip_range_low, interface.static_ip_range_high)
12+ else:
13+ static_range = []
14+ interface_ranges[interface] = (ip_range, static_range)
15 for ip, mac in leases.items():
16 try:
17 mac_address = MACAddress.objects.get(mac_address=mac)
18 except MACAddress.DoesNotExist:
19 # Silently ignore MAC addresses that we don't know about.
20 continue
21- for interface, ip_range in interface_ranges.items():
22- if netaddr.IPAddress(ip) in ip_range:
23+ for interface, (ip_range, static_range) in interface_ranges.items():
24+ ipaddress = netaddr.IPAddress(ip)
25+ if ipaddress in ip_range or ipaddress in static_range:
26 mac_address.cluster_interface = interface
27 mac_address.save()
28
29@@ -1735,6 +1741,9 @@
30 try:
31 network = Network.objects.get(ip=ipnetwork.ip.format())
32 network.macaddress_set.add(mac_address)
33+ maaslog.info(
34+ "Linking %s to network %s",
35+ mac_address, network.name)
36 except Network.DoesNotExist:
37 pass
38
39
40=== modified file 'src/maasserver/tests/test_api_nodegroup.py'
41--- src/maasserver/tests/test_api_nodegroup.py 2014-08-12 03:03:53 +0000
42+++ src/maasserver/tests/test_api_nodegroup.py 2014-08-14 09:21:28 +0000
43@@ -79,12 +79,16 @@
44 )
45
46
47-def get_random_ip_from_interface_range(interface):
48+def get_random_ip_from_interface_range(interface, use_static_range=None):
49 """Return a random IP from the pool available to an interface.
50
51 :return: An IP address as a string."""
52- ip_range = netaddr.IPRange(
53- interface.ip_range_low, interface.ip_range_high)
54+ if use_static_range:
55+ ip_range = netaddr.IPRange(
56+ interface.static_ip_range_low, interface.static_ip_range_high)
57+ else:
58+ ip_range = netaddr.IPRange(
59+ interface.ip_range_low, interface.ip_range_high)
60 chosen_ip = random.choice(ip_range)
61 return unicode(chosen_ip)
62
63@@ -834,7 +838,7 @@
64 class TestUpdateMacClusterInterfaces(MAASServerTestCase):
65 """Tests for `update_mac_cluster_interfaces`()."""
66
67- def make_cluster_with_macs_and_leases(self):
68+ def make_cluster_with_macs_and_leases(self, use_static_range=False):
69 cluster = factory.make_node_group()
70 mac_addresses = {
71 factory.make_mac_address(): factory.make_node_group_interface(
72@@ -842,7 +846,7 @@
73 for i in range(4)
74 }
75 leases = {
76- get_random_ip_from_interface_range(interface): (
77+ get_random_ip_from_interface_range(interface, use_static_range): (
78 mac_address.mac_address)
79 for mac_address, interface in mac_addresses.viewitems()
80 }
81@@ -859,6 +863,17 @@
82 }
83 self.assertEqual(mac_addresses, results)
84
85+ def test_considers_static_range_when_updating_interfaces(self):
86+ cluster, mac_addresses, leases = (
87+ self.make_cluster_with_macs_and_leases(use_static_range=True))
88+ update_mac_cluster_interfaces(leases, cluster)
89+ results = {
90+ mac_address: mac_address.cluster_interface
91+ for mac_address in MACAddress.objects.filter(
92+ mac_address__in=leases.values())
93+ }
94+ self.assertEqual(mac_addresses, results)
95+
96 def test_updates_network_relations(self):
97 # update_mac_cluster_interfaces should also associate the mac
98 # with the network on which it resides.
99@@ -873,7 +888,7 @@
100 # fugly, so I'm iterating.
101 for net, mac in expected_relations:
102 [observed_macddress] = net.macaddress_set.all()
103- self.assertEqual(mac, observed_macddress)
104+ self.expectThat(mac, Equals(observed_macddress))
105
106 def test_ignores_mac_not_attached_to_cluster(self):
107 cluster = factory.make_node_group()