Merge ~ack/maas:kernel-options-all-tags into maas:master

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: 75f57a97f099d0ea3e78a95375f041404ab17772
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ack/maas:kernel-options-all-tags
Merge into: maas:master
Diff against target: 299 lines (+57/-95)
9 files modified
src/maasserver/api/examples/tags.json (+2/-2)
src/maasserver/api/tags.py (+3/-3)
src/maasserver/migrations/maasserver/0230_tag_kernel_opts_blank_instead_of_null.py (+19/-0)
src/maasserver/models/node.py (+10/-20)
src/maasserver/models/tag.py (+1/-1)
src/maasserver/models/tests/test_node.py (+16/-49)
src/maasserver/models/tests/test_tag.py (+1/-1)
src/maasserver/rpc/boot.py (+4/-18)
src/maasserver/testing/factory.py (+1/-1)
Reviewer Review Type Date Requested Status
Adam Collard (community) Approve
MAAS Lander Needs Fixing
Review via email: mp+399201@code.launchpad.net

Commit message

combine kernel commandline options node from all associated tags

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

UNIT TESTS
-b kernel-options-all-tags lp:~ack/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/9414/console
COMMIT: d055378c902d55b5f8901ea1c5391bd66aee5983

review: Needs Fixing
Revision history for this message
Adam Collard (adam-collard) wrote :

Make sure we document the order in which we combine kernel tags and nod towards that being important if the options aren't complete.

review: Approve

