Merge lp:~lamont/maas/bug-1677741 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: 5908
Proposed branch: lp:~lamont/maas/bug-1677741
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 432 lines (+215/-82)
2 files modified
src/maasserver/models/staticipaddress.py (+75/-43)
src/maasserver/models/tests/test_staticipaddress.py (+140/-39)
To merge this branch: bzr merge lp:~lamont/maas/bug-1677741
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+321572@code.launchpad.net

Commit message

In some cases, DNS Resource address records were ignored.

Description of the change

Refactor the special mappings in the static ipaddress model so that they
actually return the right things. Add greater coverage to the unit tests.

staticipaddress.py is best reviewed by simply reading the new version of the
file, since it's building an SQL query bit by bit and the diff doesn't help.

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

This code is very difficult to review since its complexity has gone through the roof.

I think I said this the last this was changed, but I really think we should break this down into multiple queries (via views, perhaps) so that individual pieces can be tested easier.

For now, I attempted to review by comparing the added/changed tests to the added/changed code. I think I would like to see more specific tests to capture each edge case, such as:

    test__default_domain_is_extra_special_ipv4
    test__default_domain_is_extra_special_ipv6
    test__domains_are_special
    test__attached_addresses_only_map_back_to_node

That way it's clearer to future maintainers how each edge case and branch called out in the SQL maps to a requirement for a specific behavior.

review: Needs Fixing
Revision history for this message
LaMont Jones (lamont) wrote :

> This code is very difficult to review since its complexity has gone through
> the roof.
>
> I think I said this the last this was changed, but I really think we should
> break this down into multiple queries (via views, perhaps) so that individual
> pieces can be tested easier.
>
> For now, I attempted to review by comparing the added/changed tests to the
> added/changed code. I think I would like to see more specific tests to capture
> each edge case, such as:
>
> test__default_domain_is_extra_special_ipv4
> test__default_domain_is_extra_special_ipv6
These are both covered via:
    test_user_reserved_addresses_included_in_get_hostname_ip_mapping
    test_user_reserved_addresses_included_in_correct_domains
    test_user_reserved_IP_on_node_or_default_domain_not_both
I have updated them to be more clear about what they are expecting to see.

> test__domains_are_special
This is covered (among others) via:
    test_user_reserved_addresses_included_in_correct_domains

> test__attached_addresses_only_map_back_to_node
This is covered via:
    test_get_hostname_ip_mapping_handles_dnsrr_node_collision

> That way it's clearer to future maintainers how each edge case and branch
> called out in the SQL maps to a requirement for a specific behavior.

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

Thanks for the cleanup; I tested this and it's working well!

