Merge ~mpontillo/maas:default-dns-ip--bug-1776604--2.3 into maas:2.3

Proposed by Mike Pontillo
Status: Merged
Approved by: Mike Pontillo
Approved revision: b3662e720ee79d6f87b199dc362890b5b0468b6c
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~mpontillo/maas:default-dns-ip--bug-1776604--2.3
Merge into: maas:2.3
Diff against target: 190 lines (+109/-18)
3 files modified
src/maasserver/models/interface.py (+2/-0)
src/maasserver/models/staticipaddress.py (+29/-18)
src/maasserver/models/tests/test_staticipaddress.py (+78/-0)
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
MAAS Lander Approve
Review via email: mp+349444@code.launchpad.net

Commit message

LP: #1776604 - Improve hostname mapping heuristic for bonded bridges

This commit changes the default hostname to IP address mapping to
account for situations where an interface parent's parent is a
machine's boot interface.

Backports: 72aba3a90faa053905c20967604195e80fee6b05

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

UNIT TESTS
-b default-dns-ip--bug-1776604--2.3 lp:~mpontillo/maas/+git/maas into -b 2.3 lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci-jenkins.internal:8080/job/maas/job/branch-tester/3395/console
COMMIT: 9700765435ddfc532aa62a6dc41c239c7a1cd418

review: Needs Fixing
e74e6dc... by Mike Pontillo

Fix errors resulting from merge conflict.

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

UNIT TESTS
-b default-dns-ip--bug-1776604--2.3 lp:~mpontillo/maas/+git/maas into -b 2.3 lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci-jenkins.internal:8080/job/maas/job/branch-tester/3398/console
COMMIT: e74e6dc2150c8c25dc516381dead740c1d6cccd8

review: Needs Fixing
b3662e7... by Mike Pontillo

Update test cases to remove portions that don't work on MAAS 2.3.

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

UNIT TESTS
-b default-dns-ip--bug-1776604--2.3 lp:~mpontillo/maas/+git/maas into -b 2.3 lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: b3662e720ee79d6f87b199dc362890b5b0468b6c

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

