Merge lp:~lamont/maas/bug-1584850-trunk into lp:~maas-committers/maas/trunk

Proposed by LaMont Jones
Status: Merged
Approved by: LaMont Jones
Approved revision: no longer in the source branch.
Merged at revision: 5051
Proposed branch: lp:~lamont/maas/bug-1584850-trunk
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 130 lines (+66/-6)
2 files modified
src/maasserver/models/staticipaddress.py (+26/-5)
src/maasserver/models/tests/test_staticipaddress.py (+40/-1)
To merge this branch: bzr merge lp:~lamont/maas/bug-1584850-trunk
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+295630@code.launchpad.net

Commit message

Prefer boot-interface addresses to non-boot-interface addresses (in get_hostname_ip_mapping) and don't mix-n-match them.

Description of the change

Prefer boot-interface addresses to non-boot-interface addresses (in get_hostname_ip_mapping) and don't mix-n-match them.

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

See my review at https://code.launchpad.net/~lamont/maas/bug-1584850/+merge/295621.

FWIW, fixes are normally landed in trunk before they get a backport.

review: Needs Fixing
Revision history for this message
Gavin Panella (allenap) :
review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1.3 MiB)

The attempt to merge lp:~lamont/maas/bug-1584850-trunk into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [94.5 kB]
Hit:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [94.5 kB]
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 189 kB in 0s (420 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 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-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-netaddr python3-netifaces python3-novaclient 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-simplejson 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-2ubuntu3).
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).
build-essential is already the newest version (12.1ubuntu2).
bzr is already the newest version (2.7.0-2ubuntu1).
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).
freeipmi-tools is already the newest version (1.4.11-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
isc-dhcp-common is already the newest version (4.3.3-5ubuntu12).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
pxelinux is already the newest version (3:6.03+dfsg-1...

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

The attempt to merge lp:~lamont/maas/bug-1584850-trunk into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease [94.5 kB]
Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [94.5 kB]
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-updates/main Sources [40.5 kB]
Get:6 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [111 kB]
Get:7 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates/main Translation-en [45.4 kB]
Fetched 386 kB in 0s (829 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 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-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-netaddr python3-netifaces python3-novaclient 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-simplejson 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-2ubuntu3).
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).
build-essential is already the newest version (12.1ubuntu2).
bzr is already the newest version (2.7.0-2ubuntu1).
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).
freeipmi-tools is already the newest version (1.4.11-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
isc-dhcp-common is already the newest version (4.3.3-5ubuntu12).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is alre...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/models/staticipaddress.py'
--- src/maasserver/models/staticipaddress.py 2016-05-11 19:01:48 +0000
+++ src/maasserver/models/staticipaddress.py 2016-05-26 12:46:12 +0000
@@ -304,7 +304,7 @@
304304
305 # DISTINCT ON returns the first matching row for any given305 # DISTINCT ON returns the first matching row for any given
306 # hostname, using the query's ordering. Here, we're trying to306 # hostname, using the query's ordering. Here, we're trying to
307 # return the IP for the oldest Interface address.307 # return the IPs for the oldest Interface address.
308 #308 #
309 # For nodes that have disable_ipv4 set, leave out any IPv4 address.309 # For nodes that have disable_ipv4 set, leave out any IPv4 address.
310 if isinstance(domain_or_subnet, Subnet):310 if isinstance(domain_or_subnet, Subnet):
@@ -331,12 +331,16 @@
331 domain.ttl,331 domain.ttl,
332 %s)""" % default_ttl332 %s)""" % default_ttl
333 sql_query = """333 sql_query = """
334 SELECT DISTINCT ON (node.hostname, family(staticip.ip))334 SELECT DISTINCT ON (node.hostname, is_boot, family(staticip.ip))
335 node.hostname,335 node.hostname,
336 node.system_id,336 node.system_id,
337 node.node_type,337 node.node_type,
338 """ + ttl_clause + """ AS ttl,338 """ + ttl_clause + """ AS ttl,
339 domain.name, staticip.ip339 domain.name, staticip.ip,
340 (
341 node.boot_interface_id IS NOT NULL AND
342 node.boot_interface_id = interface.id
343 ) as is_boot
340 FROM344 FROM
341 maasserver_interface AS interface345 maasserver_interface AS interface
342 LEFT OUTER JOIN maasserver_interfacerelationship AS rel ON346 LEFT OUTER JOIN maasserver_interfacerelationship AS rel ON
@@ -366,6 +370,7 @@
366 )370 )
367 ORDER BY371 ORDER BY
368 node.hostname,372 node.hostname,
373 is_boot,
369 family(staticip.ip),374 family(staticip.ip),
370 CASE375 CASE
371 WHEN interface.type = 'bond' AND376 WHEN interface.type = 'bond' AND
@@ -401,14 +406,30 @@
401 # We get user reserved et al mappings first, so that we can overwrite406 # We get user reserved et al mappings first, so that we can overwrite
402 # TTL as we process the return from the SQL horror above.407 # TTL as we process the return from the SQL horror above.
403 mapping = self._get_user_reserved_mappings(domain_or_subnet)408 mapping = self._get_user_reserved_mappings(domain_or_subnet)
409 iface_is_boot = defaultdict(bool, {
410 hostname: True for hostname in mapping.keys()
411 })
404 cursor.execute(sql_query, (domain_or_subnet.id,))412 cursor.execute(sql_query, (domain_or_subnet.id,))
413 # The records from the query provide, for each hostname (after
414 # stripping domain), the boot and non-boot interface ip address in ipv4
415 # and ipv6. Our task: if there are boot interace IPs, they win. If
416 # there are none, then whatever we got wins. The ORDER BY means that
417 # we will see all of the non-boot interfaces before we see any boot
418 # interface IPs. See Bug#1584850
405 for (node_name, system_id, node_type,419 for (node_name, system_id, node_type,
406 ttl, domain_name, ip) in cursor.fetchall():420 ttl, domain_name, ip, is_boot) in cursor.fetchall():
407 hostname = "%s.%s" % (strip_domain(node_name), domain_name)421 hostname = "%s.%s" % (strip_domain(node_name), domain_name)
408 mapping[hostname].node_type = node_type422 mapping[hostname].node_type = node_type
409 mapping[hostname].system_id = system_id423 mapping[hostname].system_id = system_id
410 mapping[hostname].ttl = ttl424 mapping[hostname].ttl = ttl
411 mapping[hostname].ips.add(ip)425 # If this is a boot interface, and we have previously only found
426 # non-boot interface IPs, discard them. See also Bug#1584850.
427 if is_boot and not iface_is_boot[hostname]:
428 mapping[hostname].ips = set()
429 iface_is_boot[hostname] = True
430 # At this point, if the interface type is correct, keep the IP.
431 if is_boot == iface_is_boot[hostname]:
432 mapping[hostname].ips.add(ip)
412 return mapping433 return mapping
413434
414 def filter_by_ip_family(self, family):435 def filter_by_ip_family(self, family):
415436
=== modified file 'src/maasserver/models/tests/test_staticipaddress.py'
--- src/maasserver/models/tests/test_staticipaddress.py 2016-05-12 19:07:37 +0000
+++ src/maasserver/models/tests/test_staticipaddress.py 2016-05-26 12:46:12 +0000
@@ -5,7 +5,10 @@
55
6__all__ = []6__all__ = []
77
8from random import randint8from random import (
9 randint,
10 shuffle,
11)
9from unittest import skip12from unittest import skip
10from unittest.mock import sentinel13from unittest.mock import sentinel
1114
@@ -756,6 +759,42 @@
756 self.assertEqual({node.fqdn: HostnameIPMapping(759 self.assertEqual({node.fqdn: HostnameIPMapping(
757 node.system_id, 30, {sip1.ip}, node.node_type)}, mapping)760 node.system_id, 30, {sip1.ip}, node.node_type)}, mapping)
758761
762 def test_get_hostname_ip_mapping_does_not_return_discovered_and_auto(self):
763 # Create a situation where we have an AUTO ip on the pxeboot interface,
764 # and a discovered IP of the other address class (v4/v6) on another
765 # interface.
766 domain = Domain.objects.get_default_domain()
767 cidrs = [factory.make_ipv6_network(), factory.make_ipv4_network()]
768 shuffle(cidrs)
769 subnets = [factory.make_Subnet(cidr=cidr) for cidr in cidrs]
770 # First, make a node with an interface on subnets[0]. Assign the boot
771 # interface an AUTO IP on subnets[0].
772 node = factory.make_Node_with_Interface_on_Subnet(
773 hostname=factory.make_name('host'), subnet=subnets[0],
774 vlan=subnets[0].vlan, disable_ipv4=False)
775 sip0 = node.boot_interface.ip_addresses.first()
776 ip0 = factory.pick_ip_in_network(cidrs[0])
777 sip0.ip = ip0
778 sip0.alloc_type = IPADDRESS_TYPE.AUTO
779 sip0.save()
780 # Now create another interface, and give it a DISCOVERED IP of the
781 # other family from subnets[1].
782 iface1 = factory.make_Interface(node=node, vlan=subnets[1].vlan)
783 ip1 = factory.pick_ip_in_network(cidrs[1])
784 sip1 = factory.make_StaticIPAddress(
785 subnet=subnets[1], ip=ip1,
786 alloc_type=IPADDRESS_TYPE.DISCOVERED
787 )
788 iface1.ip_addresses.add(sip1)
789 iface1.save()
790 # The only mapping we should get is for the boot interface.
791 mapping = StaticIPAddress.objects.get_hostname_ip_mapping(domain)
792 expected_mapping = {
793 node.fqdn: HostnameIPMapping(
794 node.system_id, 30, {sip0.ip}, node.node_type
795 )}
796 self.assertEqual(expected_mapping, mapping)
797
759798
760class TestStaticIPAddress(MAASServerTestCase):799class TestStaticIPAddress(MAASServerTestCase):
761800