Merge lp:~mpontillo/maas/fix-1570606 into lp:~maas-committers/maas/trunk

Proposed by Mike Pontillo
Status: Merged
Approved by: Mike Pontillo
Approved revision: no longer in the source branch.
Merged at revision: 4925
Proposed branch: lp:~mpontillo/maas/fix-1570606
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 117 lines (+44/-7)
5 files modified
.idea/maas.iml (+1/-1)
.idea/misc.xml (+1/-1)
.idea/modules.xml (+1/-1)
src/provisioningserver/utils/network.py (+15/-4)
src/provisioningserver/utils/tests/test_network.py (+26/-0)
To merge this branch: bzr merge lp:~mpontillo/maas/fix-1570606
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
LaMont Jones (community) Approve
Review via email: mp+291957@code.launchpad.net

Commit message

Add support for /31 and /127 subnets. Fixes bug #1570606.

To post a comment you must log in.
Revision history for this message
LaMont Jones (lamont) wrote :

Looks good. And yeah, /31 and /127 are strange corner cases that cause me to wonder at the sanity of the admin...

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

Looks good.

It might be good to create a test that runs through all of the different /n to make sure that it handles all cases.

review: Approve
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Agreed about testing all /n, but I think in order for the test to be valuable it couldn't just be a loop; I would want to examine the sanity of the data for each /n manually.

So... not today. =|

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (32.8 KiB)

