Merge ~adam-collard/maas:websocket-create-deployed-machine into maas:master
- Git
- lp:~adam-collard/maas
- websocket-create-deployed-machine
- Merge into master
Status: | Merged |
---|---|
Approved by: | Adam Collard |
Approved revision: | e038d4d1b1cfb3659236e242f96bc48845536fbf |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~adam-collard/maas:websocket-create-deployed-machine |
Merge into: | maas:master |
Diff against target: |
518 lines (+170/-128) 9 files modified
src/maasserver/api/machines.py (+13/-19) src/maasserver/forms/__init__.py (+20/-2) src/maasserver/forms/ephemeral.py (+2/-30) src/maasserver/forms/tests/test_ephemeral.py (+2/-58) src/maasserver/forms/tests/test_machine.py (+23/-2) src/maasserver/websockets/handlers/machine.py (+18/-10) src/maasserver/websockets/handlers/tests/test_machine.py (+28/-0) src/metadataserver/models/scriptset.py (+21/-6) src/metadataserver/models/tests/test_scriptset.py (+43/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Lander | Needs Fixing | ||
Alberto Donato (community) | Approve | ||
Review via email: mp+407385@code.launchpad.net |
Commit message
Allow creating a machine as deployed via websocket handler
Description of the change
Adam Collard (adam-collard) : | # |
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b websocket-
STATUS: SUCCESS
COMMIT: 1633be5330aca16
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b websocket-
STATUS: FAILED
LOG: http://
COMMIT: 08c2fc6141b4500
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b websocket-
STATUS: FAILED BUILD
LOG: http://
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b websocket-
STATUS: FAILED
LOG: http://
COMMIT: 6de8d707da29ec7
- e038d4d... by Adam Collard
-
Flaky test - we don't care about the order
Preview Diff
1 | diff --git a/src/maasserver/api/machines.py b/src/maasserver/api/machines.py |
2 | index fe60680..5c234f2 100644 |
3 | --- a/src/maasserver/api/machines.py |
4 | +++ b/src/maasserver/api/machines.py |
5 | @@ -71,10 +71,7 @@ from maasserver.forms import ( |
6 | MachineForm, |
7 | ) |
8 | from maasserver.forms.clone import CloneForm |
9 | -from maasserver.forms.ephemeral import ( |
10 | - CommissionForm, |
11 | - CreateScriptsForDeployedForm, |
12 | -) |
13 | +from maasserver.forms.ephemeral import CommissionForm |
14 | from maasserver.forms.filesystem import ( |
15 | MountNonStorageFilesystemForm, |
16 | UnmountNonStorageFilesystemForm, |
17 | @@ -1968,6 +1965,10 @@ class MachinesHandler(NodesHandler, PowersMixin): |
18 | time out. Machines created by administrators will be commissioned |
19 | unless set to false. |
20 | |
21 | + @param (boolean) "deployed" [required=false,formatting=true] Request |
22 | + the newly created machine to be created with status set to |
23 | + DEPLOYED. |
24 | + |
25 | @param (int) "enable_ssh" [required=false] Whether to enable SSH for |
26 | the commissioning environment using the user's SSH key(s). '1' == True, |
27 | '0' == False. |
28 | @@ -2011,21 +2012,14 @@ class MachinesHandler(NodesHandler, PowersMixin): |
29 | request.data, "deployed", default=False, validator=StringBool |
30 | ) |
31 | machine = create_machine(request) |
32 | - if request.user.is_superuser: |
33 | - if deployed: |
34 | - form = CreateScriptsForDeployedForm( |
35 | - instance=machine, |
36 | - data=request.data, |
37 | - ) |
38 | - form.save() |
39 | - elif commission: |
40 | - form = CommissionForm( |
41 | - instance=machine, user=request.user, data=request.data |
42 | - ) |
43 | - # Silently ignore errors to prevent 500 errors. The commissioning |
44 | - # callbacks have their own logging. This fixes LP:1600328. |
45 | - if form.is_valid(): |
46 | - machine = form.save() |
47 | + if request.user.is_superuser and commission and not deployed: |
48 | + form = CommissionForm( |
49 | + instance=machine, user=request.user, data=request.data |
50 | + ) |
51 | + # Silently ignore errors to prevent 500 errors. The commissioning |
52 | + # callbacks have their own logging. This fixes LP:1600328. |
53 | + if form.is_valid(): |
54 | + machine = form.save() |
55 | |
56 | return machine |
57 | |
58 | diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py |
59 | index d4d35df..f5feb77 100644 |
60 | --- a/src/maasserver/forms/__init__.py |
61 | +++ b/src/maasserver/forms/__init__.py |
62 | @@ -748,6 +748,7 @@ class MachineForm(NodeForm): |
63 | "architecture", choices |
64 | ) |
65 | required = requires_macs_and_architecture(self.data) or requires_arch |
66 | + self._need_boot_images = required |
67 | self.fields["architecture"] = forms.ChoiceField( |
68 | choices=choices, |
69 | required=required, |
70 | @@ -853,7 +854,7 @@ class MachineForm(NodeForm): |
71 | is_valid = super().is_valid() |
72 | if not is_valid: |
73 | return False |
74 | - if len(list_all_usable_architectures()) == 0: |
75 | + if self._need_boot_images and not list_all_usable_architectures(): |
76 | set_form_error(self, "architecture", NO_ARCHITECTURES_AVAILABLE) |
77 | is_valid = False |
78 | return is_valid |
79 | @@ -1172,6 +1173,23 @@ class AdminMachineForm(MachineForm, AdminNodeForm, WithPowerTypeMixin): |
80 | cleaned_data = WithPowerTypeMixin.check_driver(self, cleaned_data) |
81 | return cleaned_data |
82 | |
83 | + def _setup_deployed_machine(self, machine): |
84 | + """Configure the Machine before it has been saved.""" |
85 | + from metadataserver.models import NodeKey |
86 | + from metadataserver.models.scriptset import ScriptSet |
87 | + |
88 | + machine.status = NODE_STATUS.DEPLOYED |
89 | + # Foreign relations need to have an id to relate to, have to |
90 | + # save here |
91 | + machine.save() |
92 | + script_set = ScriptSet.objects.create_deployed_machine_script_set( |
93 | + machine |
94 | + ) |
95 | + machine.current_commissioning_script_set = script_set |
96 | + |
97 | + # ensure a token is available for the machine |
98 | + NodeKey.objects.get_token_for_node(machine) |
99 | + |
100 | def save(self, *args, **kwargs): |
101 | """Persist the node into the database.""" |
102 | machine = super().save(commit=False) |
103 | @@ -1182,7 +1200,7 @@ class AdminMachineForm(MachineForm, AdminNodeForm, WithPowerTypeMixin): |
104 | if pool: |
105 | machine.pool = pool |
106 | if self.cleaned_data.get("deployed"): |
107 | - machine.status = NODE_STATUS.DEPLOYED |
108 | + self._setup_deployed_machine(machine) |
109 | WithPowerTypeMixin.set_values(self, machine) |
110 | if kwargs.get("commit", True): |
111 | machine.save(*args, **kwargs) |
112 | diff --git a/src/maasserver/forms/ephemeral.py b/src/maasserver/forms/ephemeral.py |
113 | index 39d28e2..b736eaa 100644 |
114 | --- a/src/maasserver/forms/ephemeral.py |
115 | +++ b/src/maasserver/forms/ephemeral.py |
116 | @@ -21,8 +21,8 @@ from django.http import QueryDict |
117 | from maasserver.enum import NODE_STATUS |
118 | from maasserver.node_action import compile_node_actions |
119 | from maasserver.utils.forms import set_form_error |
120 | -from metadataserver.enum import RESULT_TYPE, SCRIPT_TYPE |
121 | -from metadataserver.models import NodeKey, Script, ScriptSet |
122 | +from metadataserver.enum import SCRIPT_TYPE |
123 | +from metadataserver.models import Script |
124 | |
125 | |
126 | class TestForm(Form): |
127 | @@ -322,31 +322,3 @@ class CommissionForm(TestForm): |
128 | ), |
129 | ) |
130 | return self.instance |
131 | - |
132 | - |
133 | -class CreateScriptsForDeployedForm(Form): |
134 | - def __init__(self, instance, **kwargs): |
135 | - super().__init__(**kwargs) |
136 | - self.instance = instance |
137 | - |
138 | - def save(self): |
139 | - node = self.instance |
140 | - scripts = list( |
141 | - Script.objects.filter( |
142 | - script_type=SCRIPT_TYPE.COMMISSIONING, |
143 | - default=True, |
144 | - tags__contains=["deploy-info"], |
145 | - ) |
146 | - ) |
147 | - script_set = ScriptSet.objects.create( |
148 | - node=node, |
149 | - result_type=RESULT_TYPE.COMMISSIONING, |
150 | - requested_scripts=[script.name for script in scripts], |
151 | - ) |
152 | - for script in scripts: |
153 | - script_set.add_pending_script(script) |
154 | - node.current_commissioning_script_set = script_set |
155 | - node.save() |
156 | - # ensure a token is available for the machine |
157 | - NodeKey.objects.get_token_for_node(node) |
158 | - return script_set |
159 | diff --git a/src/maasserver/forms/tests/test_ephemeral.py b/src/maasserver/forms/tests/test_ephemeral.py |
160 | index a5c2e56..fde9528 100644 |
161 | --- a/src/maasserver/forms/tests/test_ephemeral.py |
162 | +++ b/src/maasserver/forms/tests/test_ephemeral.py |
163 | @@ -12,16 +12,11 @@ from maasserver.enum import ( |
164 | NODE_TYPE_CHOICES, |
165 | POWER_STATE, |
166 | ) |
167 | -from maasserver.forms.ephemeral import ( |
168 | - CommissionForm, |
169 | - CreateScriptsForDeployedForm, |
170 | - TestForm, |
171 | -) |
172 | +from maasserver.forms.ephemeral import CommissionForm, TestForm |
173 | from maasserver.testing.factory import factory |
174 | from maasserver.testing.testcase import MAASServerTestCase |
175 | from maastesting.matchers import MockCalledOnceWith |
176 | -from metadataserver.enum import SCRIPT_STATUS, SCRIPT_TYPE |
177 | -from metadataserver.models import NodeKey |
178 | +from metadataserver.enum import SCRIPT_TYPE |
179 | |
180 | |
181 | class TestTestForm(MAASServerTestCase): |
182 | @@ -988,54 +983,3 @@ class TestCommissionForm(MAASServerTestCase): |
183 | script_input={}, |
184 | ), |
185 | ) |
186 | - |
187 | - |
188 | -class TestCreateScriptsForDeployedForm(MAASServerTestCase): |
189 | - def test_create_scripts(self): |
190 | - script1 = factory.make_Script( |
191 | - script_type=SCRIPT_TYPE.COMMISSIONING, |
192 | - default=True, |
193 | - tags=["foo", "deploy-info"], |
194 | - ) |
195 | - script2 = factory.make_Script( |
196 | - script_type=SCRIPT_TYPE.COMMISSIONING, |
197 | - default=True, |
198 | - tags=["bar", "deploy-info"], |
199 | - ) |
200 | - # other scripts that are not matched |
201 | - factory.make_Script( # not for commissioning |
202 | - script_type=SCRIPT_TYPE.TESTING, |
203 | - default=True, |
204 | - tags=["bar", "deploy-info"], |
205 | - ) |
206 | - factory.make_Script( # not a builtin script |
207 | - script_type=SCRIPT_TYPE.COMMISSIONING, |
208 | - default=False, |
209 | - tags=["deploy-info"], |
210 | - ) |
211 | - factory.make_Script( # no deploy-info tag |
212 | - script_type=SCRIPT_TYPE.COMMISSIONING, |
213 | - default=True, |
214 | - tags=["foo"], |
215 | - ) |
216 | - node = factory.make_Node(status=NODE_STATUS.DEPLOYED) |
217 | - form = CreateScriptsForDeployedForm(instance=node, data={}) |
218 | - self.assertTrue(form.is_valid()) |
219 | - script_set = form.save() |
220 | - self.assertEqual(script_set.node, node) |
221 | - script_results = list(script_set.scriptresult_set.order_by("id")) |
222 | - self.assertEqual( |
223 | - [script_result.script for script_result in script_results], |
224 | - [script1, script2], |
225 | - ) |
226 | - for script_result in script_results: |
227 | - self.assertEqual(script_result.status, SCRIPT_STATUS.PENDING) |
228 | - self.assertIs(node.current_commissioning_script_set, script_set) |
229 | - |
230 | - def test_create_node_token(self): |
231 | - node = factory.make_Node(status=NODE_STATUS.DEPLOYED) |
232 | - self.assertFalse(NodeKey.objects.filter(node=node).exists()) |
233 | - form = CreateScriptsForDeployedForm(instance=node, data={}) |
234 | - self.assertTrue(form.is_valid()) |
235 | - form.save() |
236 | - self.assertTrue(NodeKey.objects.filter(node=node).exists()) |
237 | diff --git a/src/maasserver/forms/tests/test_machine.py b/src/maasserver/forms/tests/test_machine.py |
238 | index cef7cbe..bf61313 100644 |
239 | --- a/src/maasserver/forms/tests/test_machine.py |
240 | +++ b/src/maasserver/forms/tests/test_machine.py |
241 | @@ -24,6 +24,7 @@ from maasserver.testing.osystems import ( |
242 | patch_usable_osystems, |
243 | ) |
244 | from maasserver.testing.testcase import MAASServerTestCase |
245 | +from metadataserver.models import NodeKey |
246 | from provisioningserver.rpc.exceptions import ( |
247 | NoConnectionsAvailable, |
248 | NoSuchOperatingSystem, |
249 | @@ -409,11 +410,9 @@ class TestAdminMachineForm(MAASServerTestCase): |
250 | |
251 | def test_AdminMachineForm_new_machine_deployed(self): |
252 | hostname = factory.make_string() |
253 | - arch = make_usable_architecture(self) |
254 | form = AdminMachineForm( |
255 | data={ |
256 | "hostname": hostname, |
257 | - "architecture": arch, |
258 | "deployed": True, |
259 | }, |
260 | ) |
261 | @@ -518,3 +517,25 @@ class TestAdminMachineForm(MAASServerTestCase): |
262 | ] |
263 | }, |
264 | ) |
265 | + |
266 | + def test_AdminMachineForm_creates_scriptset_for_deployed(self): |
267 | + hostname = factory.make_string() |
268 | + form = AdminMachineForm( |
269 | + data={ |
270 | + "hostname": hostname, |
271 | + "deployed": True, |
272 | + }, |
273 | + ) |
274 | + machine = form.save() |
275 | + self.assertIsNotNone(machine.current_commissioning_script_set) |
276 | + |
277 | + def test_AdminMachineForm_creates_node_token_for_deployed(self): |
278 | + hostname = factory.make_string() |
279 | + form = AdminMachineForm( |
280 | + data={ |
281 | + "hostname": hostname, |
282 | + "deployed": True, |
283 | + }, |
284 | + ) |
285 | + machine = form.save() |
286 | + self.assertTrue(NodeKey.objects.filter(node=machine).exists()) |
287 | diff --git a/src/maasserver/websockets/handlers/machine.py b/src/maasserver/websockets/handlers/machine.py |
288 | index 3236647..4425c78 100644 |
289 | --- a/src/maasserver/websockets/handlers/machine.py |
290 | +++ b/src/maasserver/websockets/handlers/machine.py |
291 | @@ -22,6 +22,7 @@ from maasserver.enum import ( |
292 | from maasserver.exceptions import NodeActionError, NodeStateViolation |
293 | from maasserver.forms import ( |
294 | AddPartitionForm, |
295 | + AdminMachineForm, |
296 | AdminMachineWithMACAddressesForm, |
297 | CreateBcacheForm, |
298 | CreateCacheSetForm, |
299 | @@ -246,6 +247,10 @@ class MachineHandler(NodeHandler): |
300 | edit_permission = NodePermission.admin |
301 | delete_permission = NodePermission.admin |
302 | |
303 | + def __init__(self, *args, **kwargs): |
304 | + super().__init__(*args, **kwargs) |
305 | + self._deployed = False |
306 | + |
307 | def get_queryset(self, for_list=False): |
308 | """Return `QuerySet` for devices only viewable by `user`.""" |
309 | return Machine.objects.get_nodes( |
310 | @@ -391,6 +396,8 @@ class MachineHandler(NodeHandler): |
311 | |
312 | def get_form_class(self, action): |
313 | """Return the form class used for `action`.""" |
314 | + if action == "create" and self._deployed: |
315 | + return AdminMachineForm |
316 | if action in ("create", "update"): |
317 | return AdminMachineWithMACAddressesForm |
318 | else: |
319 | @@ -408,6 +415,7 @@ class MachineHandler(NodeHandler): |
320 | new_params["description"] = params.get("description") |
321 | new_params["power_type"] = params.get("power_type") |
322 | new_params["power_parameters"] = params.get("power_parameters") |
323 | + new_params["deployed"] = params.get("deployed") |
324 | if "zone" in params: |
325 | new_params["zone"] = params["zone"]["name"] |
326 | if params.get("pool"): |
327 | @@ -427,18 +435,18 @@ class MachineHandler(NodeHandler): |
328 | return super().preprocess_form(action, new_params) |
329 | |
330 | def create(self, params): |
331 | - """Create the object from params.""" |
332 | + self._deployed = bool(params.get("deployed", False)) |
333 | data = super().create(params) |
334 | - node_obj = Node.objects.get(system_id=data["system_id"]) |
335 | + if not self._deployed: |
336 | + machine = Node.objects.get(system_id=data["system_id"]) |
337 | + # Start the commissioning process right away, which has the |
338 | + # desired side effect of initializing the node's power state. |
339 | + d = machine.start_commissioning(self.user) |
340 | + # Silently ignore errors to prevent tracebacks. The commissioning |
341 | + # callbacks have their own logging. This fixes LP1600328. |
342 | + d.addErrback(lambda _: None) |
343 | |
344 | - # Start the commissioning process right away, which has the |
345 | - # desired side effect of initializing the node's power state. |
346 | - d = node_obj.start_commissioning(self.user) |
347 | - # Silently ignore errors to prevent tracebacks. The commissioning |
348 | - # callbacks have their own logging. This fixes LP1600328. |
349 | - d.addErrback(lambda _: None) |
350 | - |
351 | - return self.full_dehydrate(node_obj) |
352 | + return data |
353 | |
354 | def update(self, params): |
355 | """Update the object from params.""" |
356 | diff --git a/src/maasserver/websockets/handlers/tests/test_machine.py b/src/maasserver/websockets/handlers/tests/test_machine.py |
357 | index 391127b..b13f953 100644 |
358 | --- a/src/maasserver/websockets/handlers/tests/test_machine.py |
359 | +++ b/src/maasserver/websockets/handlers/tests/test_machine.py |
360 | @@ -114,6 +114,7 @@ from metadataserver.enum import ( |
361 | SCRIPT_STATUS_FAILED, |
362 | SCRIPT_TYPE, |
363 | ) |
364 | +from metadataserver.models.nodekey import NodeKey |
365 | from metadataserver.models.scriptset import get_status_from_qs |
366 | from provisioningserver.refresh.node_info_scripts import ( |
367 | LIST_MODALIASES_OUTPUT_NAME, |
368 | @@ -2416,6 +2417,33 @@ class TestMachineHandler(MAASServerTestCase): |
369 | ) |
370 | self.assertThat(mock_start_commissioning, MockCalledOnceWith(user)) |
371 | |
372 | + def test_create_creates_deployed_node(self): |
373 | + user = factory.make_admin() |
374 | + handler = MachineHandler(user, {}, None) |
375 | + hostname = factory.make_name("hostname") |
376 | + description = factory.make_name("description") |
377 | + zone = factory.make_Zone() |
378 | + |
379 | + mock_start_commissioning = self.patch( |
380 | + node_model, "start_commissioning" |
381 | + ) |
382 | + |
383 | + created_node = handler.create( |
384 | + { |
385 | + "hostname": hostname, |
386 | + "description": description, |
387 | + "zone": {"name": zone.name}, |
388 | + "deployed": True, |
389 | + } |
390 | + ) |
391 | + # the commissioning process is not started |
392 | + mock_start_commissioning.assert_not_called() |
393 | + self.assertEqual(created_node["status"], "Deployed") |
394 | + node = Node.objects.get(system_id=created_node["system_id"]) |
395 | + self.assertIsNotNone(node.current_commissioning_script_set) |
396 | + self.assertTrue(NodeKey.objects.filter(node=node).exists()) |
397 | + self.assertEqual(node.status, NODE_STATUS.DEPLOYED) |
398 | + |
399 | def test_update_raise_permissions_error_for_non_admin(self): |
400 | user = factory.make_User() |
401 | node = factory.make_Node() |
402 | diff --git a/src/metadataserver/models/scriptset.py b/src/metadataserver/models/scriptset.py |
403 | index e9eed4a..2e8dea6 100644 |
404 | --- a/src/metadataserver/models/scriptset.py |
405 | +++ b/src/metadataserver/models/scriptset.py |
406 | @@ -227,6 +227,25 @@ class ScriptSetManager(Manager): |
407 | self._clean_old(node, RESULT_TYPE.INSTALLATION, script_set) |
408 | return script_set |
409 | |
410 | + def create_deployed_machine_script_set(self, machine): |
411 | + """Setup ScriptSet for a brown-field deployment. |
412 | + |
413 | + Built-in scripts with deploy-info tag are queued up. |
414 | + """ |
415 | + scripts = list( |
416 | + Script.objects.filter( |
417 | + script_type=SCRIPT_TYPE.COMMISSIONING, |
418 | + default=True, |
419 | + tags__contains=["deploy-info"], |
420 | + ) |
421 | + ) |
422 | + script_set = machine.scriptset_set.create( |
423 | + requested_scripts=[script.name for script in scripts] |
424 | + ) |
425 | + for script in scripts: |
426 | + script_set.add_pending_script(script) |
427 | + return script_set |
428 | + |
429 | def _find_scripts(self, script_qs, hw_pairs, modaliases): |
430 | for script in script_qs: |
431 | # If a script is not for specific hardware, it is always included |
432 | @@ -444,13 +463,10 @@ class ScriptSet(CleanSave, Model): |
433 | def add_pending_script(self, script, script_input=None): |
434 | """Create and add a new ScriptResult for the given Script. |
435 | |
436 | - Creates a new ScriptResult for the given script and assoicates it with |
437 | + Creates a new ScriptResult for the given script and associates it with |
438 | this ScriptSet. Raises a ValidationError if ParametersForm validation |
439 | fails. |
440 | """ |
441 | - # Avoid circular dependencies. |
442 | - from metadataserver.models import ScriptResult |
443 | - |
444 | if script_input is None: |
445 | script_input = {} |
446 | form = ParametersForm( |
447 | @@ -461,8 +477,7 @@ class ScriptSet(CleanSave, Model): |
448 | if not form.is_valid(): |
449 | raise ValidationError(form.errors) |
450 | for param in form.cleaned_data["input"]: |
451 | - ScriptResult.objects.create( |
452 | - script_set=self, |
453 | + self.scriptresult_set.create( |
454 | status=SCRIPT_STATUS.PENDING, |
455 | script=script, |
456 | script_name=script.name, |
457 | diff --git a/src/metadataserver/models/tests/test_scriptset.py b/src/metadataserver/models/tests/test_scriptset.py |
458 | index 68a5b9f..ad37878 100644 |
459 | --- a/src/metadataserver/models/tests/test_scriptset.py |
460 | +++ b/src/metadataserver/models/tests/test_scriptset.py |
461 | @@ -10,7 +10,7 @@ from unittest.mock import PropertyMock |
462 | from django.core.exceptions import ValidationError |
463 | from django.db.models import Q |
464 | |
465 | -from maasserver.enum import NODE_TYPE |
466 | +from maasserver.enum import NODE_STATUS, NODE_TYPE |
467 | from maasserver.exceptions import NoScriptsFound |
468 | from maasserver.models import Config, Event, EventType, Node |
469 | from maasserver.preseed import CURTIN_INSTALL_LOG |
470 | @@ -1012,6 +1012,48 @@ class TestScriptSetManager(MAASServerTestCase): |
471 | ).all(), |
472 | ) |
473 | |
474 | + def test_create_deployed_machine_script_set_scripts(self): |
475 | + # Avoid builtins muddying the test |
476 | + Script.objects.all().delete() |
477 | + script1 = factory.make_Script( |
478 | + script_type=SCRIPT_TYPE.COMMISSIONING, |
479 | + default=True, |
480 | + tags=["foo", "deploy-info"], |
481 | + ) |
482 | + script2 = factory.make_Script( |
483 | + script_type=SCRIPT_TYPE.COMMISSIONING, |
484 | + default=True, |
485 | + tags=["bar", "deploy-info"], |
486 | + ) |
487 | + # other scripts that are not matched |
488 | + factory.make_Script( # not for commissioning |
489 | + script_type=SCRIPT_TYPE.TESTING, |
490 | + default=True, |
491 | + tags=["bar", "deploy-info"], |
492 | + ) |
493 | + factory.make_Script( # not a builtin script |
494 | + script_type=SCRIPT_TYPE.COMMISSIONING, |
495 | + default=False, |
496 | + tags=["deploy-info"], |
497 | + ) |
498 | + factory.make_Script( # no deploy-info tag |
499 | + script_type=SCRIPT_TYPE.COMMISSIONING, |
500 | + default=True, |
501 | + tags=["foo"], |
502 | + ) |
503 | + node = factory.make_Node(status=NODE_STATUS.DEPLOYED) |
504 | + script_set = ScriptSet.objects.create_deployed_machine_script_set(node) |
505 | + self.assertItemsEqual( |
506 | + [ |
507 | + (script_result.script, script_result.status) |
508 | + for script_result in script_set.scriptresult_set.all() |
509 | + ], |
510 | + [ |
511 | + (script1, SCRIPT_STATUS.PENDING), |
512 | + (script2, SCRIPT_STATUS.PENDING), |
513 | + ], |
514 | + ) |
515 | + |
516 | |
517 | class TestScriptSet(MAASServerTestCase): |
518 | """Test the ScriptSet model.""" |
nice!
just one question inline