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

Proposed by Mike Pontillo on 2018-07-12
Status: Merged
Approved by: Mike Pontillo on 2018-07-30
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 on 2018-07-30
MAAS Lander Approve on 2018-07-13
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.
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 on 2018-07-13

Fix errors resulting from merge conflict.

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 on 2018-07-13

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

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
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
1diff --git a/src/maasserver/models/interface.py b/src/maasserver/models/interface.py
2index 5c425b5..9a1867a 100644
3--- a/src/maasserver/models/interface.py
4+++ b/src/maasserver/models/interface.py
5@@ -1116,6 +1116,8 @@ class Interface(CleanSave, TimestampedModel):
6 """Remove all the `IPAddress` link on the interface."""
7 for ip_address in self.ip_addresses.exclude(
8 alloc_type=IPADDRESS_TYPE.DISCOVERED):
9+ maaslog.info("%s: IP address automatically unlinked: %s" % (
10+ self.get_log_string(), ip_address))
11 self.unlink_ip_address(ip_address, clearing_config=clearing_config)
12
13 def claim_auto_ips(self, exclude_addresses=[]):
14diff --git a/src/maasserver/models/staticipaddress.py b/src/maasserver/models/staticipaddress.py
15index 26ccd1b..40cdc1b 100644
16--- a/src/maasserver/models/staticipaddress.py
17+++ b/src/maasserver/models/staticipaddress.py
18@@ -455,7 +455,7 @@ class StaticIPAddressManager(Manager):
19 domain.ttl,
20 %s)""" % default_ttl
21 sql_query = """
22- SELECT DISTINCT ON (node.hostname, is_boot, family(staticip.ip))
23+ SELECT DISTINCT ON (fqdn, is_boot, family)
24 CONCAT(node.hostname, '.', domain.name) AS fqdn,
25 node.system_id,
26 node.node_type,
27@@ -465,16 +465,38 @@ class StaticIPAddressManager(Manager):
28 node.boot_interface_id IS NOT NULL AND
29 (
30 node.boot_interface_id = interface.id OR
31- node.boot_interface_id = parent.id
32+ node.boot_interface_id = parent.id OR
33+ node.boot_interface_id = parent_parent.id
34 ),
35 False
36- ) AS is_boot
37+ ) AS is_boot,
38+ CASE
39+ WHEN interface.type = 'bridge' AND
40+ parent_parent.id = node.boot_interface_id THEN 1
41+ WHEN interface.type = 'bridge' AND
42+ parent.id = node.boot_interface_id THEN 2
43+ WHEN interface.type = 'bond' AND
44+ parent.id = node.boot_interface_id THEN 3
45+ WHEN interface.type = 'physical' AND
46+ interface.id = node.boot_interface_id THEN 4
47+ WHEN interface.type = 'bond' THEN 5
48+ WHEN interface.type = 'physical' THEN 6
49+ WHEN interface.type = 'vlan' THEN 7
50+ WHEN interface.type = 'alias' THEN 8
51+ WHEN interface.type = 'unknown' THEN 9
52+ ELSE 10
53+ END AS preference,
54+ family(staticip.ip) AS family
55 FROM
56 maasserver_interface AS interface
57 LEFT OUTER JOIN maasserver_interfacerelationship AS rel ON
58 interface.id = rel.child_id
59 LEFT OUTER JOIN maasserver_interface AS parent ON
60 rel.parent_id = parent.id
61+ LEFT OUTER JOIN maasserver_interfacerelationship AS parent_rel ON
62+ parent.id = parent_rel.child_id
63+ LEFT OUTER JOIN maasserver_interface AS parent_parent ON
64+ parent_rel.parent_id = parent_parent.id
65 JOIN maasserver_node AS node ON
66 node.id = interface.node_id
67 JOIN maasserver_domain AS domain ON
68@@ -512,21 +534,10 @@ class StaticIPAddressManager(Manager):
69 staticip.ip IS NOT NULL AND
70 host(staticip.ip) != ''
71 ORDER BY
72- node.hostname,
73+ fqdn,
74 is_boot DESC,
75- family(staticip.ip),
76- CASE
77- WHEN interface.type = 'bond' AND
78- parent.id = node.boot_interface_id THEN 1
79- WHEN interface.type = 'physical' AND
80- interface.id = node.boot_interface_id THEN 2
81- WHEN interface.type = 'bond' THEN 3
82- WHEN interface.type = 'physical' THEN 4
83- WHEN interface.type = 'vlan' THEN 5
84- WHEN interface.type = 'alias' THEN 6
85- WHEN interface.type = 'unknown' THEN 7
86- ELSE 8
87- END,
88+ family,
89+ preference,
90 /*
91 * We want STICKY and USER_RESERVED addresses to be preferred,
92 * followed by AUTO, DHCP, and finally DISCOVERED.
93@@ -612,7 +623,7 @@ class StaticIPAddressManager(Manager):
94 # we will see all of the boot interfaces before we see any non-boot
95 # interface IPs. See Bug#1584850
96 for (fqdn, system_id, node_type, ttl,
97- ip, is_boot) in cursor.fetchall():
98+ ip, is_boot, preference, family) in cursor.fetchall():
99 mapping[fqdn].node_type = node_type
100 mapping[fqdn].system_id = system_id
101 mapping[fqdn].ttl = ttl
102diff --git a/src/maasserver/models/tests/test_staticipaddress.py b/src/maasserver/models/tests/test_staticipaddress.py
103index 995bb7a..d9a79a3 100644
104--- a/src/maasserver/models/tests/test_staticipaddress.py
105+++ b/src/maasserver/models/tests/test_staticipaddress.py
106@@ -821,6 +821,84 @@ class TestStaticIPAddressManagerMapping(MAASServerTestCase):
107 node.system_id, 30, {vlanip.ip}, node.node_type)}
108 self.assertEqual(expected_mapping, mapping)
109
110+ def test_get_hostname_ip_mapping_prefers_bridged_bond_pxe_interface(self):
111+ subnet = factory.make_Subnet(
112+ cidr='10.0.0.0/24', dns_servers=[], gateway_ip='10.0.0.1')
113+ node = factory.make_Node_with_Interface_on_Subnet(
114+ hostname='host', subnet=subnet)
115+ eth0 = node.get_boot_interface()
116+ eth0.name = 'eth0'
117+ eth0.save()
118+ eth1 = factory.make_Interface(
119+ INTERFACE_TYPE.PHYSICAL, node=node, name='eth1', vlan=subnet.vlan)
120+ eth2 = factory.make_Interface(
121+ INTERFACE_TYPE.PHYSICAL, node=node, name='eth2', vlan=subnet.vlan)
122+ node.boot_interface = eth1
123+ node.save()
124+ bond0 = factory.make_Interface(
125+ INTERFACE_TYPE.BOND, node=node, parents=[eth1, eth2], name='bond0')
126+ br_bond0 = factory.make_Interface(
127+ INTERFACE_TYPE.BRIDGE, parents=[bond0], name='br-bond0')
128+ phy_staticip = factory.make_StaticIPAddress(
129+ alloc_type=IPADDRESS_TYPE.STICKY, interface=eth0,
130+ subnet=subnet, ip='10.0.0.2')
131+ bridge_ip = factory.make_StaticIPAddress(
132+ alloc_type=IPADDRESS_TYPE.STICKY, interface=br_bond0,
133+ subnet=subnet, ip='10.0.0.3')
134+ mapping = StaticIPAddress.objects.get_hostname_ip_mapping(
135+ node.domain)
136+ expected_mapping = {
137+ node.fqdn: HostnameIPMapping(
138+ node.system_id, 30, {bridge_ip.ip}, node.node_type),
139+ "%s.%s" % (eth0.name, node.fqdn): HostnameIPMapping(
140+ node.system_id, 30, {phy_staticip.ip}, node.node_type),
141+ }
142+ self.assertThat(mapping, Equals(expected_mapping))
143+
144+ def test_get_hostname_ip_mapping_with_v4_and_v6_and_bridged_bonds(self):
145+ subnet_v4 = factory.make_Subnet(
146+ cidr=str(factory.make_ipv4_network().cidr))
147+ subnet_v6 = factory.make_Subnet(
148+ cidr='2001:db8::/64')
149+ node = factory.make_Node_with_Interface_on_Subnet(
150+ hostname='host', subnet=subnet_v4)
151+ eth0 = node.get_boot_interface()
152+ eth0.name = 'eth0'
153+ eth0.save()
154+ eth1 = factory.make_Interface(
155+ INTERFACE_TYPE.PHYSICAL, node=node, name='eth1')
156+ eth2 = factory.make_Interface(
157+ INTERFACE_TYPE.PHYSICAL, node=node, name='eth2')
158+ node.boot_interface = eth1
159+ node.save()
160+ bond0 = factory.make_Interface(
161+ INTERFACE_TYPE.BOND, node=node, parents=[eth1, eth2], name='bond0')
162+ br_bond0 = factory.make_Interface(
163+ INTERFACE_TYPE.BRIDGE, parents=[bond0], name='br-bond0')
164+ phy_staticip_v4 = factory.make_StaticIPAddress(
165+ alloc_type=IPADDRESS_TYPE.STICKY, interface=eth0,
166+ subnet=subnet_v4)
167+ bridge_ip_v4 = factory.make_StaticIPAddress(
168+ alloc_type=IPADDRESS_TYPE.STICKY, interface=br_bond0,
169+ subnet=subnet_v4)
170+ phy_staticip_v6 = factory.make_StaticIPAddress(
171+ alloc_type=IPADDRESS_TYPE.STICKY, interface=eth0,
172+ subnet=subnet_v6)
173+ bridge_ip_v6 = factory.make_StaticIPAddress(
174+ alloc_type=IPADDRESS_TYPE.STICKY, interface=br_bond0,
175+ subnet=subnet_v6)
176+ mapping = StaticIPAddress.objects.get_hostname_ip_mapping(
177+ node.domain)
178+ expected_mapping = {
179+ node.fqdn: HostnameIPMapping(
180+ node.system_id, 30, {bridge_ip_v4.ip, bridge_ip_v6.ip},
181+ node.node_type),
182+ "%s.%s" % (eth0.name, node.fqdn): HostnameIPMapping(
183+ node.system_id, 30, {phy_staticip_v4.ip, phy_staticip_v6.ip},
184+ node.node_type),
185+ }
186+ self.assertThat(mapping, Equals(expected_mapping))
187+
188 def test_get_hostname_ip_mapping_returns_domain_head_ips(self):
189 parent = factory.make_Domain()
190 name = factory.make_name()

Subscribers

People subscribed via source and target branches