Merge lp:~rvb/maas/maas-ip-assign-bug-1438218 into lp:~maas-committers/maas/trunk

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 3756
Proposed branch: lp:~rvb/maas/maas-ip-assign-bug-1438218
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 67 lines (+17/-6)
3 files modified
src/maasserver/models/staticipaddress.py (+5/-5)
src/maasserver/models/tests/test_staticipaddress.py (+12/-0)
src/maasserver/utils/orm.py (+0/-1)
To merge this branch: bzr merge lp:~rvb/maas/maas-ip-assign-bug-1438218
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Blake Rouse (community) Approve
Review via email: mp+254746@code.launchpad.net

Commit message

When acquiring a static IP address before deployment, leverage the retry mechanism to grab another IP address if it's been snatched from under us by another transaction.

Description of the change

Without this change, the whole transaction would fail to grab a second IP address because it would have been broken by the first error encountered (the IntegrityError).

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

Damn it... the whack-a-mole begins.

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

Looks good.

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

Thanks for the review Blake!

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/staticipaddress.py'
2--- src/maasserver/models/staticipaddress.py 2015-03-26 00:12:12 +0000
3+++ src/maasserver/models/staticipaddress.py 2015-03-31 15:49:59 +0000
4@@ -54,6 +54,7 @@
5 get_ip_based_hostname,
6 validate_hostname,
7 )
8+from maasserver.utils.orm import make_serialization_failure
9 from netaddr import (
10 IPAddress,
11 IPRange,
12@@ -208,11 +209,10 @@
13 requested_address, alloc_type, user,
14 hostname=hostname)
15 except StaticIPAddressUnavailable:
16- # That address has been taken since we obtained the
17- # list of existing addresses from the database. This
18- # is a race! It also ought to be impossible as
19- # this critical section is in a lock...
20- continue
21+ # This is phantom read: another transaction has
22+ # taken this IP. Raise a serialization failure to
23+ # let the retry mechanism do its thing.
24+ raise make_serialization_failure()
25 else:
26 raise StaticIPAddressExhaustion(
27 "No more IPs available in range %s-%s" % (
28
29=== modified file 'src/maasserver/models/tests/test_staticipaddress.py'
30--- src/maasserver/models/tests/test_staticipaddress.py 2015-03-26 00:12:12 +0000
31+++ src/maasserver/models/tests/test_staticipaddress.py 2015-03-31 15:49:59 +0000
32@@ -32,6 +32,7 @@
33 MockCalledOnceWith,
34 MockNotCalled,
35 )
36+from maasserver.utils.orm import is_serialization_failure
37 from mock import sentinel
38 from netaddr import (
39 IPAddress,
40@@ -116,6 +117,17 @@
41 StaticIPAddressUnavailable, StaticIPAddress.objects.allocate_new,
42 low, high, requested_address=requested_address)
43
44+ def test_allocate_new_raises_serialization_error_if_ip_taken(self):
45+ low, high = factory.make_ip_range()
46+ # Simulate a "IP already taken" error.
47+ mock_attempt_allocation = self.patch(
48+ StaticIPAddress.objects, '_attempt_allocation')
49+ mock_attempt_allocation.side_effect = StaticIPAddressUnavailable()
50+
51+ error = self.assertRaises(
52+ Exception, StaticIPAddress.objects.allocate_new, low, high)
53+ self.assertTrue(is_serialization_failure(error))
54+
55 def test_allocate_new_does_not_use_lock_for_requested_ip(self):
56 # When requesting a specific IP address, there's no need to
57 # acquire the lock.
58
59=== modified file 'src/maasserver/utils/orm.py'
60--- src/maasserver/utils/orm.py 2015-03-26 00:12:12 +0000
61+++ src/maasserver/utils/orm.py 2015-03-31 15:49:59 +0000
62@@ -217,7 +217,6 @@
63 set to `SERIALIZATION_FAILURE` without subclassing. I suspect only the C
64 interface can do that.
65 """
66-
67 pgcode = SERIALIZATION_FAILURE
68
69