Merge ~ltrager/maas:disable_boot_architectures_form into maas:master

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: 70aed55263f3731d29a17acf7f7d6ab8191950d3
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:disable_boot_architectures_form
Merge into: maas:master
Prerequisite: ~ltrager/maas:disable_boot_architectures_model
Diff against target: 223 lines (+169/-2)
2 files modified
src/maasserver/forms/subnet.py (+37/-1)
src/maasserver/forms/tests/test_subnet.py (+132/-1)
Reviewer Review Type Date Requested Status
MAAS Lander Needs Fixing
Alberto Donato (community) Approve
Review via email: mp+401920@code.launchpad.net

Commit message

Add Subnet form support for disable_boot_architectures

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

UNIT TESTS
-b disable_boot_architectures_form lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/9883/console
COMMIT: 2184f66ed7c881293b9318e9eae17713e1cef3e4

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

+1

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

UNIT TESTS
-b disable_boot_architectures_form lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/9902/console
COMMIT: 748971315f8ec161e147ab3650a2ccf55287f224

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

LANDING
-b disable_boot_architectures_form lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED BUILD
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/9924/consoleText

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

UNIT TESTS
-b disable_boot_architectures_form lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/9925/console
COMMIT: 921d84a90b08935b23222004d0b5151f5cfb1e81

review: Needs Fixing
70aed55... by Lee Trager