The attempt to merge lp:~mpontillo/maas/fix-1570606 into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://security.ubuntu.com/ubuntu xenial-security InRelease
Get:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease [247 kB]
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:5 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/main Sources [866 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Sources [7,753 kB]
Get:7 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1,183 kB]
Get:8 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [7,538 kB]
Get:9 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial/universe Translation-en [4,358 kB]
Fetched 21.9 MB in 3s (5,841 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind bash bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm postgresql pxelinux python3-all python3-apt python3-bson python3-convoy python3-coverage python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-mock python3-netaddr python3-netifaces python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-2ubuntu2).
archdetect-deb is already the newest version (1.117ubuntu2).
authbind is already the newest version (2.1.1+nmu1).
bash is already the newest version (4.3-14ubuntu1).
bind9 is already the newest version (1:9.10.3.dfsg.P4-8).
bind9utils is already the newest version (1:9.10.3.dfsg.P4-8).
build-essential is already the newest version (12.1ubuntu2).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
dnsutils is already the newest versi...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.idea/maas.iml'
2--- .idea/maas.iml 2015-12-09 01:35:30 +0000
3+++ .idea/maas.iml 2016-04-15 16:47:24 +0000
4@@ -9,7 +9,7 @@
5 <excludeFolder url="file://$MODULE_DIR$/local" />
6 <excludeFolder url="file://$MODULE_DIR$/logs" />
7 </content>
8- <orderEntry type="jdk" jdkName="Python 3.5.1rc1 (/usr/bin/python3.5)" jdkType="Python SDK" />
9+ <orderEntry type="jdk" jdkName="Python 3.5.1+ (/usr/bin/python3.5)" jdkType="Python SDK" />
10 <orderEntry type="sourceFolder" forTests="false" />
11 </component>
12 <component name="TemplatesService">
13
14=== modified file '.idea/misc.xml'
15--- .idea/misc.xml 2015-12-09 01:35:30 +0000
16+++ .idea/misc.xml 2016-04-15 16:47:24 +0000
17@@ -10,5 +10,5 @@
18 <ConfirmationsSetting value="0" id="Add" />
19 <ConfirmationsSetting value="0" id="Remove" />
20 </component>
21- <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5.1rc1 (/usr/bin/python3.5)" project-jdk-type="Python SDK" />
22+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5.1+ (/usr/bin/python3.5)" project-jdk-type="Python SDK" />
23 </project>
24\ No newline at end of file
25
26=== modified file '.idea/modules.xml'
27--- .idea/modules.xml 2015-05-14 04:40:12 +0000
28+++ .idea/modules.xml 2016-04-15 16:47:24 +0000
29@@ -5,4 +5,4 @@
30 <module fileurl="file://$PROJECT_DIR$/.idea/maas.iml" filepath="$PROJECT_DIR$/.idea/maas.iml" />
31 </modules>
32 </component>
33-</project>
34+</project>
35\ No newline at end of file
36
37=== modified file 'src/provisioningserver/utils/network.py'
38--- src/provisioningserver/utils/network.py 2016-04-14 15:25:36 +0000
39+++ src/provisioningserver/utils/network.py 2016-04-15 16:47:24 +0000
40@@ -415,9 +415,10 @@
41 unused_ranges = []
42 if type(outer_range) == IPNetwork:
43 # Skip the network address, if this is a network
44- if outer_range.version == 4 and outer_range.prefixlen == 32:
45+ prefixlen = outer_range.prefixlen
46+ if outer_range.version == 4 and prefixlen in (31, 32):
47 start = outer_range.first
48- elif outer_range.version == 6 and outer_range.prefixlen == 128:
49+ elif outer_range.version == 6 and prefixlen in (127, 128):
50 start = outer_range.first
51 else:
52 start = outer_range.first + 1
53@@ -438,7 +439,8 @@
54 candidate_start = used_range.last + 1
55 # Skip the broadcast address, if this is an IPv4 network
56 if type(outer_range) == IPNetwork:
57- if outer_range.version == 4 and outer_range.prefixlen != 32:
58+ prefixlen = outer_range.prefixlen
59+ if outer_range.version == 4 and prefixlen not in (31, 32):
60 candidate_end = outer_range.last - 1
61 else:
62 candidate_end = outer_range.last
63@@ -453,7 +455,16 @@
64
65 def get_full_range(self, outer_range):
66 unused_ranges = self.get_unused_ranges(outer_range)
67- return MAASIPSet(self | unused_ranges, cidr=outer_range)
68+ full_range = MAASIPSet(self | unused_ranges, cidr=outer_range)
69+ # The full_range should always contain at least one IP address.
70+ # However, in bug #1570606 we observed a situation where there were
71+ # no resulting ranges. This assert is just in case the fix didn't cover
72+ # all cases where this could happen.
73+ assert len(full_range.ranges) > 0, (
74+ "get_full_range(): No ranges for CIDR: %s; "
75+ "self=%r, unused_ranges=%r" % (
76+ outer_range, self, unused_ranges))
77+ return full_range
78
79 def __repr__(self):
80 item_repr = []
81
82=== modified file 'src/provisioningserver/utils/tests/test_network.py'
83--- src/provisioningserver/utils/tests/test_network.py 2016-04-14 15:25:36 +0000
84+++ src/provisioningserver/utils/tests/test_network.py 2016-04-15 16:47:24 +0000
85@@ -789,6 +789,32 @@
86 self.assertThat(json['available_string'], Equals("100%"))
87 self.assertThat(json, Not(Contains("ranges")))
88
89+ def test__statistics_are_accurate_for_empty_slash_127(self):
90+ s = MAASIPSet([])
91+ u = s.get_full_range('2001:db8::1/127')
92+ stats = IPRangeStatistics(u)
93+ json = stats.render_json()
94+ self.assertThat(json['num_available'], Equals(2))
95+ self.assertThat(json['largest_available'], Equals(2))
96+ self.assertThat(json['num_unavailable'], Equals(0))
97+ self.assertThat(json['usage'], Equals(float(0) / float(2)))
98+ self.assertThat(json['usage_string'], Equals("0%"))
99+ self.assertThat(json['available_string'], Equals("100%"))
100+ self.assertThat(json, Not(Contains("ranges")))
101+
102+ def test__statistics_are_accurate_for_empty_slash_31(self):
103+ s = MAASIPSet([])
104+ u = s.get_full_range('10.0.0.0/31')
105+ stats = IPRangeStatistics(u)
106+ json = stats.render_json()
107+ self.assertThat(json['num_available'], Equals(2))
108+ self.assertThat(json['largest_available'], Equals(2))
109+ self.assertThat(json['num_unavailable'], Equals(0))
110+ self.assertThat(json['usage'], Equals(float(0) / float(2)))
111+ self.assertThat(json['usage_string'], Equals("0%"))
112+ self.assertThat(json['available_string'], Equals("100%"))
113+ self.assertThat(json, Not(Contains("ranges")))
114+
115 def test__suggests_subnet_anycast_address_for_ipv6(self):
116 s = MAASIPSet([])
117 u = s.get_full_range('2001:db8::/64')