Merge ~bjornt/maas:bug-1988229-dhcp-snippet-relay into maas:master

Proposed by Björn Tillenius
Status: Merged
Approved by: Björn Tillenius
Approved revision: ae560acae5628832e7f855c69177add56ac7f357
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~bjornt/maas:bug-1988229-dhcp-snippet-relay
Merge into: maas:master
Diff against target: 266 lines (+132/-34)
6 files modified
src/maasserver/dhcp.py (+15/-13)
src/maasserver/models/dhcpsnippet.py (+4/-0)
src/maasserver/models/node.py (+10/-12)
src/maasserver/models/subnet.py (+6/-8)
src/maasserver/models/tests/test_dhcpsnippet.py (+14/-0)
src/maasserver/tests/test_dhcp.py (+83/-1)
Reviewer Review Type Date Requested Status
Alberto Donato (community) Approve
MAAS Lander Approve
Review via email: mp+432311@code.launchpad.net

Commit message

LP #1988229: dhcp snippet create fails when dhcp subnet is relayed regression

Extract logic to make it easier to test, and make use of get_dhcp_vlan, which
knows about dhcp relaying.

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

UNIT TESTS
-b bug-1988229-dhcp-snippet-relay lp:~bjornt/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 1b2b5b2b54024701278262d834b6d2eb42e74ae8

review: Approve
Revision history for this message
Alberto Donato (ack) wrote :

+1

review: Approve
Revision history for this message
Björn Tillenius (bjornt) :
ae560ac... by Björn Tillenius