Self-approve backport.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/models/interface.py b/src/maasserver/models/interface.py
index 5c425b5..9a1867a 100644
--- a/src/maasserver/models/interface.py
+++ b/src/maasserver/models/interface.py
@@ -1116,6 +1116,8 @@ class Interface(CleanSave, TimestampedModel):
1116 """Remove all the `IPAddress` link on the interface."""1116 """Remove all the `IPAddress` link on the interface."""
1117 for ip_address in self.ip_addresses.exclude(1117 for ip_address in self.ip_addresses.exclude(
1118 alloc_type=IPADDRESS_TYPE.DISCOVERED):1118 alloc_type=IPADDRESS_TYPE.DISCOVERED):
1119 maaslog.info("%s: IP address automatically unlinked: %s" % (
1120 self.get_log_string(), ip_address))
1119 self.unlink_ip_address(ip_address, clearing_config=clearing_config)1121 self.unlink_ip_address(ip_address, clearing_config=clearing_config)
11201122
1121 def claim_auto_ips(self, exclude_addresses=[]):1123 def claim_auto_ips(self, exclude_addresses=[]):
diff --git a/src/maasserver/models/staticipaddress.py b/src/maasserver/models/staticipaddress.py
index 26ccd1b..40cdc1b 100644
--- a/src/maasserver/models/staticipaddress.py
+++ b/src/maasserver/models/staticipaddress.py
@@ -455,7 +455,7 @@ class StaticIPAddressManager(Manager):
455 domain.ttl,455 domain.ttl,
456 %s)""" % default_ttl456 %s)""" % default_ttl
457 sql_query = """457 sql_query = """
458 SELECT DISTINCT ON (node.hostname, is_boot, family(staticip.ip))458 SELECT DISTINCT ON (fqdn, is_boot, family)
459 CONCAT(node.hostname, '.', domain.name) AS fqdn,459 CONCAT(node.hostname, '.', domain.name) AS fqdn,
460 node.system_id,460 node.system_id,
461 node.node_type,461 node.node_type,
@@ -465,16 +465,38 @@ class StaticIPAddressManager(Manager):
465 node.boot_interface_id IS NOT NULL AND465 node.boot_interface_id IS NOT NULL AND
466 (466 (
467 node.boot_interface_id = interface.id OR467 node.boot_interface_id = interface.id OR
468 node.boot_interface_id = parent.id468 node.boot_interface_id = parent.id OR
469 node.boot_interface_id = parent_parent.id
469 ),470 ),
470 False471 False
471 ) AS is_boot472 ) AS is_boot,
473 CASE
474 WHEN interface.type = 'bridge' AND
475 parent_parent.id = node.boot_interface_id THEN 1
476 WHEN interface.type = 'bridge' AND
477 parent.id = node.boot_interface_id THEN 2
478 WHEN interface.type = 'bond' AND
479 parent.id = node.boot_interface_id THEN 3
480 WHEN interface.type = 'physical' AND
481 interface.id = node.boot_interface_id THEN 4
482 WHEN interface.type = 'bond' THEN 5
483 WHEN interface.type = 'physical' THEN 6
484 WHEN interface.type = 'vlan' THEN 7
485 WHEN interface.type = 'alias' THEN 8
486 WHEN interface.type = 'unknown' THEN 9
487 ELSE 10
488 END AS preference,
489 family(staticip.ip) AS family
472 FROM490 FROM
473 maasserver_interface AS interface491 maasserver_interface AS interface
474 LEFT OUTER JOIN maasserver_interfacerelationship AS rel ON492 LEFT OUTER JOIN maasserver_interfacerelationship AS rel ON
475 interface.id = rel.child_id493 interface.id = rel.child_id
476 LEFT OUTER JOIN maasserver_interface AS parent ON494 LEFT OUTER JOIN maasserver_interface AS parent ON
477 rel.parent_id = parent.id495 rel.parent_id = parent.id
496 LEFT OUTER JOIN maasserver_interfacerelationship AS parent_rel ON
497 parent.id = parent_rel.child_id
498 LEFT OUTER JOIN maasserver_interface AS parent_parent ON
499 parent_rel.parent_id = parent_parent.id
478 JOIN maasserver_node AS node ON500 JOIN maasserver_node AS node ON
479 node.id = interface.node_id501 node.id = interface.node_id
480 JOIN maasserver_domain AS domain ON502 JOIN maasserver_domain AS domain ON
@@ -512,21 +534,10 @@ class StaticIPAddressManager(Manager):
512 staticip.ip IS NOT NULL AND534 staticip.ip IS NOT NULL AND
513 host(staticip.ip) != ''535 host(staticip.ip) != ''
514 ORDER BY536 ORDER BY
515 node.hostname,537 fqdn,
516 is_boot DESC,538 is_boot DESC,
517 family(staticip.ip),539 family,
518 CASE540 preference,
519 WHEN interface.type = 'bond' AND
520 parent.id = node.boot_interface_id THEN 1
521 WHEN interface.type = 'physical' AND
522 interface.id = node.boot_interface_id THEN 2
523 WHEN interface.type = 'bond' THEN 3
524 WHEN interface.type = 'physical' THEN 4
525 WHEN interface.type = 'vlan' THEN 5
526 WHEN interface.type = 'alias' THEN 6
527 WHEN interface.type = 'unknown' THEN 7
528 ELSE 8
529 END,
530 /*541 /*
531 * We want STICKY and USER_RESERVED addresses to be preferred,542 * We want STICKY and USER_RESERVED addresses to be preferred,
532 * followed by AUTO, DHCP, and finally DISCOVERED.543 * followed by AUTO, DHCP, and finally DISCOVERED.
@@ -612,7 +623,7 @@ class StaticIPAddressManager(Manager):
612 # we will see all of the boot interfaces before we see any non-boot623 # we will see all of the boot interfaces before we see any non-boot
613 # interface IPs. See Bug#1584850624 # interface IPs. See Bug#1584850
614 for (fqdn, system_id, node_type, ttl,625 for (fqdn, system_id, node_type, ttl,
615 ip, is_boot) in cursor.fetchall():626 ip, is_boot, preference, family) in cursor.fetchall():
616 mapping[fqdn].node_type = node_type627 mapping[fqdn].node_type = node_type
617 mapping[fqdn].system_id = system_id628 mapping[fqdn].system_id = system_id
618 mapping[fqdn].ttl = ttl629 mapping[fqdn].ttl = ttl
diff --git a/src/maasserver/models/tests/test_staticipaddress.py b/src/maasserver/models/tests/test_staticipaddress.py
index 995bb7a..d9a79a3 100644
--- a/src/maasserver/models/tests/test_staticipaddress.py
+++ b/src/maasserver/models/tests/test_staticipaddress.py
@@ -821,6 +821,84 @@ class TestStaticIPAddressManagerMapping(MAASServerTestCase):
821 node.system_id, 30, {vlanip.ip}, node.node_type)}821 node.system_id, 30, {vlanip.ip}, node.node_type)}
822 self.assertEqual(expected_mapping, mapping)822 self.assertEqual(expected_mapping, mapping)
823823
824 def test_get_hostname_ip_mapping_prefers_bridged_bond_pxe_interface(self):
825 subnet = factory.make_Subnet(
826 cidr='10.0.0.0/24', dns_servers=[], gateway_ip='10.0.0.1')
827 node = factory.make_Node_with_Interface_on_Subnet(
828 hostname='host', subnet=subnet)
829 eth0 = node.get_boot_interface()
830 eth0.name = 'eth0'
831 eth0.save()
832 eth1 = factory.make_Interface(
833 INTERFACE_TYPE.PHYSICAL, node=node, name='eth1', vlan=subnet.vlan)
834 eth2 = factory.make_Interface(
835 INTERFACE_TYPE.PHYSICAL, node=node, name='eth2', vlan=subnet.vlan)
836 node.boot_interface = eth1
837 node.save()
838 bond0 = factory.make_Interface(
839 INTERFACE_TYPE.BOND, node=node, parents=[eth1, eth2], name='bond0')
840 br_bond0 = factory.make_Interface(
841 INTERFACE_TYPE.BRIDGE, parents=[bond0], name='br-bond0')
842 phy_staticip = factory.make_StaticIPAddress(
843 alloc_type=IPADDRESS_TYPE.STICKY, interface=eth0,
844 subnet=subnet, ip='10.0.0.2')
845 bridge_ip = factory.make_StaticIPAddress(
846 alloc_type=IPADDRESS_TYPE.STICKY, interface=br_bond0,
847 subnet=subnet, ip='10.0.0.3')
848 mapping = StaticIPAddress.objects.get_hostname_ip_mapping(
849 node.domain)
850 expected_mapping = {
851 node.fqdn: HostnameIPMapping(
852 node.system_id, 30, {bridge_ip.ip}, node.node_type),
853 "%s.%s" % (eth0.name, node.fqdn): HostnameIPMapping(
854 node.system_id, 30, {phy_staticip.ip}, node.node_type),
855 }
856 self.assertThat(mapping, Equals(expected_mapping))
857
858 def test_get_hostname_ip_mapping_with_v4_and_v6_and_bridged_bonds(self):
859 subnet_v4 = factory.make_Subnet(
860 cidr=str(factory.make_ipv4_network().cidr))
861 subnet_v6 = factory.make_Subnet(
862 cidr='2001:db8::/64')
863 node = factory.make_Node_with_Interface_on_Subnet(
864 hostname='host', subnet=subnet_v4)
865 eth0 = node.get_boot_interface()
866 eth0.name = 'eth0'
867 eth0.save()
868 eth1 = factory.make_Interface(
869 INTERFACE_TYPE.PHYSICAL, node=node, name='eth1')
870 eth2 = factory.make_Interface(
871 INTERFACE_TYPE.PHYSICAL, node=node, name='eth2')
872 node.boot_interface = eth1
873 node.save()
874 bond0 = factory.make_Interface(
875 INTERFACE_TYPE.BOND, node=node, parents=[eth1, eth2], name='bond0')
876 br_bond0 = factory.make_Interface(
877 INTERFACE_TYPE.BRIDGE, parents=[bond0], name='br-bond0')
878 phy_staticip_v4 = factory.make_StaticIPAddress(
879 alloc_type=IPADDRESS_TYPE.STICKY, interface=eth0,
880 subnet=subnet_v4)
881 bridge_ip_v4 = factory.make_StaticIPAddress(
882 alloc_type=IPADDRESS_TYPE.STICKY, interface=br_bond0,
883 subnet=subnet_v4)
884 phy_staticip_v6 = factory.make_StaticIPAddress(
885 alloc_type=IPADDRESS_TYPE.STICKY, interface=eth0,
886 subnet=subnet_v6)
887 bridge_ip_v6 = factory.make_StaticIPAddress(
888 alloc_type=IPADDRESS_TYPE.STICKY, interface=br_bond0,
889 subnet=subnet_v6)
890 mapping = StaticIPAddress.objects.get_hostname_ip_mapping(
891 node.domain)
892 expected_mapping = {
893 node.fqdn: HostnameIPMapping(
894 node.system_id, 30, {bridge_ip_v4.ip, bridge_ip_v6.ip},
895 node.node_type),
896 "%s.%s" % (eth0.name, node.fqdn): HostnameIPMapping(
897 node.system_id, 30, {phy_staticip_v4.ip, phy_staticip_v6.ip},
898 node.node_type),
899 }
900 self.assertThat(mapping, Equals(expected_mapping))
901
824 def test_get_hostname_ip_mapping_returns_domain_head_ips(self):902 def test_get_hostname_ip_mapping_returns_domain_head_ips(self):
825 parent = factory.make_Domain()903 parent = factory.make_Domain()
826 name = factory.make_name()904 name = factory.make_name()

Subscribers

People subscribed via source and target branches