Merge ~ack/maas:deploy-ip-check-exclude-addresses into maas:master

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: 6384b92fa39a4a0e2cbe6349d4af5ab54a2c4694
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ack/maas:deploy-ip-check-exclude-addresses
Merge into: maas:master
Diff against target: 102 lines (+70/-2)
2 files modified
src/maasserver/models/node.py (+5/-2)
src/maasserver/models/tests/test_node.py (+65/-0)
Reviewer Review Type Date Requested Status
Björn Tillenius Approve
MAAS Lander Approve
Review via email: mp+397715@code.launchpad.net

Commit message

LP: #1902425 - exclude already tested IPs when claiming IPs during deploy

This fixes a corner case for the linked bug which happens when the used IP is
on an interface that has neighbour discovery disabled, in which case the IP is
not recorded in MAAS, and can get picked up again.

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deploy-ip-check-exclude-addresses lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/9183/console
COMMIT: 30015b95cfbbbc7392b069966ae12220e8bd3338

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deploy-ip-check-exclude-addresses lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 6384b92fa39a4a0e2cbe6349d4af5ab54a2c4694

review: Approve
Revision history for this message
Björn Tillenius (bjornt) wrote :

+1

review: Approve

There was an error fetching revisions from git servers. Please try again in a few minutes. If the problem persists, contact Launchpad support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/models/node.py b/src/maasserver/models/node.py
2index 105ac72..16af317 100644
3--- a/src/maasserver/models/node.py
4+++ b/src/maasserver/models/node.py
5@@ -4335,9 +4335,11 @@ class Node(CleanSave, TimestampedModel):
6 bridge_fd=bridge_fd,
7 )
8
9- def claim_auto_ips(self, temp_expires_after=None):
10+ def claim_auto_ips(self, exclude_addresses=None, temp_expires_after=None):
11 """Assign IP addresses to all interface links set to AUTO."""
12- exclude_addresses = set()
13+ exclude_addresses = (
14+ exclude_addresses.copy() if exclude_addresses else set()
15+ )
16 allocated_ips = set()
17 # Query for the interfaces again here; if we use the cached
18 # interface_set, we could skip a newly-created bridge if it was created
19@@ -4500,6 +4502,7 @@ class Node(CleanSave, TimestampedModel):
20 yield deferToDatabase(clean_expired)
21 allocated_ips = yield deferToDatabase(
22 transactional(self.claim_auto_ips),
23+ exclude_addresses=attempted_ips,
24 temp_expires_after=timedelta(minutes=5),
25 )
26 if not allocated_ips:
27diff --git a/src/maasserver/models/tests/test_node.py b/src/maasserver/models/tests/test_node.py
28index e63ffa5..d7dbcec 100644
29--- a/src/maasserver/models/tests/test_node.py
30+++ b/src/maasserver/models/tests/test_node.py
31@@ -8664,6 +8664,71 @@ class TestNode_Start(MAASTransactionServerTestCase):
32 self.assertThat(auto_ip.ip, Equals(third_ip.ip))
33 self.assertThat(auto_ip.temp_expires_on, Is(None))
34
35+ def test_claims_auto_ip_addresses_skips_used_ip_discovery_disabled(self):
36+ user = factory.make_User()
37+ node = self.make_acquired_node_with_interface(
38+ user, power_type="manual"
39+ )
40+ node_interface = node.get_boot_interface()
41+ [auto_ip] = node_interface.ip_addresses.filter(
42+ alloc_type=IPADDRESS_TYPE.AUTO
43+ )
44+
45+ # Create a rack controller that has an interface on the same subnet
46+ # as the node. Don't enable neighbour discovery
47+ rack = factory.make_RackController()
48+ rack.interface_set.all().delete()
49+ rackif = factory.make_Interface(vlan=node_interface.vlan, node=rack)
50+ rackif_ip = factory.pick_ip_in_Subnet(auto_ip.subnet)
51+ rackif.link_subnet(
52+ INTERFACE_LINK_TYPE.STATIC, auto_ip.subnet, rackif_ip
53+ )
54+
55+ # Mock the rack controller connected to the region controller.
56+ client = Mock()
57+ client.ident = rack.system_id
58+ self.patch(node_module, "getAllClients").return_value = [client]
59+
60+ # Must be executed in a transaction as `allocate_new` uses savepoints.
61+ with transaction.atomic():
62+ # Get two IPs and remove them so they're unknown
63+ ip = StaticIPAddress.objects.allocate_new(
64+ subnet=auto_ip.subnet, alloc_type=IPADDRESS_TYPE.AUTO
65+ )
66+ ip1 = ip.ip
67+ ip.delete()
68+ ip = StaticIPAddress.objects.allocate_new(
69+ subnet=auto_ip.subnet,
70+ alloc_type=IPADDRESS_TYPE.AUTO,
71+ exclude_addresses=[ip1],
72+ )
73+ ip2 = ip.ip
74+ ip.delete()
75+
76+ client.side_effect = [
77+ defer.succeed(
78+ {
79+ "ip_addresses": [
80+ {
81+ "ip_address": ip1,
82+ "used": True,
83+ "mac_address": factory.make_mac_address(),
84+ }
85+ ]
86+ }
87+ ),
88+ defer.succeed(
89+ {"ip_addresses": [{"ip_address": ip2, "used": False}]}
90+ ),
91+ ]
92+
93+ with post_commit_hooks:
94+ node.start(user)
95+
96+ auto_ip = reload_object(auto_ip)
97+ self.assertThat(auto_ip.ip, Equals(ip2))
98+ self.assertThat(auto_ip.temp_expires_on, Is(None))
99+
100 def test_claims_auto_ip_addresses_retries_on_failure_from_rack(self):
101 user = factory.make_User()
102 node = self.make_acquired_node_with_interface(

Subscribers

People subscribed via source and target branches