Rename parameter.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/dhcp.py b/src/maasserver/dhcp.py
index ccbe8f3..32ad98a 100644
--- a/src/maasserver/dhcp.py
+++ b/src/maasserver/dhcp.py
@@ -977,6 +977,13 @@ def get_racks_by_subnet(subnet):
977 return racks977 return racks
978978
979979
980def _get_dhcp_rackcontrollers(dhcp_snippet):
981 if dhcp_snippet.subnet is not None:
982 return get_racks_by_subnet(dhcp_snippet.subnet)
983 elif dhcp_snippet.node is not None:
984 return dhcp_snippet.node.get_boot_rack_controllers()
985
986
980def validate_dhcp_config(test_dhcp_snippet=None):987def validate_dhcp_config(test_dhcp_snippet=None):
981 """Validate a DHCPD config with uncommitted values.988 """Validate a DHCPD config with uncommitted values.
982989
@@ -987,9 +994,6 @@ def validate_dhcp_config(test_dhcp_snippet=None):
987 :param test_dhcp_snippet: A DHCPSnippet which has not yet been committed to994 :param test_dhcp_snippet: A DHCPSnippet which has not yet been committed to
988 the database and needs to be validated.995 the database and needs to be validated.
989 """996 """
990 # XXX ltrager 2016-03-28 - This only tests the existing config with new
991 # DHCPSnippets but could be expanded to test changes to the config(e.g
992 # subnets, omapi_key, interfaces, etc) before they are commited.
993997
994 def find_connected_rack(racks):998 def find_connected_rack(racks):
995 connected_racks = [client.ident for client in getAllClients()]999 connected_racks = [client.ident for client in getAllClients()]
@@ -1006,17 +1010,15 @@ def validate_dhcp_config(test_dhcp_snippet=None):
1006 "no available rack controller connected."1010 "no available rack controller connected."
1007 )1011 )
10081012
1009 rack_controller = None1013 # XXX ltrager 2016-03-28 - This only tests the existing config with new
1014 # DHCPSnippets but could be expanded to test changes to the config(e.g
1015 # subnets, omapi_key, interfaces, etc) before they are commited.
1010 # Test on the rack controller where the DHCPSnippet will be used1016 # Test on the rack controller where the DHCPSnippet will be used
1011 if test_dhcp_snippet is not None:1017 rack_controller = None
1012 if test_dhcp_snippet.subnet is not None:1018 if test_dhcp_snippet is not None and not test_dhcp_snippet.is_global:
1013 rack_controller = find_connected_rack(1019 rack_controller = find_connected_rack(
1014 get_racks_by_subnet(test_dhcp_snippet.subnet)1020 _get_dhcp_rackcontrollers(test_dhcp_snippet)
1015 )1021 )
1016 elif test_dhcp_snippet.node is not None:
1017 rack_controller = find_connected_rack(
1018 test_dhcp_snippet.node.get_boot_rack_controllers()
1019 )
1020 # If no rack controller is linked to the DHCPSnippet its a global DHCP1022 # If no rack controller is linked to the DHCPSnippet its a global DHCP
1021 # snippet which we can test anywhere.1023 # snippet which we can test anywhere.
1022 if rack_controller is None:1024 if rack_controller is None:
diff --git a/src/maasserver/models/dhcpsnippet.py b/src/maasserver/models/dhcpsnippet.py
index 7a401d7..054ccce 100644
--- a/src/maasserver/models/dhcpsnippet.py
+++ b/src/maasserver/models/dhcpsnippet.py
@@ -93,6 +93,10 @@ class DHCPSnippet(CleanSave, TimestampedModel):
93 def __str__(self):93 def __str__(self):
94 return self.name94 return self.name
9595
96 @property
97 def is_global(self):
98 return self.node_id is None and self.subnet_id is None
99
96 def clean(self, *args, **kwargs):100 def clean(self, *args, **kwargs):
97 super().clean(*args, **kwargs)101 super().clean(*args, **kwargs)
98 if self.node is not None and self.subnet is not None:102 if self.node is not None and self.subnet is not None:
diff --git a/src/maasserver/models/node.py b/src/maasserver/models/node.py
index 06e80f8..ba2f710 100644
--- a/src/maasserver/models/node.py
+++ b/src/maasserver/models/node.py
@@ -130,7 +130,7 @@ from maasserver.models.physicalblockdevice import PhysicalBlockDevice
130from maasserver.models.resourcepool import ResourcePool130from maasserver.models.resourcepool import ResourcePool
131from maasserver.models.service import Service131from maasserver.models.service import Service
132from maasserver.models.staticipaddress import StaticIPAddress132from maasserver.models.staticipaddress import StaticIPAddress
133from maasserver.models.subnet import Subnet133from maasserver.models.subnet import get_dhcp_vlan, Subnet
134from maasserver.models.tag import Tag134from maasserver.models.tag import Tag
135from maasserver.models.timestampedmodel import now, TimestampedModel135from maasserver.models.timestampedmodel import now, TimestampedModel
136from maasserver.models.vlan import VLAN136from maasserver.models.vlan import VLAN
@@ -5360,18 +5360,16 @@ class Node(CleanSave, TimestampedModel):
5360 def get_boot_rack_controllers(self):5360 def get_boot_rack_controllers(self):
5361 """Return the `RackController` that this node will boot from."""5361 """Return the `RackController` that this node will boot from."""
5362 boot_interface = self.get_boot_interface()5362 boot_interface = self.get_boot_interface()
5363 if (5363 if boot_interface is None:
5364 boot_interface is None
5365 or boot_interface.vlan is None
5366 or not boot_interface.vlan.dhcp_on
5367 ):
5368 return []5364 return []
5369 else:5365
5370 racks = [5366 boot_vlan = get_dhcp_vlan(boot_interface.vlan)
5371 boot_interface.vlan.primary_rack,5367 if boot_vlan is None:
5372 boot_interface.vlan.secondary_rack,5368 return []
5373 ]5369 racks = [boot_vlan.primary_rack]
5374 return [rack for rack in racks if rack is not None]5370 if boot_vlan.secondary_rack:
5371 racks.append(boot_vlan.secondary_rack)
5372 return racks
53755373
5376 def get_extra_macs(self):5374 def get_extra_macs(self):
5377 """Get the MACs other that the one the node booted from."""5375 """Get the MACs other that the one the node booted from."""
diff --git a/src/maasserver/models/subnet.py b/src/maasserver/models/subnet.py
index 924aefa..870d4eb 100644
--- a/src/maasserver/models/subnet.py
+++ b/src/maasserver/models/subnet.py
@@ -1065,14 +1065,10 @@ def get_allocated_ips(subnets):
1065 yield subnet, mapping[subnet.id]1065 yield subnet, mapping[subnet.id]
10661066
10671067
1068def get_dhcp_vlan(subnet):1068def get_dhcp_vlan(vlan):
1069 if subnet is None:1069 if vlan is None:
1070 return None1070 return None
1071 dhcp_vlan = (1071 dhcp_vlan = vlan if vlan.relay_vlan_id is None else vlan.relay_vlan
1072 subnet.vlan
1073 if subnet.vlan.relay_vlan_id is None
1074 else subnet.vlan.relay_vlan
1075 )
1076 if not dhcp_vlan.dhcp_on or dhcp_vlan.primary_rack is None:1072 if not dhcp_vlan.dhcp_on or dhcp_vlan.primary_rack is None:
1077 return None1073 return None
1078 return dhcp_vlan1074 return dhcp_vlan
@@ -1104,7 +1100,9 @@ def get_boot_rackcontroller_ips(subnet):
11041100
1105 from maasserver.models.staticipaddress import StaticIPAddress1101 from maasserver.models.staticipaddress import StaticIPAddress
11061102
1107 dhcp_vlan = get_dhcp_vlan(subnet)1103 dhcp_vlan = None
1104 if subnet is not None:
1105 dhcp_vlan = get_dhcp_vlan(subnet.vlan)
1108 if dhcp_vlan is None:1106 if dhcp_vlan is None:
1109 return []1107 return []
11101108
diff --git a/src/maasserver/models/tests/test_dhcpsnippet.py b/src/maasserver/models/tests/test_dhcpsnippet.py
index acefc80..465f445 100644
--- a/src/maasserver/models/tests/test_dhcpsnippet.py
+++ b/src/maasserver/models/tests/test_dhcpsnippet.py
@@ -138,3 +138,17 @@ class TestDHCPSnippet(MAASServerTestCase):
138 VersionedTextFile.objects.get,138 VersionedTextFile.objects.get,
139 id=i,139 id=i,
140 )140 )
141
142 def test_is_global(self):
143 snippet = factory.make_DHCPSnippet(subnet=None, node=None)
144 self.assertTrue(snippet.is_global)
145
146 def test_is_global_node(self):
147 node = factory.make_Machine()
148 snippet = factory.make_DHCPSnippet(subnet=None, node=node)
149 self.assertFalse(snippet.is_global)
150
151 def test_is_global_subnet(self):
152 subnet = factory.make_Subnet()
153 snippet = factory.make_DHCPSnippet(subnet=subnet, node=None)
154 self.assertFalse(snippet.is_global)
diff --git a/src/maasserver/tests/test_dhcp.py b/src/maasserver/tests/test_dhcp.py
index 58bee72..e9d0cfa 100644
--- a/src/maasserver/tests/test_dhcp.py
+++ b/src/maasserver/tests/test_dhcp.py
@@ -25,7 +25,7 @@ from twisted.internet.threads import deferToThread
2525
26from maasserver import dhcp26from maasserver import dhcp
27from maasserver import server_address as server_address_module27from maasserver import server_address as server_address_module
28from maasserver.dhcp import get_default_dns_servers28from maasserver.dhcp import _get_dhcp_rackcontrollers, get_default_dns_servers
29from maasserver.enum import INTERFACE_TYPE, IPADDRESS_TYPE, SERVICE_STATUS29from maasserver.enum import INTERFACE_TYPE, IPADDRESS_TYPE, SERVICE_STATUS
30from maasserver.models import (30from maasserver.models import (
31 Config,31 Config,
@@ -2923,6 +2923,88 @@ class TestConfigureDHCP(MAASTransactionServerTestCase):
2923 yield deferToDatabase(service_status_updated)2923 yield deferToDatabase(service_status_updated)
29242924
29252925
2926class TestGetDHCPRackcontroller(MAASTransactionServerTestCase):
2927 def create_dhcp_vlan(self, primary_address, secondary_adress=None):
2928 dhcp_vlan = factory.make_VLAN()
2929 dhcp_subnet = factory.make_Subnet(
2930 vlan=dhcp_vlan, cidr=IPNetwork(primary_address).cidr
2931 )
2932 primary_rack = factory.make_rack_with_interfaces(
2933 eth0=[primary_address]
2934 )
2935 secondary_rack = None
2936 if secondary_adress is not None:
2937 secondary_rack = factory.make_rack_with_interfaces(
2938 eth0=[secondary_adress]
2939 )
2940 dhcp_vlan.dhcp_on = True
2941 dhcp_vlan.primary_rack = primary_rack
2942 dhcp_vlan.secondary_rack = secondary_rack
2943 dhcp_vlan.save()
2944 return dhcp_subnet
2945
2946 def test_subnet(self):
2947 subnet = self.create_dhcp_vlan("10.10.10.2/24")
2948 self.create_dhcp_vlan("10.10.20.2/24")
2949 snippet = factory.make_DHCPSnippet(subnet=subnet, enabled=True)
2950 self.assertCountEqual(
2951 [subnet.vlan.primary_rack], _get_dhcp_rackcontrollers(snippet)
2952 )
2953
2954 def test_subnet_includes_secondary(self):
2955 subnet = self.create_dhcp_vlan("10.10.10.2/24", "10.10.10.3/24")
2956 self.create_dhcp_vlan("10.10.20.0/24")
2957 snippet = factory.make_DHCPSnippet(subnet=subnet, enabled=True)
2958 self.assertCountEqual(
2959 [subnet.vlan.primary_rack, subnet.vlan.secondary_rack],
2960 _get_dhcp_rackcontrollers(snippet),
2961 )
2962
2963 def test_subnet_relay(self):
2964 dhcp_subnet = self.create_dhcp_vlan("10.10.10.2/24")
2965 self.create_dhcp_vlan("10.10.20.2/24")
2966 relay_subnet = factory.make_Subnet(cidr="10.10.30.0/24")
2967 relay_subnet.vlan.relay_vlan = dhcp_subnet.vlan
2968 relay_subnet.vlan.save()
2969 snippet = factory.make_DHCPSnippet(subnet=relay_subnet, enabled=True)
2970 self.assertCountEqual(
2971 [dhcp_subnet.vlan.primary_rack], _get_dhcp_rackcontrollers(snippet)
2972 )
2973
2974 def test_node(self):
2975 subnet = self.create_dhcp_vlan("10.10.10.2/24")
2976 self.create_dhcp_vlan("10.10.20.0/24")
2977 node = factory.make_Machine_with_Interface_on_Subnet(subnet=subnet)
2978 snippet = factory.make_DHCPSnippet(node=node, enabled=True)
2979 self.assertCountEqual(
2980 [subnet.vlan.primary_rack], _get_dhcp_rackcontrollers(snippet)
2981 )
2982
2983 def test_node_includes_secondary(self):
2984 subnet = self.create_dhcp_vlan("10.10.10.2/24", "10.10.10.3/24")
2985 self.create_dhcp_vlan("10.10.20.0/24")
2986 node = factory.make_Machine_with_Interface_on_Subnet(subnet=subnet)
2987 snippet = factory.make_DHCPSnippet(node=node, enabled=True)
2988 self.assertCountEqual(
2989 [subnet.vlan.primary_rack, subnet.vlan.secondary_rack],
2990 _get_dhcp_rackcontrollers(snippet),
2991 )
2992
2993 def test_node_relay(self):
2994 dhcp_subnet = self.create_dhcp_vlan("10.10.10.2/24")
2995 self.create_dhcp_vlan("10.10.20.2/24")
2996 relay_subnet = factory.make_Subnet(cidr="10.10.30.0/24")
2997 relay_subnet.vlan.relay_vlan = dhcp_subnet.vlan
2998 relay_subnet.vlan.save()
2999 node = factory.make_Machine_with_Interface_on_Subnet(
3000 subnet=relay_subnet
3001 )
3002 snippet = factory.make_DHCPSnippet(node=node, enabled=True)
3003 self.assertCountEqual(
3004 [dhcp_subnet.vlan.primary_rack], _get_dhcp_rackcontrollers(snippet)
3005 )
3006
3007
2926class TestValidateDHCPConfig(MAASTransactionServerTestCase):3008class TestValidateDHCPConfig(MAASTransactionServerTestCase):
2927 """Tests for `validate_dhcp_config`."""3009 """Tests for `validate_dhcp_config`."""
29283010

Subscribers

People subscribed via source and target branches