Fix failing test

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/forms/subnet.py b/src/maasserver/forms/subnet.py
2index fadeec9..62e1c0b 100644
3--- a/src/maasserver/forms/subnet.py
4+++ b/src/maasserver/forms/subnet.py
5@@ -1,4 +1,4 @@
6-# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
7+# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 """Subnet form."""
11@@ -16,6 +16,7 @@ from maasserver.models.subnet import Subnet
12 from maasserver.models.vlan import VLAN
13 from maasserver.utils.forms import set_form_error
14 from maasserver.utils.orm import get_one
15+from provisioningserver.boot import BootMethodRegistry
16
17
18 class SubnetForm(MAASModelForm):
19@@ -53,6 +54,7 @@ class SubnetForm(MAASModelForm):
20 "allow_dns",
21 "allow_proxy",
22 "managed",
23+ "disabled_boot_architectures",
24 )
25
26 def __init__(self, *args, **kwargs):
27@@ -82,6 +84,7 @@ class SubnetForm(MAASModelForm):
28 cleaned_data["dns_servers"] = self.data.getlist("dns_servers")
29 cleaned_data = self._clean_name(cleaned_data)
30 cleaned_data = self._clean_dns_servers(cleaned_data)
31+ cleaned_data = self._clean_disabled_boot_architectures(cleaned_data)
32 if self.instance.id is None:
33 # We only allow the helpers when creating. When updating we require
34 # the VLAN specifically. This is because we cannot make a correct
35@@ -172,3 +175,36 @@ class SubnetForm(MAASModelForm):
36 clean_dns_servers += ip_list_cleaned.split(" ")
37 cleaned_data["dns_servers"] = clean_dns_servers
38 return cleaned_data
39+
40+ def _clean_disabled_boot_architectures(self, cleaned_data):
41+ disabled_boot_architectures = cleaned_data.get(
42+ "disabled_boot_architectures"
43+ )
44+ if disabled_boot_architectures is None:
45+ return cleaned_data
46+ disabled_arches = []
47+ for disabled_arch in disabled_boot_architectures:
48+ disabled_arches += disabled_arch.split(" ")
49+ cleaned_arches = set()
50+ octet_to_boot_method = {
51+ boot_method.arch_octet: boot_method
52+ for _, boot_method in BootMethodRegistry
53+ if boot_method.arch_octet
54+ }
55+ for disabled_arch in disabled_arches:
56+ boot_method = BootMethodRegistry.get_item(
57+ disabled_arch,
58+ octet_to_boot_method.get(disabled_arch.replace("0x", "00:")),
59+ )
60+ if boot_method is None or (
61+ not boot_method.arch_octet and not boot_method.path_prefix_http
62+ ):
63+ set_form_error(
64+ self,
65+ "disabled_boot_architectures",
66+ f"Unknown boot architecture {disabled_arch}",
67+ )
68+ else:
69+ cleaned_arches.add(boot_method.name)
70+ cleaned_data["disabled_boot_architectures"] = list(cleaned_arches)
71+ return cleaned_data
72diff --git a/src/maasserver/forms/tests/test_subnet.py b/src/maasserver/forms/tests/test_subnet.py
73index 0d5228e..cfb2b1a 100644
74--- a/src/maasserver/forms/tests/test_subnet.py
75+++ b/src/maasserver/forms/tests/test_subnet.py
76@@ -1,4 +1,4 @@
77-# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
78+# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
79 # GNU Affero General Public License version 3 (see the file LICENSE).
80
81 """Tests for Subnet forms."""
82@@ -13,6 +13,7 @@ from maasserver.models.fabric import Fabric
83 from maasserver.testing.factory import factory
84 from maasserver.testing.testcase import MAASServerTestCase
85 from maasserver.utils.orm import reload_object
86+from provisioningserver.boot import BootMethodRegistry
87
88
89 class TestSubnetForm(MAASServerTestCase):
90@@ -369,3 +370,133 @@ class TestSubnetForm(MAASServerTestCase):
91 form.save()
92 subnet = reload_object(subnet)
93 self.assertEqual(dns_servers, subnet.dns_servers)
94+
95+ def test_clean_disabled_boot_arches_name_comma_seperated_list(self):
96+ subnet = factory.make_Subnet()
97+ disabled_arches = random.sample(
98+ [
99+ boot_method.name
100+ for _, boot_method in BootMethodRegistry
101+ if boot_method.arch_octet or boot_method.path_prefix_http
102+ ],
103+ 3,
104+ )
105+
106+ form = SubnetForm(
107+ instance=subnet,
108+ data={"disabled_boot_architectures": ",".join(disabled_arches)},
109+ )
110+ self.assertTrue(form.is_valid(), dict(form.errors))
111+ form.save()
112+ subnet = reload_object(subnet)
113+ self.assertEqual(
114+ sorted(disabled_arches), sorted(subnet.disabled_boot_architectures)
115+ )
116+
117+ def test_clean_disabled_boot_arches_name_space_seperated_list(self):
118+ subnet = factory.make_Subnet()
119+ disabled_arches = random.sample(
120+ [
121+ boot_method.name
122+ for _, boot_method in BootMethodRegistry
123+ if boot_method.arch_octet or boot_method.path_prefix_http
124+ ],
125+ 3,
126+ )
127+
128+ form = SubnetForm(
129+ instance=subnet,
130+ data={"disabled_boot_architectures": " ".join(disabled_arches)},
131+ )
132+ self.assertTrue(form.is_valid(), dict(form.errors))
133+ form.save()
134+ subnet = reload_object(subnet)
135+ self.assertEqual(
136+ sorted(disabled_arches), sorted(subnet.disabled_boot_architectures)
137+ )
138+
139+ def test_clean_disabled_boot_arches_octet(self):
140+ subnet = factory.make_Subnet()
141+ disabled_arches = random.sample(
142+ [
143+ boot_method
144+ for _, boot_method in BootMethodRegistry
145+ if boot_method.arch_octet or boot_method.path_prefix_http
146+ ],
147+ 3,
148+ )
149+ form = SubnetForm(
150+ instance=subnet,
151+ data={
152+ "disabled_boot_architectures": ",".join(
153+ [bm.arch_octet for bm in disabled_arches]
154+ )
155+ },
156+ )
157+ self.assertTrue(form.is_valid(), dict(form.errors))
158+ form.save()
159+ subnet = reload_object(subnet)
160+ self.assertEqual(
161+ sorted([bm.name for bm in disabled_arches]),
162+ sorted(subnet.disabled_boot_architectures),
163+ )
164+
165+ def test_clean_disabled_boot_arches_hex(self):
166+ subnet = factory.make_Subnet()
167+ disabled_arches = random.sample(
168+ [
169+ boot_method
170+ for _, boot_method in BootMethodRegistry
171+ if boot_method.arch_octet or boot_method.path_prefix_http
172+ ],
173+ 3,
174+ )
175+ form = SubnetForm(
176+ instance=subnet,
177+ data={
178+ "disabled_boot_architectures": ",".join(
179+ [
180+ bm.arch_octet.replace("00:", "0x")
181+ for bm in disabled_arches
182+ ]
183+ )
184+ },
185+ )
186+ self.assertTrue(form.is_valid(), dict(form.errors))
187+ form.save()
188+ subnet = reload_object(subnet)
189+ self.assertEqual(
190+ sorted([bm.name for bm in disabled_arches]),
191+ sorted(subnet.disabled_boot_architectures),
192+ )
193+
194+ def test_clean_disabled_boot_arches_cannot_disable_fake_boot_arch(self):
195+ # The Windows boot loader responds to bootloader configuration requests
196+ # but isc-dhcpd is not configured to respond to a boot octet nor a
197+ # user-class. Thus it is unable to be disabled.
198+ subnet = factory.make_Subnet(disabled_boot_architectures=[])
199+ choices = [
200+ boot_method.name
201+ for _, boot_method in BootMethodRegistry
202+ if not boot_method.arch_octet and not boot_method.path_prefix_http
203+ ]
204+
205+ form = SubnetForm(
206+ instance=subnet,
207+ data={"disabled_boot_architectures": random.choice(choices)},
208+ )
209+ self.assertFalse(form.is_valid())
210+ subnet = reload_object(subnet)
211+ self.assertEqual([], subnet.disabled_boot_architectures)
212+
213+ def test_clean_disabled_detects_invalid_arch(self):
214+ subnet = factory.make_Subnet(disabled_boot_architectures=[])
215+ form = SubnetForm(
216+ instance=subnet,
217+ data={
218+ "disabled_boot_architectures": factory.make_name("boot_arch")
219+ },
220+ )
221+ self.assertFalse(form.is_valid())
222+ subnet = reload_object(subnet)
223+ self.assertEqual([], subnet.disabled_boot_architectures)

Subscribers

People subscribed via source and target branches