There was an error fetching revisions from git servers. Please try again in a few minutes. If the problem persists, contact Launchpad support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/api/examples/tags.json b/src/maasserver/api/examples/tags.json
2index 98804ed..504001d 100644
3--- a/src/maasserver/api/examples/tags.json
4+++ b/src/maasserver/api/examples/tags.json
5@@ -4,7 +4,7 @@
6 "name": "virtual",
7 "definition": "",
8 "comment": "",
9- "kernel_opts": null,
10+ "kernel_opts": "",
11 "resource_uri": "/MAAS/api/2.0/tags/virtual/"
12 }
13 ],
14@@ -12,7 +12,7 @@
15 "name": "virtual",
16 "definition": "",
17 "comment": "",
18- "kernel_opts": null,
19+ "kernel_opts": "",
20 "resource_uri": "/MAAS/api/2.0/tags/virtual/"
21 },
22 "get-devices-by-tag": [
23diff --git a/src/maasserver/api/tags.py b/src/maasserver/api/tags.py
24index 42c8466..b4ce8eb 100644
25--- a/src/maasserver/api/tags.py
26+++ b/src/maasserver/api/tags.py
27@@ -420,9 +420,9 @@ class TagsHandler(OperationsHandler):
28 @param (string) "kernel_opts" [required=false] Nodes associated
29 with this tag will add this string to their kernel options
30 when booting. The value overrides the global ``kernel_opts``
31- setting. If more than one tag is associated with a node, the
32- one with the lower alphabetical name will be picked. For example,
33- ``01-my-tag`` will be chosen instead of ``99-tag-name``.
34+ setting. If more than one tag is associated with a node, command
35+ line will be concatenated from all associated tags, in alphabetic
36+ tag name order.
37 @param-example "kernel_opts"
38 nouveau.noaccel=1
39
40diff --git a/src/maasserver/migrations/maasserver/0230_tag_kernel_opts_blank_instead_of_null.py b/src/maasserver/migrations/maasserver/0230_tag_kernel_opts_blank_instead_of_null.py
41new file mode 100644
42index 0000000..397b945
43--- /dev/null
44+++ b/src/maasserver/migrations/maasserver/0230_tag_kernel_opts_blank_instead_of_null.py
45@@ -0,0 +1,19 @@
46+# Generated by Django 2.2.12 on 2021-03-05 10:56
47+
48+from django.db import migrations, models
49+
50+
51+class Migration(migrations.Migration):
52+
53+ dependencies = [
54+ ("maasserver", "0229_drop_physicalblockdevice_storage_pool"),
55+ ]
56+
57+ operations = [
58+ migrations.AlterField(
59+ model_name="tag",
60+ name="kernel_opts",
61+ field=models.TextField(blank=True, default=""),
62+ preserve_default=False,
63+ ),
64+ ]
65diff --git a/src/maasserver/models/node.py b/src/maasserver/models/node.py
66index a7c41d5..641e2d8 100644
67--- a/src/maasserver/models/node.py
68+++ b/src/maasserver/models/node.py
69@@ -3024,26 +3024,16 @@ class Node(CleanSave, TimestampedModel):
70 raise UnknownPowerType("Node power type is unconfigured")
71 return self.bmc.power_type
72
73- def get_effective_kernel_options(self, default_kernel_opts=undefined):
74- """Determine any special kernel parameters for this node.
75-
76- :return: (tag, kernel_options)
77- tag is a Tag object or None. If None, the kernel_options came from
78- the global setting.
79- kernel_options, a string indicating extra kernel_options that
80- should be used when booting this node. May be None if no tags match
81- and no global setting has been configured.
82- """
83- # First, see if there are any tags associated with this node that has a
84- # custom kernel parameter
85- tags = self.tags.filter(kernel_opts__isnull=False)
86- tags = tags.order_by("name")
87- for tag in tags:
88- if tag.kernel_opts != "":
89- return tag, tag.kernel_opts
90- if default_kernel_opts is undefined:
91- default_kernel_opts = Config.objects.get_config("kernel_opts")
92- return None, default_kernel_opts
93+ def get_effective_kernel_options(self, default_kernel_opts=""):
94+ """Return a string with kernel commandline."""
95+ options = (
96+ self.tags.exclude(kernel_opts="")
97+ .order_by("name")
98+ .values_list("kernel_opts", flat=True)
99+ )
100+ if options:
101+ return " ".join(options)
102+ return default_kernel_opts or ""
103
104 def get_osystem(self, default=undefined):
105 """Return the operating system to install that node."""
106diff --git a/src/maasserver/models/tag.py b/src/maasserver/models/tag.py
107index 0a49b99..5806b3d 100644
108--- a/src/maasserver/models/tag.py
109+++ b/src/maasserver/models/tag.py
110@@ -71,7 +71,7 @@ class Tag(CleanSave, TimestampedModel):
111 )
112 definition = TextField(blank=True)
113 comment = TextField(blank=True)
114- kernel_opts = TextField(blank=True, null=True)
115+ kernel_opts = TextField(blank=True)
116
117 objects = TagManager()
118
119diff --git a/src/maasserver/models/tests/test_node.py b/src/maasserver/models/tests/test_node.py
120index d77a37d..954740f 100644
121--- a/src/maasserver/models/tests/test_node.py
122+++ b/src/maasserver/models/tests/test_node.py
123@@ -1818,24 +1818,16 @@ class TestNode(MAASServerTestCase):
124
125 def test_get_effective_kernel_options_with_nothing_set(self):
126 node = factory.make_Node()
127- self.assertEqual((None, None), node.get_effective_kernel_options())
128-
129- def test_get_effective_kernel_options_sees_global_config(self):
130- node = factory.make_Node()
131- kernel_opts = factory.make_string()
132- Config.objects.set_config("kernel_opts", kernel_opts)
133- self.assertEqual(
134- (None, kernel_opts), node.get_effective_kernel_options()
135- )
136+ self.assertEqual(node.get_effective_kernel_options(), "")
137
138 def test_get_effective_kernel_options_not_confused_by_None_opts(self):
139 node = factory.make_Node()
140 tag = factory.make_Tag()
141 node.tags.add(tag)
142 kernel_opts = factory.make_string()
143- Config.objects.set_config("kernel_opts", kernel_opts)
144 self.assertEqual(
145- (None, kernel_opts), node.get_effective_kernel_options()
146+ node.get_effective_kernel_options(default_kernel_opts=kernel_opts),
147+ kernel_opts,
148 )
149
150 def test_get_effective_kernel_options_not_confused_by_empty_str_opts(self):
151@@ -1843,69 +1835,44 @@ class TestNode(MAASServerTestCase):
152 tag = factory.make_Tag(kernel_opts="")
153 node.tags.add(tag)
154 kernel_opts = factory.make_string()
155- Config.objects.set_config("kernel_opts", kernel_opts)
156 self.assertEqual(
157- (None, kernel_opts), node.get_effective_kernel_options()
158+ node.get_effective_kernel_options(default_kernel_opts=kernel_opts),
159+ kernel_opts,
160 )
161
162 def test_get_effective_kernel_options_multiple_tags_with_opts(self):
163- # In this scenario:
164- # global kernel_opts='fish-n-chips'
165- # tag_a kernel_opts=null
166- # tag_b kernel_opts=''
167- # tag_c kernel_opts='bacon-n-eggs'
168- # we require that 'bacon-n-eggs' is chosen as it is the first
169- # tag with a valid kernel option.
170- Config.objects.set_config("kernel_opts", "fish-n-chips")
171 node = factory.make_Node()
172 node.tags.add(factory.make_Tag("tag_a"))
173 node.tags.add(factory.make_Tag("tag_b", kernel_opts=""))
174 tag_c = factory.make_Tag("tag_c", kernel_opts="bacon-n-eggs")
175+ tag_d = factory.make_Tag("tag_d", kernel_opts="foo-bar")
176 node.tags.add(tag_c)
177-
178+ node.tags.add(tag_d)
179 self.assertEqual(
180- (tag_c, "bacon-n-eggs"), node.get_effective_kernel_options()
181+ node.get_effective_kernel_options(), "bacon-n-eggs foo-bar"
182 )
183
184 def test_get_effective_kernel_options_ignores_unassociated_tag_value(self):
185 node = factory.make_Node()
186 factory.make_Tag(kernel_opts=factory.make_string())
187- self.assertEqual((None, None), node.get_effective_kernel_options())
188+ self.assertEqual(node.get_effective_kernel_options(), "")
189
190 def test_get_effective_kernel_options_uses_tag_value(self):
191 node = factory.make_Node()
192 tag = factory.make_Tag(kernel_opts=factory.make_string())
193 node.tags.add(tag)
194- self.assertEqual(
195- (tag, tag.kernel_opts), node.get_effective_kernel_options()
196- )
197+ self.assertEqual(node.get_effective_kernel_options(), tag.kernel_opts)
198
199- def test_get_effective_kernel_options_tag_overrides_global(self):
200+ def test_get_effective_kernel_options_tag_overrides_default(self):
201 node = factory.make_Node()
202- global_opts = factory.make_string()
203- Config.objects.set_config("kernel_opts", global_opts)
204+ default_opts = factory.make_string()
205 tag = factory.make_Tag(kernel_opts=factory.make_string())
206 node.tags.add(tag)
207 self.assertEqual(
208- (tag, tag.kernel_opts), node.get_effective_kernel_options()
209- )
210-
211- def test_get_effective_kernel_options_uses_first_real_tag_value(self):
212- node = factory.make_Node()
213- # Intentionally create them in reverse order, so the default 'db' order
214- # doesn't work, and we have asserted that we sort them.
215- tag3 = factory.make_Tag(
216- factory.make_name("tag-03-"), kernel_opts=factory.make_string()
217- )
218- tag2 = factory.make_Tag(
219- factory.make_name("tag-02-"), kernel_opts=factory.make_string()
220- )
221- tag1 = factory.make_Tag(factory.make_name("tag-01-"), kernel_opts=None)
222- self.assertTrue(tag1.name < tag2.name)
223- self.assertTrue(tag2.name < tag3.name)
224- node.tags.add(tag1, tag2, tag3)
225- self.assertEqual(
226- (tag2, tag2.kernel_opts), node.get_effective_kernel_options()
227+ node.get_effective_kernel_options(
228+ default_kernel_opts=default_opts
229+ ),
230+ tag.kernel_opts,
231 )
232
233 def test_acquire(self):
234diff --git a/src/maasserver/models/tests/test_tag.py b/src/maasserver/models/tests/test_tag.py
235index 1a0666f..fdf7b58 100644
236--- a/src/maasserver/models/tests/test_tag.py
237+++ b/src/maasserver/models/tests/test_tag.py
238@@ -28,7 +28,7 @@ class TagTest(MAASServerTestCase):
239 self.assertEqual("tag-name", tag.name)
240 self.assertEqual("//node[@id=display]", tag.definition)
241 self.assertEqual("", tag.comment)
242- self.assertIs(None, tag.kernel_opts)
243+ self.assertEqual(tag.kernel_opts, "")
244 self.assertIsNot(None, tag.updated)
245 self.assertIsNot(None, tag.created)
246
247diff --git a/src/maasserver/rpc/boot.py b/src/maasserver/rpc/boot.py
248index fdd9ef7..ce7af59 100644
249--- a/src/maasserver/rpc/boot.py
250+++ b/src/maasserver/rpc/boot.py
251@@ -515,9 +515,7 @@ def get_config(
252 machine, configs, purpose
253 )
254
255- # We don't care if the kernel opts is from the global setting or a tag,
256- # just get the options
257- _, effective_kernel_opts = machine.get_effective_kernel_options(
258+ extra_kernel_opts = machine.get_effective_kernel_options(
259 default_kernel_opts=configs["kernel_opts"]
260 )
261
262@@ -527,21 +525,9 @@ def get_config(
263 driver = get_third_party_driver(machine, series=series)
264 driver_kernel_opts = driver.get("kernel_opts", "")
265
266- combined_opts = (
267- "%s %s"
268- % (
269- ""
270- if effective_kernel_opts is None
271- else effective_kernel_opts,
272- driver_kernel_opts,
273- )
274- ).strip()
275- if len(combined_opts):
276- extra_kernel_opts = combined_opts
277- else:
278- extra_kernel_opts = None
279- else:
280- extra_kernel_opts = effective_kernel_opts
281+ extra_kernel_opts += f" {driver_kernel_opts}"
282+
283+ extra_kernel_opts.strip()
284
285 kparams = BootResource.objects.get_kparams_for_node(
286 machine,
287diff --git a/src/maasserver/testing/factory.py b/src/maasserver/testing/factory.py
288index 94a156d..d5bc9ea 100644
289--- a/src/maasserver/testing/factory.py
290+++ b/src/maasserver/testing/factory.py
291@@ -1930,7 +1930,7 @@ class Factory(maastesting.factory.Factory):
292 name=None,
293 definition=None,
294 comment="",
295- kernel_opts=None,
296+ kernel_opts="",
297 created=None,
298 updated=None,
299 populate=True,

Subscribers

People subscribed via source and target branches