review: Approve

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 2017-03-25 22:29:09 +0000
+++ src/maasserver/models/staticipaddress.py 2017-03-31 21:12:36 +0000
@@ -252,14 +252,21 @@
252 """Get the special mappings, possibly limited to a single Domain.252 """Get the special mappings, possibly limited to a single Domain.
253253
254 This function is responsible for creating these mappings:254 This function is responsible for creating these mappings:
255 - any USER_RESERVED IP,255 - any USER_RESERVED IP that has no name (dnsrr or node),
256 - any IP not associated with a Node,256 - any IP not associated with a Node,
257 - any IP associated with a DNSResource.257 - any IP associated with a DNSResource.
258
259 Addresses that are associated with both a Node and a DNSResource behave
260 thusly:
261 - Both forward mappings include the address
262 - The reverse mapping points only to the Node (and is the
263 responsibility of the caller.)
264
258 The caller is responsible for addresses otherwise derived from nodes.265 The caller is responsible for addresses otherwise derived from nodes.
259266
260 Because of how the get hostname_ip_mapping code works, we actually need267 Because of how the get hostname_ip_mapping code works, we actually need
261 to fetch ALL of the entries for subnets, but forward mappings need to268 to fetch ALL of the entries for subnets, but forward mappings are
262 be domain-specific.269 domain-specific.
263270
264 :param domain: limit return to just the given Domain. If anything271 :param domain: limit return to just the given Domain. If anything
265 other than a Domain is passed in (e.g., a Subnet or None), we272 other than a Domain is passed in (e.g., a Subnet or None), we
@@ -270,32 +277,6 @@
270 :return: a (default) dict of hostname: HostnameIPMapping entries.277 :return: a (default) dict of hostname: HostnameIPMapping entries.
271 """278 """
272 default_ttl = "%d" % Config.objects.get_config('default_dns_ttl')279 default_ttl = "%d" % Config.objects.get_config('default_dns_ttl')
273 if isinstance(domain, Domain):
274 # Domains are special in that we only want to have entries for the
275 # domain that we were asked about. And they can possibly come from
276 # either the child or the parent for glue.
277 where_clause = """
278 AND (
279 dnsrr.dom2_id = %s OR
280 node.dom2_id = %s OR
281 dnsrr.domain_id = %s OR
282 node.domain_id = %s
283 """
284 query_parms = [domain.id, domain.id, domain.id, domain.id]
285 # And the default domain is extra special, since it needs to have
286 # A/AAAA RRs for any USER_RESERVED addresses that have no name
287 # otherwise attached to them.
288 if domain.is_default():
289 where_clause += """ OR (
290 dnsrr.fqdn IS NULL AND
291 node.fqdn IS NULL)
292 """
293 where_clause += ")"
294 else:
295 # There is nothing special about the query for subnets.
296 domain = None
297 where_clause = ""
298 query_parms = []
299 # raw_ttl says that we don't coalesce, but we need to pick one, so we280 # raw_ttl says that we don't coalesce, but we need to pick one, so we
300 # go with DNSResource if it is involved.281 # go with DNSResource if it is involved.
301 if raw_ttl:282 if raw_ttl:
@@ -371,27 +352,78 @@
371 ) AS node ON352 ) AS node ON
372 node_sip_id = staticip.id353 node_sip_id = staticip.id
373 WHERE354 WHERE
374 staticip.ip IS NOT NULL AND355 (staticip.ip IS NOT NULL AND host(staticip.ip) != '') AND
375 host(staticip.ip) != '' AND356 """
376 (357
377 staticip.alloc_type = %s OR358 query_parms = []
378 node.fqdn IS NULL OR359 if isinstance(domain, Domain):
379 dnsrr IS NOT NULL360 if domain.is_default():
380 )""" + where_clause + """361 # The default domain is extra special, since it needs to have
381 """362 # A/AAAA RRs for any USER_RESERVED addresses that have no name
363 # otherwise attached to them.
364 # We need to get all of the entries that are:
365 # - in this domain and have a dnsrr associated, OR
366 # - are USER_RESERVED and have NO fqdn associated at all.
367 sql_query += """ ((
368 staticip.alloc_type = %s AND
369 dnsrr.fqdn IS NULL AND
370 node.fqdn IS NULL
371 ) OR (
372 dnsrr.fqdn IS NOT NULL AND
373 (
374 dnsrr.dom2_id = %s OR
375 node.dom2_id = %s OR
376 dnsrr.domain_id = %s OR
377 node.domain_id = %s)))"""
378 query_parms += [IPADDRESS_TYPE.USER_RESERVED]
379 else:
380 # For domains, we only need answers for the domain we were
381 # given. These can can possibly come from either the child or
382 # the parent for glue. Anything with a node associated will be
383 # found inside of get_hostname_ip_mapping() - we need any
384 # entries that are:
385 # - in this domain and have a dnsrr associated.
386 sql_query += """ (
387 dnsrr.fqdn IS NOT NULL AND
388 (
389 dnsrr.dom2_id = %s OR
390 node.dom2_id = %s OR
391 dnsrr.domain_id = %s OR
392 node.domain_id = %s))"""
393 query_parms += [domain.id, domain.id, domain.id, domain.id]
394 else:
395 # In the subnet map, addresses attached to nodes only map back to
396 # the node, since some things don't like multiple PTR RRs in
397 # answers from the DNS.
398 # Since that is handled in get_hostname_ip_mapping, we exclude
399 # anything where the node also has a link to the address.
400 domain = None
401 sql_query += """ ((
402 node.fqdn IS NULL AND dnsrr.fqdn IS NOT NULL
403 ) OR (
404 staticip.alloc_type = %s AND
405 dnsrr.fqdn IS NULL AND
406 node.fqdn IS NULL))"""
407 query_parms += [IPADDRESS_TYPE.USER_RESERVED]
408
382 default_domain = Domain.objects.get_default_domain()409 default_domain = Domain.objects.get_default_domain()
383 mapping = defaultdict(HostnameIPMapping)410 mapping = defaultdict(HostnameIPMapping)
384 cursor = connection.cursor()411 cursor = connection.cursor()
385 query_parms = [IPADDRESS_TYPE.USER_RESERVED] + query_parms
386 cursor.execute(sql_query, query_parms)412 cursor.execute(sql_query, query_parms)
387 for (fqdn, system_id, node_type, ttl,413 for (fqdn, system_id, node_type, ttl, ip) in cursor.fetchall():
388 ip) in cursor.fetchall():
389 if fqdn is None or fqdn == '':414 if fqdn is None or fqdn == '':
390 fqdn = "%s.%s" % (415 fqdn = "%s.%s" % (
391 get_ip_based_hostname(ip), default_domain.name)416 get_ip_based_hostname(ip), default_domain.name)
392 mapping[fqdn].node_type = node_type417 # It is possible that there are both Node and DNSResource entries
393 mapping[fqdn].system_id = system_id418 # for this fqdn. If we have any system_id, preserve it. Ditto for
394 mapping[fqdn].ttl = ttl419 # TTL. It is left as an exercise for the admin to make sure that
420 # the any non-default TTL applied to the Node and DNSResource are
421 # equal.
422 if system_id is not None:
423 mapping[fqdn].node_type = node_type
424 mapping[fqdn].system_id = system_id
425 if ttl is not None:
426 mapping[fqdn].ttl = ttl
395 mapping[fqdn].ips.add(ip)427 mapping[fqdn].ips.add(ip)
396 return mapping428 return mapping
397429
398430
=== modified file 'src/maasserver/models/tests/test_staticipaddress.py'
--- src/maasserver/models/tests/test_staticipaddress.py 2017-03-25 22:29:09 +0000
+++ src/maasserver/models/tests/test_staticipaddress.py 2017-03-31 21:12:36 +0000
@@ -10,7 +10,6 @@
10 shuffle,10 shuffle,
11)11)
12import threading12import threading
13from unittest import skip
14from unittest.mock import sentinel13from unittest.mock import sentinel
1514
16from django.core.exceptions import ValidationError15from django.core.exceptions import ValidationError
@@ -822,7 +821,6 @@
822 node.system_id, 30, {vlanip.ip}, node.node_type)}821 node.system_id, 30, {vlanip.ip}, node.node_type)}
823 self.assertEqual(expected_mapping, mapping)822 self.assertEqual(expected_mapping, mapping)
824823
825 @skip("XXX: GavinPanella 2016-04-27 bug=1556188: Fails spuriously.")
826 def test_get_hostname_ip_mapping_returns_domain_head_ips(self):824 def test_get_hostname_ip_mapping_returns_domain_head_ips(self):
827 parent = factory.make_Domain()825 parent = factory.make_Domain()
828 name = factory.make_name()826 name = factory.make_name()
@@ -923,6 +921,67 @@
923 }921 }
924 self.assertEqual(expected_mapping, mapping)922 self.assertEqual(expected_mapping, mapping)
925923
924 def test_get_hostname_ip_mapping_handles_dnsrr_node_collision(self):
925 hostname = factory.make_name('hostname')
926 domainname = factory.make_name('domain')
927 # Randomly make our domain either the default, or non-default.
928 # This does not change what we expect the answer to be.
929 if factory.pick_bool():
930 Domain.objects.get_default_domain()
931 domain = factory.make_Domain(name=domainname)
932 full_hostname = "%s.%s" % (hostname, domainname)
933 dnsrrname = factory.make_name('dnsrrname')
934 full_dnsrrname = "%s.%s" % (dnsrrname, domainname)
935
936 subnet = factory.make_Subnet()
937 node = factory.make_Node_with_Interface_on_Subnet(
938 interface=True, hostname=full_hostname, interface_count=3,
939 subnet=subnet)
940 boot_interface = node.get_boot_interface()
941 staticip = factory.make_StaticIPAddress(
942 alloc_type=IPADDRESS_TYPE.STICKY,
943 ip=factory.pick_ip_in_Subnet(subnet),
944 subnet=subnet, interface=boot_interface)
945 iface2 = node.interface_set.exclude(id=boot_interface.id).first()
946 sip2 = factory.make_StaticIPAddress(
947 alloc_type=IPADDRESS_TYPE.STICKY,
948 ip=factory.pick_ip_in_Subnet(subnet),
949 subnet=subnet, interface=iface2)
950 sip3 = factory.make_StaticIPAddress(
951 alloc_type=IPADDRESS_TYPE.STICKY,
952 ip=factory.pick_ip_in_Subnet(subnet),
953 subnet=subnet)
954 # Create a DNSResource with one address on the node, and one not.
955 # The forward mapping for the dnsrr points to both IPs.
956 # The subnet mapping for the IP on the node only points to the node.
957 # The other IP points to the DNSRR name.
958 factory.make_DNSResource(
959 name=dnsrrname, domain=domain, ip_addresses=[sip2, sip3])
960 mapping = StaticIPAddress.objects.get_hostname_ip_mapping(domain)
961 expected = {
962 full_hostname:
963 HostnameIPMapping(
964 node.system_id, 30, {staticip.ip}, node.node_type),
965 "%s.%s" % (iface2.name, full_hostname):
966 HostnameIPMapping(
967 node.system_id, 30, {sip2.ip}, node.node_type),
968 full_dnsrrname:
969 HostnameIPMapping(
970 node.system_id, 30, {sip2.ip, sip3.ip}, node.node_type),
971 }
972 self.assertEqual(expected, mapping)
973 mapping = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)
974 expected = {
975 full_hostname:
976 HostnameIPMapping(
977 node.system_id, 30, {staticip.ip}, node.node_type),
978 "%s.%s" % (iface2.name, full_hostname):
979 HostnameIPMapping(
980 node.system_id, 30, {sip2.ip}, node.node_type),
981 full_dnsrrname:
982 HostnameIPMapping(None, 30, {sip3.ip}, None),
983 }
984
926985
927class TestStaticIPAddress(MAASServerTestCase):986class TestStaticIPAddress(MAASServerTestCase):
928987
@@ -1012,23 +1071,34 @@
1012 alloc_type=IPADDRESS_TYPE.USER_RESERVED)1071 alloc_type=IPADDRESS_TYPE.USER_RESERVED)
1013 for _ in range(num_ips)1072 for _ in range(num_ips)
1014 ]1073 ]
1074 expected = {
1075 ip.dnsresource_set.first().fqdn:
1076 HostnameIPMapping(None, 30, {ip.ip}, None)
1077 for ip in ips
1078 }
1015 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain0)1079 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain0)
1016 self.expectThat(mappings, HasLength(len(ips)))1080 self.assertEqual(expected, mappings)
1017 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain1)1081 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain1)
1018 self.expectThat(mappings, HasLength(0))1082 self.expectThat(mappings, HasLength(0))
10191083
1020 def test_user_reserved_addresses_included_in_correct_domains(self):1084 def test_user_reserved_addresses_included_in_correct_domains(self):
1021 # Generate addresses in two domains, and make sure that they wind up in1085 # Generate some addresses with no names attached, and some more in each
1022 # the right domains, and not in other domains.1086 # of two (non-default) domains. Make sure that they wind up in the
1087 # right domains, and not in other domains.
1023 domain0 = Domain.objects.get_default_domain()1088 domain0 = Domain.objects.get_default_domain()
1024 domain1 = factory.make_Domain()1089 domain1 = factory.make_Domain()
1025 domain2 = factory.make_Domain()1090 domain2 = factory.make_Domain()
1091 ips0 = [
1092 factory.make_StaticIPAddress(
1093 alloc_type=IPADDRESS_TYPE.USER_RESERVED)
1094 for _ in range(randint(3, 5))
1095 ]
1026 ips1 = [1096 ips1 = [
1027 factory.make_StaticIPAddress(1097 factory.make_StaticIPAddress(
1028 hostname="%s.%s" % (1098 hostname="%s.%s" % (
1029 factory.make_name('host'), domain1.name),1099 factory.make_name('host'), domain1.name),
1030 alloc_type=IPADDRESS_TYPE.USER_RESERVED)1100 alloc_type=IPADDRESS_TYPE.USER_RESERVED)
1031 for _ in range(randint(3, 5))1101 for _ in range(randint(6, 9))
1032 ]1102 ]
1033 ips2 = [1103 ips2 = [
1034 factory.make_StaticIPAddress(1104 factory.make_StaticIPAddress(
@@ -1037,12 +1107,27 @@
1037 alloc_type=IPADDRESS_TYPE.USER_RESERVED)1107 alloc_type=IPADDRESS_TYPE.USER_RESERVED)
1038 for _ in range(randint(1, 2))1108 for _ in range(randint(1, 2))
1039 ]1109 ]
1110 expected = {
1111 "%s.%s" % (get_ip_based_hostname(ip.ip), domain0.name):
1112 HostnameIPMapping(None, 30, {ip.ip}, None)
1113 for ip in ips0
1114 }
1040 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain0)1115 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain0)
1041 self.expectThat(mappings, HasLength(0))1116 self.assertEqual(expected, mappings)
1117 expected = {
1118 ip.dnsresource_set.first().fqdn:
1119 HostnameIPMapping(None, 30, {ip.ip}, None)
1120 for ip in ips1
1121 }
1042 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain1)1122 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain1)
1043 self.expectThat(mappings, HasLength(len(ips1)))1123 self.assertEqual(expected, mappings)
1124 expected = {
1125 ip.dnsresource_set.first().fqdn:
1126 HostnameIPMapping(None, 30, {ip.ip}, None)
1127 for ip in ips2
1128 }
1044 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain2)1129 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain2)
1045 self.expectThat(mappings, HasLength(len(ips2)))1130 self.assertEqual(expected, mappings)
10461131
1047 def test_dns_resources_only_have_correct_domain(self):1132 def test_dns_resources_only_have_correct_domain(self):
1048 # Create two DNS resources pointing to the same IP, and make sure that1133 # Create two DNS resources pointing to the same IP, and make sure that
@@ -1080,35 +1165,54 @@
1080 def test_user_reserved_IP_on_node_or_default_domain_not_both(self):1165 def test_user_reserved_IP_on_node_or_default_domain_not_both(self):
1081 # ip1 gets assigned to an interface on a node in domain11166 # ip1 gets assigned to an interface on a node in domain1
1082 # ip2 is not assigned to anything.1167 # ip2 is not assigned to anything.
1168 # ip3 gets assigned to a DNS resource in domain2
1083 # ip1 should show up for the node, in domain1, and the subnet.1169 # ip1 should show up for the node, in domain1, and the subnet.
1084 # ip2 should show up in the default domain, and the subnet.1170 # ip2 should show up in the default domain, and the subnet.
1171 # ip3 should show up in domain2, and the subnet.
1085 domain0 = Domain.objects.get_default_domain()1172 domain0 = Domain.objects.get_default_domain()
1086 domain1 = factory.make_Domain()1173 domain1 = factory.make_Domain()
1174 domain2 = factory.make_Domain()
1175 rrname = factory.make_name('dnsrr')
1087 subnet = factory.make_Subnet()1176 subnet = factory.make_Subnet()
1088 ip1 = factory.make_StaticIPAddress(subnet=subnet)1177 ip1 = factory.make_StaticIPAddress(subnet=subnet)
1089 ip2 = factory.make_StaticIPAddress(subnet=subnet)1178 ip2 = factory.make_StaticIPAddress(
1179 subnet=subnet, alloc_type=IPADDRESS_TYPE.USER_RESERVED)
1180 ip3 = factory.make_StaticIPAddress(
1181 subnet=subnet, alloc_type=IPADDRESS_TYPE.USER_RESERVED)
1182 dnsrr = factory.make_DNSResource(
1183 name=rrname, domain=domain2, ip_addresses=[ip3])
1090 name2 = "%s.%s" % (get_ip_based_hostname(ip2.ip), domain0.name)1184 name2 = "%s.%s" % (get_ip_based_hostname(ip2.ip), domain0.name)
1091 node = factory.make_Node(1185 node = factory.make_Node(
1092 interface=True,1186 interface=True,
1093 domain=domain1,1187 domain=domain1,
1094 vlan=subnet.vlan)1188 vlan=subnet.vlan)
1095 node.interface_set.first().ip_addresses.add(ip1)1189 node.interface_set.first().ip_addresses.add(ip1)
1190 expected0 = {
1191 name2: HostnameIPMapping(None, 30, {ip2.ip}, None),
1192 }
1193 expected1 = {
1194 node.fqdn:
1195 HostnameIPMapping(
1196 node.system_id, 30, {ip1.ip}, node.node_type),
1197 }
1198 expected2 = {
1199 dnsrr.fqdn: HostnameIPMapping(None, 30, {ip3.ip}, None),
1200 }
1201 expected_subnet = {
1202 name2: HostnameIPMapping(None, 30, {ip2.ip}, None),
1203 node.fqdn:
1204 HostnameIPMapping(
1205 node.system_id, 30, {ip1.ip}, node.node_type),
1206 dnsrr.fqdn: HostnameIPMapping(None, 30, {ip3.ip}, None),
1207 }
1096 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain0)1208 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain0)
1097 self.expectThat(mappings, HasLength(1))1209 self.assertEqual(expected0, mappings)
1098 self.assertEqual(
1099 mappings, {
1100 name2: HostnameIPMapping(None, 30, {ip2.ip}, None)})
1101 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain1)1210 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain1)
1102 self.expectThat(mappings, HasLength(1))1211 self.assertEqual(expected1, mappings)
1103 self.assertEqual(1212 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain2)
1104 mappings.get(node.fqdn),1213 self.assertEqual(expected2, mappings)
1105 HostnameIPMapping(node.system_id, 30, {ip1.ip}, node.node_type))
1106 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)1214 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)
1107 self.assertEqual(1215 self.assertEqual(expected_subnet, mappings)
1108 mappings, {
1109 node.fqdn: HostnameIPMapping(
1110 node.system_id, 30, {ip1.ip}, node.node_type),
1111 name2: HostnameIPMapping(None, 30, {ip2.ip}, None)})
11121216
1113 def test_node_glue_correctly_generated(self):1217 def test_node_glue_correctly_generated(self):
1114 # Given node "foo.bar.com" and a "foo.bar.com" domain (in addition to1218 # Given node "foo.bar.com" and a "foo.bar.com" domain (in addition to
@@ -1131,18 +1235,17 @@
1131 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(parent)1235 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(parent)
1132 self.expectThat(mappings, HasLength(1))1236 self.expectThat(mappings, HasLength(1))
1133 self.assertEqual(1237 self.assertEqual(
1134 mappings.get(node.fqdn),1238 HostnameIPMapping(node.system_id, 30, {ip.ip}, node.node_type),
1135 HostnameIPMapping(node.system_id, 30, {ip.ip}, node.node_type))1239 mappings.get(node.fqdn))
1136 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain)1240 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain)
1137 self.expectThat(mappings, HasLength(1))1241 self.expectThat(mappings, HasLength(1))
1138 self.assertEqual(1242 self.assertEqual(
1139 mappings.get(node.fqdn),1243 HostnameIPMapping(node.system_id, 30, {ip.ip}, node.node_type),
1140 HostnameIPMapping(node.system_id, 30, {ip.ip}, node.node_type))1244 mappings.get(node.fqdn))
1141 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)1245 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)
1142 self.assertEqual(1246 self.assertEqual({
1143 mappings, {1247 node.fqdn: HostnameIPMapping(
1144 node.fqdn: HostnameIPMapping(1248 node.system_id, 30, {ip.ip}, node.node_type)}, mappings)
1145 node.system_id, 30, {ip.ip}, node.node_type)})
11461249
1147 def test_dnsrr_glue_correctly_generated(self):1250 def test_dnsrr_glue_correctly_generated(self):
1148 # Given DNSResource "foo.bar.com" and a "foo.bar.com" domain (in1251 # Given DNSResource "foo.bar.com" and a "foo.bar.com" domain (in
@@ -1163,18 +1266,16 @@
1163 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(parent)1266 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(parent)
1164 self.expectThat(mappings, HasLength(1))1267 self.expectThat(mappings, HasLength(1))
1165 self.assertEqual(1268 self.assertEqual(
1166 mappings.get(dnsrr.fqdn),1269 HostnameIPMapping(None, 30, {ip.ip}, None),
1167 HostnameIPMapping(None, 30, {ip.ip}, None))1270 mappings.get(dnsrr.fqdn))
1168 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain)1271 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(domain)
1169 self.expectThat(mappings, HasLength(1))1272 self.expectThat(mappings, HasLength(1))
1170 self.assertEqual(1273 self.assertEqual(
1171 mappings.get(dnsrr.fqdn),1274 HostnameIPMapping(None, 30, {ip.ip}, None),
1172 HostnameIPMapping(None, 30, {ip.ip}, None))1275 mappings.get(dnsrr.fqdn))
1173 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)1276 mappings = StaticIPAddress.objects.get_hostname_ip_mapping(subnet)
1174 self.assertEqual(1277 self.assertEqual({
1175 mappings, {1278 dnsrr.fqdn: HostnameIPMapping(None, 30, {ip.ip}, None)}, mappings)
1176 dnsrr.fqdn: HostnameIPMapping(
1177 None, 30, {ip.ip}, None)})
11781279
11791280
1180class TestRenderJSON(MAASServerTestCase):1281class TestRenderJSON(MAASServerTestCase):