1# Test configuration switching.
2{ lib, pkgs, ... }:
3
4let
5
6 # Simple service that can either be socket-activated or that will
7 # listen on port 1234 if not socket-activated.
8 # A connection to the socket causes 'hello' to be written to the client.
9 socketTest =
10 pkgs.writeScript "socket-test.py" # python
11 ''
12 #!${pkgs.python3}/bin/python3
13
14 from socketserver import TCPServer, StreamRequestHandler
15 import socket
16 import os
17
18
19 class Handler(StreamRequestHandler):
20 def handle(self):
21 self.wfile.write("hello".encode("utf-8"))
22
23
24 class Server(TCPServer):
25 def __init__(self, server_address, handler_cls):
26 listenFds = os.getenv('LISTEN_FDS')
27 if listenFds is None or int(listenFds) < 1:
28 print(f'Binding to {server_address}')
29 TCPServer.__init__(
30 self, server_address, handler_cls, bind_and_activate=True)
31 else:
32 TCPServer.__init__(
33 self, server_address, handler_cls, bind_and_activate=False)
34 # Override socket
35 print(f'Got activated by {os.getenv("LISTEN_FDNAMES")} '
36 f'with {listenFds} FDs')
37 self.socket = socket.fromfd(3, self.address_family,
38 self.socket_type)
39
40
41 if __name__ == "__main__":
42 server = Server(("localhost", 1234), Handler)
43 server.serve_forever()
44 '';
45
46in
47{
48 name = "switch-test";
49 meta = with pkgs.lib.maintainers; {
50 maintainers = [
51 gleber
52 das_j
53 ];
54 };
55
56 nodes = {
57 machine =
58 { pkgs, lib, ... }:
59 {
60 environment.systemPackages = [ pkgs.socat ]; # for the socket activation stuff
61 users.mutableUsers = false;
62
63 # Test that no boot loader still switches, e.g. in the ISO
64 boot.loader.grub.enable = false;
65
66 specialisation = rec {
67 brokenInitInterface.configuration.config.system.extraSystemBuilderCmds = ''
68 echo "systemd 0" > $out/init-interface-version
69 '';
70
71 modifiedSystemConf.configuration.systemd.settings.Manager = {
72 DefaultEnvironment = "XXX_SYSTEM=foo";
73 };
74
75 addedMount.configuration.virtualisation.fileSystems."/test" = {
76 device = "tmpfs";
77 fsType = "tmpfs";
78 };
79
80 addedMountOptsModified.configuration = {
81 imports = [ addedMount.configuration ];
82 virtualisation.fileSystems."/test".options = [ "x-test" ];
83 };
84
85 addedMountDevModified.configuration = {
86 imports = [ addedMountOptsModified.configuration ];
87 virtualisation.fileSystems."/test".device = lib.mkForce "ramfs";
88 };
89
90 storeMountModified.configuration = {
91 virtualisation.fileSystems."/".device = lib.mkForce "auto";
92 };
93
94 swap.configuration.swapDevices = lib.mkVMOverride [
95 {
96 device = "/swapfile";
97 size = 1;
98 }
99 ];
100
101 simpleService.configuration = {
102 systemd.services.test = {
103 wantedBy = [ "multi-user.target" ];
104 serviceConfig = {
105 Type = "oneshot";
106 RemainAfterExit = true;
107 ExecStart = "${pkgs.coreutils}/bin/true";
108 ExecReload = "${pkgs.coreutils}/bin/true";
109 };
110 };
111 };
112
113 simpleServiceSeparateActivationScript.configuration = {
114 system.activatable = false;
115 systemd.services.test = {
116 wantedBy = [ "multi-user.target" ];
117 serviceConfig = {
118 Type = "oneshot";
119 RemainAfterExit = true;
120 ExecStart = "${pkgs.coreutils}/bin/true";
121 ExecReload = "${pkgs.coreutils}/bin/true";
122 };
123 };
124 };
125
126 simpleServiceDifferentDescription.configuration = {
127 imports = [ simpleService.configuration ];
128 systemd.services.test.description = "Test unit";
129 };
130
131 simpleServiceModified.configuration = {
132 imports = [ simpleService.configuration ];
133 systemd.services.test.serviceConfig.X-Test = true;
134 };
135
136 simpleServiceNostop.configuration = {
137 imports = [ simpleService.configuration ];
138 systemd.services.test.stopIfChanged = false;
139 };
140
141 simpleServiceReload.configuration = {
142 imports = [ simpleService.configuration ];
143 systemd.services.test = {
144 reloadIfChanged = true;
145 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
146 };
147 };
148
149 simpleServiceNorestart.configuration = {
150 imports = [ simpleService.configuration ];
151 systemd.services.test.restartIfChanged = false;
152 };
153
154 simpleServiceFailing.configuration = {
155 imports = [ simpleServiceModified.configuration ];
156 systemd.services.test.serviceConfig.ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false";
157 };
158
159 autorestartService.configuration = {
160 # A service that immediately goes into restarting (but without failing)
161 systemd.services.autorestart = {
162 wantedBy = [ "multi-user.target" ];
163 serviceConfig = {
164 Type = "simple";
165 Restart = "always";
166 RestartSec = "20y"; # Should be long enough
167 ExecStart = "${pkgs.coreutils}/bin/true";
168 };
169 };
170 };
171
172 autorestartServiceFailing.configuration = {
173 imports = [ autorestartService.configuration ];
174 systemd.services.autorestart.serviceConfig = {
175 ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false";
176 };
177 };
178
179 simpleServiceWithExtraSection.configuration = {
180 imports = [ simpleServiceNostop.configuration ];
181 systemd.packages = [
182 (pkgs.writeTextFile {
183 name = "systemd-extra-section";
184 destination = "/etc/systemd/system/test.service";
185 text = ''
186 [X-Test]
187 X-Test-Value=a
188 '';
189 })
190 ];
191 };
192
193 simpleServiceWithExtraSectionOtherName.configuration = {
194 imports = [ simpleServiceNostop.configuration ];
195 systemd.packages = [
196 (pkgs.writeTextFile {
197 name = "systemd-extra-section";
198 destination = "/etc/systemd/system/test.service";
199 text = ''
200 [X-Test2]
201 X-Test-Value=a
202 '';
203 })
204 ];
205 };
206
207 simpleServiceWithInstallSection.configuration = {
208 imports = [ simpleServiceNostop.configuration ];
209 systemd.packages = [
210 (pkgs.writeTextFile {
211 name = "systemd-extra-section";
212 destination = "/etc/systemd/system/test.service";
213 text = ''
214 [Install]
215 WantedBy=multi-user.target
216 '';
217 })
218 ];
219 };
220
221 simpleServiceWithExtraKey.configuration = {
222 imports = [ simpleServiceNostop.configuration ];
223 systemd.services.test.serviceConfig."X-Test" = "test";
224 };
225
226 simpleServiceWithExtraKeyOtherValue.configuration = {
227 imports = [ simpleServiceNostop.configuration ];
228 systemd.services.test.serviceConfig."X-Test" = "test2";
229 };
230
231 simpleServiceWithExtraKeyOtherName.configuration = {
232 imports = [ simpleServiceNostop.configuration ];
233 systemd.services.test.serviceConfig."X-Test2" = "test";
234 };
235
236 simpleServiceReloadTrigger.configuration = {
237 imports = [ simpleServiceNostop.configuration ];
238 systemd.services.test.reloadTriggers = [ "/dev/null" ];
239 };
240
241 simpleServiceReloadTriggerModified.configuration = {
242 imports = [ simpleServiceNostop.configuration ];
243 systemd.services.test.reloadTriggers = [ "/dev/zero" ];
244 };
245
246 simpleServiceReloadTriggerModifiedAndSomethingElse.configuration = {
247 imports = [ simpleServiceNostop.configuration ];
248 systemd.services.test = {
249 reloadTriggers = [ "/dev/zero" ];
250 serviceConfig."X-Test" = "test";
251 };
252 };
253
254 simpleServiceReloadTriggerModifiedSomethingElse.configuration = {
255 imports = [ simpleServiceNostop.configuration ];
256 systemd.services.test.serviceConfig."X-Test" = "test";
257 };
258
259 unitWithBackslash.configuration = {
260 systemd.services."escaped\\x2ddash" = {
261 wantedBy = [ "multi-user.target" ];
262 serviceConfig = {
263 Type = "oneshot";
264 RemainAfterExit = true;
265 ExecStart = "${pkgs.coreutils}/bin/true";
266 ExecReload = "${pkgs.coreutils}/bin/true";
267 };
268 };
269 };
270
271 unitWithBackslashModified.configuration = {
272 imports = [ unitWithBackslash.configuration ];
273 systemd.services."escaped\\x2ddash".serviceConfig.X-Test = "test";
274 };
275
276 unitWithMultilineValue.configuration = {
277 systemd.services.test.serviceConfig.ExecStart = ''
278 ${pkgs.coreutils}/bin/true \
279 # ignored
280 ; ignored
281 blah blah
282 '';
283 };
284
285 unitStartingWithDash.configuration = {
286 systemd.services."-" = {
287 wantedBy = [ "multi-user.target" ];
288 serviceConfig = {
289 Type = "oneshot";
290 RemainAfterExit = true;
291 ExecStart = "${pkgs.coreutils}/bin/true";
292 };
293 };
294 };
295
296 unitStartingWithDashModified.configuration = {
297 imports = [ unitStartingWithDash.configuration ];
298 systemd.services."-" = {
299 reloadIfChanged = true;
300 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
301 };
302 };
303
304 unitWithRequirement.configuration = {
305 systemd.services.required-service = {
306 wantedBy = [ "multi-user.target" ];
307 serviceConfig = {
308 Type = "oneshot";
309 RemainAfterExit = true;
310 ExecStart = "${pkgs.coreutils}/bin/true";
311 ExecReload = "${pkgs.coreutils}/bin/true";
312 };
313 };
314 systemd.services.test-service = {
315 wantedBy = [ "multi-user.target" ];
316 requires = [ "required-service.service" ];
317 serviceConfig = {
318 Type = "oneshot";
319 RemainAfterExit = true;
320 ExecStart = "${pkgs.coreutils}/bin/true";
321 ExecReload = "${pkgs.coreutils}/bin/true";
322 };
323 };
324 };
325
326 unitWithRequirementModified.configuration = {
327 imports = [ unitWithRequirement.configuration ];
328 systemd.services.required-service.serviceConfig.X-Test = "test";
329 systemd.services.test-service.reloadTriggers = [ "test" ];
330 };
331
332 unitWithRequirementModifiedNostart.configuration = {
333 imports = [ unitWithRequirement.configuration ];
334 systemd.services.test-service.unitConfig.RefuseManualStart = true;
335 };
336
337 unitWithTemplate.configuration = {
338 systemd.services."instantiated@".serviceConfig = {
339 Type = "oneshot";
340 RemainAfterExit = true;
341 ExecStart = "${pkgs.coreutils}/bin/true";
342 ExecReload = "${pkgs.coreutils}/bin/true";
343 };
344 systemd.services."instantiated@one" = {
345 wantedBy = [ "multi-user.target" ];
346 overrideStrategy = "asDropin";
347 };
348 systemd.services."instantiated@two" = {
349 wantedBy = [ "multi-user.target" ];
350 overrideStrategy = "asDropin";
351 };
352 };
353
354 unitWithTemplateModified.configuration = {
355 imports = [ unitWithTemplate.configuration ];
356 systemd.services."instantiated@".serviceConfig.X-Test = "test";
357 };
358
359 restart-and-reload-by-activation-script.configuration = {
360 systemd.services = rec {
361 simple-service = {
362 # No wantedBy so we can check if the activation script restart triggers them
363 serviceConfig = {
364 Type = "oneshot";
365 RemainAfterExit = true;
366 ExecStart = "${pkgs.coreutils}/bin/true";
367 ExecReload = "${pkgs.coreutils}/bin/true";
368 };
369 };
370 "templated-simple-service@" = simple-service;
371 "templated-simple-service@instance".overrideStrategy = "asDropin";
372
373 simple-restart-service = simple-service // {
374 stopIfChanged = false;
375 };
376 "templated-simple-restart-service@" = simple-restart-service;
377 "templated-simple-restart-service@instance".overrideStrategy = "asDropin";
378
379 simple-reload-service = simple-service // {
380 reloadIfChanged = true;
381 };
382 "templated-simple-reload-service@" = simple-reload-service;
383 "templated-simple-reload-service@instance".overrideStrategy = "asDropin";
384
385 no-restart-service = simple-service // {
386 restartIfChanged = false;
387 };
388 "templated-no-restart-service@" = no-restart-service;
389 "templated-no-restart-service@instance".overrideStrategy = "asDropin";
390
391 reload-triggers = simple-service // {
392 wantedBy = [ "multi-user.target" ];
393 };
394 "templated-reload-triggers@" = simple-service;
395 "templated-reload-triggers@instance" = {
396 overrideStrategy = "asDropin";
397 wantedBy = [ "multi-user.target" ];
398 };
399
400 reload-triggers-and-restart-by-as = simple-service;
401 "templated-reload-triggers-and-restart-by-as@" = reload-triggers-and-restart-by-as;
402 "templated-reload-triggers-and-restart-by-as@instance".overrideStrategy = "asDropin";
403
404 reload-triggers-and-restart = simple-service // {
405 stopIfChanged = false; # easier to check for this
406 wantedBy = [ "multi-user.target" ];
407 };
408 "templated-reload-triggers-and-restart@" = simple-service;
409 "templated-reload-triggers-and-restart@instance" = {
410 overrideStrategy = "asDropin";
411 stopIfChanged = false; # easier to check for this
412 wantedBy = [ "multi-user.target" ];
413 };
414 };
415
416 system.activationScripts.restart-and-reload-test = {
417 supportsDryActivation = true;
418 deps = [ ];
419 text = ''
420 if [ "$NIXOS_ACTION" = dry-activate ]; then
421 f=/run/nixos/dry-activation-restart-list
422 g=/run/nixos/dry-activation-reload-list
423 else
424 f=/run/nixos/activation-restart-list
425 g=/run/nixos/activation-reload-list
426 fi
427 cat <<EOF >> "$f"
428 simple-service.service
429 simple-restart-service.service
430 simple-reload-service.service
431 no-restart-service.service
432 reload-triggers-and-restart-by-as.service
433 templated-simple-service@instance.service
434 templated-simple-restart-service@instance.service
435 templated-simple-reload-service@instance.service
436 templated-no-restart-service@instance.service
437 templated-reload-triggers-and-restart-by-as@instance.service
438 EOF
439
440 cat <<EOF >> "$g"
441 reload-triggers.service
442 reload-triggers-and-restart-by-as.service
443 reload-triggers-and-restart.service
444 templated-reload-triggers@instance.service
445 templated-reload-triggers-and-restart-by-as@instance.service
446 templated-reload-triggers-and-restart@instance.service
447 EOF
448 '';
449 };
450 };
451
452 restart-and-reload-by-activation-script-modified.configuration = {
453 imports = [ restart-and-reload-by-activation-script.configuration ];
454 systemd.services.reload-triggers-and-restart.serviceConfig.X-Modified = "test";
455 systemd.services."templated-reload-triggers-and-restart@instance" = {
456 overrideStrategy = "asDropin";
457 serviceConfig.X-Modified = "test";
458 };
459 };
460
461 simple-socket.configuration = {
462 systemd.services.socket-activated = {
463 description = "A socket-activated service";
464 stopIfChanged = lib.mkDefault false;
465 serviceConfig = {
466 ExecStart = socketTest;
467 ExecReload = "${pkgs.coreutils}/bin/true";
468 };
469 };
470 systemd.sockets.socket-activated = {
471 wantedBy = [ "sockets.target" ];
472 listenStreams = [ "/run/test.sock" ];
473 socketConfig.SocketMode = lib.mkDefault "0777";
474 };
475 };
476
477 simple-socket-service-modified.configuration = {
478 imports = [ simple-socket.configuration ];
479 systemd.services.socket-activated.serviceConfig.X-Test = "test";
480 };
481
482 simple-socket-stop-if-changed.configuration = {
483 imports = [ simple-socket.configuration ];
484 systemd.services.socket-activated.stopIfChanged = true;
485 };
486
487 simple-socket-stop-if-changed-and-reloadtrigger.configuration = {
488 imports = [ simple-socket.configuration ];
489 systemd.services.socket-activated = {
490 stopIfChanged = true;
491 reloadTriggers = [ "test" ];
492 };
493 };
494
495 mount.configuration = {
496 systemd.mounts = [
497 {
498 description = "Testmount";
499 what = "tmpfs";
500 type = "tmpfs";
501 where = "/testmount";
502 options = "size=1M";
503 wantedBy = [ "local-fs.target" ];
504 }
505 ];
506 };
507
508 mountOptionsModified.configuration = {
509 systemd.mounts = [
510 {
511 description = "Testmount";
512 what = "tmpfs";
513 type = "tmpfs";
514 where = "/testmount";
515 options = "size=10M";
516 wantedBy = [ "local-fs.target" ];
517 }
518 ];
519 };
520
521 mountModified.configuration = {
522 systemd.mounts = [
523 {
524 description = "Testmount";
525 what = "ramfs";
526 type = "ramfs";
527 where = "/testmount";
528 options = "size=10M";
529 wantedBy = [ "local-fs.target" ];
530 }
531 ];
532 };
533
534 timer.configuration = {
535 systemd.timers.test-timer = {
536 wantedBy = [ "timers.target" ];
537 timerConfig.OnCalendar = "@1395716396"; # chosen by fair dice roll
538 };
539 systemd.services.test-timer = {
540 serviceConfig = {
541 Type = "oneshot";
542 ExecStart = "${pkgs.coreutils}/bin/true";
543 };
544 };
545 };
546
547 timerModified.configuration = {
548 imports = [ timer.configuration ];
549 systemd.timers.test-timer.timerConfig.OnCalendar = lib.mkForce "Fri 2012-11-23 16:00:00";
550 };
551
552 hybridSleepModified.configuration = {
553 systemd.targets.hybrid-sleep.unitConfig.X-Test = true;
554 };
555
556 target.configuration = {
557 systemd.targets.test-target.wantedBy = [ "multi-user.target" ];
558 # We use this service to figure out whether the target was modified.
559 # This is the only way because targets are filtered and therefore not
560 # printed when they are started/stopped.
561 systemd.services.test-service = {
562 bindsTo = [ "test-target.target" ];
563 serviceConfig.ExecStart = "${pkgs.coreutils}/bin/sleep infinity";
564 };
565 };
566
567 targetModified.configuration = {
568 imports = [ target.configuration ];
569 systemd.targets.test-target.unitConfig.X-Test = true;
570 };
571
572 targetModifiedStopOnReconfig.configuration = {
573 imports = [ target.configuration ];
574 systemd.targets.test-target.unitConfig.X-StopOnReconfiguration = true;
575 };
576
577 path.configuration = {
578 systemd.paths.test-watch = {
579 wantedBy = [ "paths.target" ];
580 pathConfig.PathExists = "/testpath";
581 };
582 systemd.services.test-watch = {
583 serviceConfig = {
584 Type = "oneshot";
585 RemainAfterExit = true;
586 ExecStart = "${pkgs.coreutils}/bin/touch /testpath-modified";
587 };
588 };
589 };
590
591 pathModified.configuration = {
592 imports = [ path.configuration ];
593 systemd.paths.test-watch.pathConfig.PathExists = lib.mkForce "/testpath2";
594 };
595
596 slice.configuration = {
597 systemd.slices.testslice.sliceConfig.MemoryMax = "1"; # don't allow memory allocation
598 systemd.services.testservice = {
599 serviceConfig = {
600 Type = "oneshot";
601 RemainAfterExit = true;
602 ExecStart = "${pkgs.coreutils}/bin/true";
603 Slice = "testslice.slice";
604 };
605 };
606 };
607
608 sliceModified.configuration = {
609 imports = [ slice.configuration ];
610 systemd.slices.testslice.sliceConfig.MemoryMax = lib.mkForce null;
611 };
612
613 dbusReload.configuration =
614 { config, ... }:
615 let
616 dbusService =
617 {
618 "dbus" = "dbus";
619 "broker" = "dbus-broker";
620 }
621 .${config.services.dbus.implementation};
622 in
623 {
624 # We want to make sure that stc catches this as a reload,
625 # not a restart.
626 systemd.services.${dbusService}.restartTriggers = [
627 (pkgs.writeText "dbus-reload-dummy" "dbus reload dummy")
628 ];
629 };
630 };
631 };
632
633 other = {
634 system.switch.enable = true;
635 users.mutableUsers = true;
636 system.preSwitchChecks.succeeds = ''
637 config="$1"
638 action="$2"
639 echo "this should succeed (config: $config, action: $action)"
640 [ "$action" == "check" ] || [ "$action" == "test" ]
641 '';
642 specialisation.failingCheck.configuration.system.preSwitchChecks.failEveryTime = ''
643 echo this will fail
644 false
645 '';
646 };
647 };
648
649 testScript =
650 { nodes, ... }:
651 let
652 originalSystem = nodes.machine.system.build.toplevel;
653 otherSystem = nodes.other.system.build.toplevel;
654 machine = nodes.machine.system.build.toplevel;
655
656 # Ensures failures pass through using pipefail, otherwise failing to
657 # switch-to-configuration is hidden by the success of `tee`.
658 stderrRunner = pkgs.writeScript "stderr-runner" ''
659 #! ${pkgs.runtimeShell}
660 set -e
661 set -o pipefail
662 exec env -i "$@" | tee /dev/stderr
663 '';
664
665 # Returns a comma separated representation of the given list in sorted
666 # order, that matches the output format of switch-to-configuration
667 sortedUnits = xs: lib.concatStringsSep ", " (builtins.sort builtins.lessThan xs);
668
669 dbusService =
670 {
671 "dbus" = "dbus.service";
672 "broker" = "dbus-broker.service";
673 }
674 .${nodes.machine.services.dbus.implementation};
675 in
676 # python
677 ''
678 def switch_to_specialisation(system, name, action="test", fail=False):
679 if name == "":
680 switcher = f"{system}/bin/switch-to-configuration"
681 else:
682 switcher = f"{system}/specialisation/{name}/bin/switch-to-configuration"
683 return run_switch(switcher, action, fail)
684
685 # like above but stc = switcher
686 def run_switch(switcher, action="test", fail=False):
687 out = machine.fail(f"{switcher} {action} 2>&1") if fail \
688 else machine.succeed(f"{switcher} {action} 2>&1")
689 assert_lacks(out, "switch-to-configuration line") # Perl warnings
690 return out
691
692 def assert_contains(haystack, needle):
693 if needle not in haystack:
694 print("The haystack that will cause the following exception is:")
695 print("---")
696 print(haystack)
697 print("---")
698 raise Exception(f"Expected string '{needle}' was not found")
699
700 def assert_lacks(haystack, needle):
701 if needle in haystack:
702 print("The haystack that will cause the following exception is:")
703 print("---")
704 print(haystack, end="")
705 print("---")
706 raise Exception(f"Unexpected string '{needle}' was found")
707
708
709 machine.wait_for_unit("multi-user.target")
710
711 machine.succeed(
712 "${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
713 )
714 # This tests whether the /etc/os-release parser works which is a fallback
715 # when /etc/NIXOS is missing. If the parser does not work, switch-to-configuration
716 # would fail.
717 machine.succeed("rm /etc/NIXOS")
718 machine.succeed(
719 "${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
720 )
721
722 boot_loader_text = "Warning: do not know how to make this configuration bootable; please enable a boot loader."
723
724 with subtest("pre-switch checks"):
725 machine.succeed("${stderrRunner} ${otherSystem}/bin/switch-to-configuration check")
726 out = switch_to_specialisation("${otherSystem}", "failingCheck", action="check", fail=True)
727 assert_contains(out, "this will fail")
728
729 with subtest("actions"):
730 # boot action
731 out = switch_to_specialisation("${machine}", "simpleService", action="boot")
732 assert_contains(out, boot_loader_text)
733 assert_lacks(out, "activating the configuration...") # good indicator of a system activation
734
735 # switch action
736 out = switch_to_specialisation("${machine}", "", action="switch")
737 assert_contains(out, boot_loader_text)
738 assert_contains(out, "activating the configuration...") # good indicator of a system activation
739
740 # test and dry-activate actions are tested further down below
741
742 # invalid action fails the script
743 switch_to_specialisation("${machine}", "", action="broken-action", fail=True)
744 # no action fails the script
745 assert "Usage:" in machine.fail("${machine}/bin/switch-to-configuration 2>&1")
746
747 with subtest("init interface version"):
748 # Do not try to switch to an invalid init interface version
749 assert "incompatible" in switch_to_specialisation("${machine}", "brokenInitInterface", fail=True)
750
751 with subtest("systemd restarts"):
752 # systemd is restarted when its system.conf changes
753 out = switch_to_specialisation("${machine}", "modifiedSystemConf")
754 assert_contains(out, "restarting systemd...")
755
756 with subtest("continuing from an aborted switch"):
757 # An aborted switch will write into a file what it tried to start
758 # and a second switch should continue from this
759 machine.succeed("echo ${dbusService} > /run/nixos/start-list")
760 out = switch_to_specialisation("${machine}", "modifiedSystemConf")
761 assert_contains(out, "starting the following units: ${dbusService}\n")
762
763 with subtest("aborts on already locked lock file"):
764 (exitcode, _) = machine.execute(
765 'flock -x --nb /run/nixos/switch-to-configuration.lock -c "${otherSystem}/bin/switch-to-configuration test"',
766 timeout=5
767 )
768 # See man timeout, exit codes above 124 come from the timeout command
769 # We want to make sure that stc actually exited with an error code,
770 # if instead we hit the timeout, then it means that stc hangs, which is
771 # what we don't want
772 # TODO: We cannot match on the exact exit code since it's not consistent between
773 # stc and stc-ng, since errno/last_os_error is not a very stable interface,
774 # we should probably get rid of that in stc-ng once we got rid of the
775 # perl implementation
776 assert exitcode < 124, \
777 "switch-to-configuration did not abort as expected, " + \
778 f"probably it timed out instead (exit code: {exitcode}), 124 means timeout"
779
780 with subtest("fstab mounts"):
781 switch_to_specialisation("${machine}", "")
782 # add a mountpoint
783 out = switch_to_specialisation("${machine}", "addedMount")
784 assert_lacks(out, "stopping the following units:")
785 assert_lacks(out, "NOT restarting the following changed units:")
786 assert_lacks(out, "\nrestarting the following units:")
787 assert_lacks(out, "\nstarting the following units:")
788 assert_contains(out, "the following new units were started: test.mount\n")
789 # modify the mountpoint's options
790 out = switch_to_specialisation("${machine}", "addedMountOptsModified")
791 assert_lacks(out, "stopping the following units:")
792 assert_lacks(out, "NOT restarting the following changed units:")
793 assert_contains(out, "reloading the following units: test.mount\n")
794 assert_lacks(out, "\nrestarting the following units:")
795 assert_lacks(out, "\nstarting the following units:")
796 assert_lacks(out, "the following new units were started:")
797 # modify the device
798 out = switch_to_specialisation("${machine}", "addedMountDevModified")
799 assert_lacks(out, "stopping the following units:")
800 assert_lacks(out, "NOT restarting the following changed units:")
801 assert_lacks(out, "reloading the following units:")
802 assert_contains(out, "\nrestarting the following units: test.mount\n")
803 assert_lacks(out, "\nstarting the following units:")
804 assert_lacks(out, "the following new units were started:")
805 # modify both
806 out = switch_to_specialisation("${machine}", "addedMount")
807 assert_lacks(out, "stopping the following units:")
808 assert_lacks(out, "NOT restarting the following changed units:")
809 assert_lacks(out, "reloading the following units:")
810 assert_contains(out, "\nrestarting the following units: test.mount\n")
811 assert_lacks(out, "\nstarting the following units:")
812 assert_lacks(out, "the following new units were started:")
813 # remove the mount
814 out = switch_to_specialisation("${machine}", "")
815 assert_contains(out, "stopping the following units: test.mount\n")
816 assert_lacks(out, "NOT restarting the following changed units:")
817 assert_lacks(out, "reloading the following units:")
818 assert_lacks(out, "\nrestarting the following units:")
819 assert_lacks(out, "\nstarting the following units:")
820 assert_lacks(out, "the following new units were started:")
821 # change something about the / mount
822 out = switch_to_specialisation("${machine}", "storeMountModified")
823 assert_lacks(out, "stopping the following units:")
824 assert_contains(out, "NOT restarting the following changed units: -.mount")
825 assert_lacks(out, "reloading the following units:")
826 assert_lacks(out, "\nrestarting the following units:")
827 assert_lacks(out, "\nstarting the following units:")
828 assert_lacks(out, "the following new units were started:")
829
830 with subtest("swaps"):
831 switch_to_specialisation("${machine}", "")
832 # add a swap
833 out = switch_to_specialisation("${machine}", "swap")
834 assert_lacks(out, "stopping the following units:")
835 assert_lacks(out, "NOT restarting the following changed units:")
836 assert_lacks(out, "reloading the following units:")
837 assert_lacks(out, "\nrestarting the following units:")
838 assert_lacks(out, "\nstarting the following units:")
839 assert_contains(out, "the following new units were started: swapfile.swap")
840 # remove it
841 out = switch_to_specialisation("${machine}", "")
842 assert_contains(out, "stopping swap device: /swapfile")
843 assert_lacks(out, "stopping the following units:")
844 assert_lacks(out, "NOT restarting the following changed units:")
845 assert_lacks(out, "reloading the following units:")
846 assert_lacks(out, "\nrestarting the following units:")
847 assert_lacks(out, "\nstarting the following units:")
848 assert_lacks(out, "the following new units were started:")
849
850 with subtest("services"):
851 switch_to_specialisation("${machine}", "")
852 # Nothing happens when nothing is changed
853 out = switch_to_specialisation("${machine}", "")
854 assert_lacks(out, "stopping the following units:")
855 assert_lacks(out, "NOT restarting the following changed units:")
856 assert_lacks(out, "reloading the following units:")
857 assert_lacks(out, "\nrestarting the following units:")
858 assert_lacks(out, "\nstarting the following units:")
859 assert_lacks(out, "the following new units were started:")
860
861 # Start a simple service
862 out = switch_to_specialisation("${machine}", "simpleService")
863 assert_lacks(out, boot_loader_text) # test does not install a bootloader
864 assert_lacks(out, "stopping the following units:")
865 assert_lacks(out, "NOT restarting the following changed units:")
866 assert_lacks(out, "reloading the following units:")
867 assert_lacks(out, "\nrestarting the following units:")
868 assert_lacks(out, "\nstarting the following units:")
869 assert_contains(out, "the following new units were started: test.service\n")
870
871 # Not changing anything doesn't do anything
872 out = switch_to_specialisation("${machine}", "simpleService")
873 assert_lacks(out, "stopping the following units:")
874 assert_lacks(out, "NOT restarting the following changed units:")
875 assert_lacks(out, "reloading the following units:")
876 assert_lacks(out, "\nrestarting the following units:")
877 assert_lacks(out, "\nstarting the following units:")
878 assert_lacks(out, "the following new units were started:")
879
880 # Only changing the description does nothing
881 out = switch_to_specialisation("${machine}", "simpleServiceDifferentDescription")
882 assert_lacks(out, "stopping the following units:")
883 assert_lacks(out, "NOT restarting the following changed units:")
884 assert_lacks(out, "reloading the following units:")
885 assert_lacks(out, "\nrestarting the following units:")
886 assert_lacks(out, "\nstarting the following units:")
887 assert_lacks(out, "the following new units were started:")
888
889 # Restart the simple service
890 out = switch_to_specialisation("${machine}", "simpleServiceModified")
891 assert_contains(out, "stopping the following units: test.service\n")
892 assert_lacks(out, "NOT restarting the following changed units:")
893 assert_lacks(out, "reloading the following units:")
894 assert_lacks(out, "\nrestarting the following units:")
895 assert_contains(out, "\nstarting the following units: test.service\n")
896 assert_lacks(out, "the following new units were started:")
897
898 # Restart the service with stopIfChanged=false
899 out = switch_to_specialisation("${machine}", "simpleServiceNostop")
900 assert_lacks(out, "stopping the following units:")
901 assert_lacks(out, "NOT restarting the following changed units:")
902 assert_lacks(out, "reloading the following units:")
903 assert_contains(out, "\nrestarting the following units: test.service\n")
904 assert_lacks(out, "\nstarting the following units:")
905 assert_lacks(out, "the following new units were started:")
906
907 # Reload the service with reloadIfChanged=true
908 out = switch_to_specialisation("${machine}", "simpleServiceReload")
909 assert_lacks(out, "stopping the following units:")
910 assert_lacks(out, "NOT restarting the following changed units:")
911 assert_contains(out, "reloading the following units: test.service\n")
912 assert_lacks(out, "\nrestarting the following units:")
913 assert_lacks(out, "\nstarting the following units:")
914 assert_lacks(out, "the following new units were started:")
915
916 # Nothing happens when restartIfChanged=false
917 out = switch_to_specialisation("${machine}", "simpleServiceNorestart")
918 assert_lacks(out, "stopping the following units:")
919 assert_contains(out, "NOT restarting the following changed units: test.service\n")
920 assert_lacks(out, "reloading the following units:")
921 assert_lacks(out, "\nrestarting the following units:")
922 assert_lacks(out, "\nstarting the following units:")
923 assert_lacks(out, "the following new units were started:")
924
925 # Dry mode shows different messages
926 out = switch_to_specialisation("${machine}", "simpleService", action="dry-activate")
927 assert_lacks(out, "stopping the following units:")
928 assert_lacks(out, "NOT restarting the following changed units:")
929 assert_lacks(out, "reloading the following units:")
930 assert_lacks(out, "\nrestarting the following units:")
931 assert_lacks(out, "\nstarting the following units:")
932 assert_lacks(out, "the following new units were started:")
933 assert_contains(out, "would start the following units: test.service\n")
934
935 out = switch_to_specialisation("${machine}", "", action="test")
936
937 # Ensure the service can be started when the activation script isn't in toplevel
938 # This is a lot like "Start a simple service", except activation-only deps could be gc-ed
939 out = run_switch("${nodes.machine.specialisation.simpleServiceSeparateActivationScript.configuration.system.build.separateActivationScript}/bin/switch-to-configuration");
940 assert_lacks(out, boot_loader_text) # test does not install a bootloader
941 assert_lacks(out, "stopping the following units:")
942 assert_lacks(out, "NOT restarting the following changed units:")
943 assert_lacks(out, "reloading the following units:")
944 assert_lacks(out, "\nrestarting the following units:")
945 assert_lacks(out, "\nstarting the following units:")
946 assert_contains(out, "the following new units were started: test.service\n")
947 machine.succeed("! test -e /run/current-system/activate")
948 machine.succeed("! test -e /run/current-system/dry-activate")
949 machine.succeed("! test -e /run/current-system/bin/switch-to-configuration")
950
951 # Ensure units with multiline values work
952 out = switch_to_specialisation("${machine}", "unitWithMultilineValue")
953 assert_lacks(out, "NOT restarting the following changed units:")
954 assert_lacks(out, "reloading the following units:")
955 assert_lacks(out, "restarting the following units:")
956 assert_lacks(out, "the following new units were started:")
957 assert_contains(out, "starting the following units: test.service")
958
959 # Ensure \ works in unit names
960 out = switch_to_specialisation("${machine}", "unitWithBackslash")
961 assert_lacks(out, "NOT restarting the following changed units:")
962 assert_lacks(out, "reloading the following units:")
963 assert_lacks(out, "\nrestarting the following units:")
964 assert_lacks(out, "\nstarting the following units:")
965 assert_contains(out, "the following new units were started: escaped\\x2ddash.service\n")
966
967 out = switch_to_specialisation("${machine}", "unitWithBackslashModified")
968 assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
969 assert_lacks(out, "NOT restarting the following changed units:")
970 assert_lacks(out, "reloading the following units:")
971 assert_lacks(out, "\nrestarting the following units:")
972 assert_contains(out, "\nstarting the following units: escaped\\x2ddash.service\n")
973 assert_lacks(out, "the following new units were started:")
974
975 # Ensure units can start with a dash
976 out = switch_to_specialisation("${machine}", "unitStartingWithDash")
977 assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
978 assert_lacks(out, "NOT restarting the following changed units:")
979 assert_lacks(out, "reloading the following units:")
980 assert_lacks(out, "\nrestarting the following units:")
981 assert_lacks(out, "\nstarting the following units:")
982 assert_contains(out, "the following new units were started: -.service\n")
983
984 # The regression only occurs when reloading units
985 out = switch_to_specialisation("${machine}", "unitStartingWithDashModified")
986 assert_lacks(out, "stopping the following units:")
987 assert_lacks(out, "NOT restarting the following changed units:")
988 assert_contains(out, "reloading the following units: -.service")
989 assert_lacks(out, "\nrestarting the following units:")
990 assert_lacks(out, "\nstarting the following units:")
991 assert_lacks(out, "the following new units were started:")
992
993 # Ensure units that require changed units are properly reloaded
994 out = switch_to_specialisation("${machine}", "unitWithRequirement")
995 assert_contains(out, "stopping the following units: -.service\n")
996 assert_lacks(out, "NOT restarting the following changed units:")
997 assert_lacks(out, "reloading the following units:")
998 assert_lacks(out, "\nrestarting the following units:")
999 assert_lacks(out, "\nstarting the following units:")
1000 assert_contains(out, "the following new units were started: required-service.service, test-service.service\n")
1001
1002 out = switch_to_specialisation("${machine}", "unitWithRequirementModified")
1003 assert_contains(out, "stopping the following units: required-service.service\n")
1004 assert_lacks(out, "NOT restarting the following changed units:")
1005 assert_lacks(out, "reloading the following units:")
1006 assert_lacks(out, "\nrestarting the following units:")
1007 assert_contains(out, "\nstarting the following units: required-service.service, test-service.service\n")
1008 assert_lacks(out, "the following new units were started:")
1009
1010 # Unless the unit asks to be not restarted
1011 out = switch_to_specialisation("${machine}", "unitWithRequirementModifiedNostart")
1012 assert_contains(out, "stopping the following units: required-service.service\n")
1013 assert_lacks(out, "NOT restarting the following changed units:")
1014 assert_lacks(out, "reloading the following units:")
1015 assert_lacks(out, "\nrestarting the following units:")
1016 assert_contains(out, "\nstarting the following units: required-service.service\n")
1017 assert_lacks(out, "the following new units were started:")
1018
1019 # Ensure templated units are restarted when the base unit changes
1020 switch_to_specialisation("${machine}", "unitWithTemplate")
1021 out = switch_to_specialisation("${machine}", "unitWithTemplateModified")
1022 assert_contains(out, "stopping the following units: instantiated@one.service, instantiated@two.service\n")
1023 assert_lacks(out, "NOT restarting the following changed units:")
1024 assert_lacks(out, "reloading the following units:")
1025 assert_lacks(out, "\nrestarting the following units:")
1026 assert_contains(out, "\nstarting the following units: instantiated@one.service, instantiated@two.service\n")
1027 assert_lacks(out, "the following new units were started:")
1028
1029 with subtest("failing units"):
1030 # Let the simple service fail
1031 switch_to_specialisation("${machine}", "simpleServiceModified")
1032 out = switch_to_specialisation("${machine}", "simpleServiceFailing", fail=True)
1033 assert_contains(out, "stopping the following units: test.service\n")
1034 assert_lacks(out, "NOT restarting the following changed units:")
1035 assert_lacks(out, "reloading the following units:")
1036 assert_lacks(out, "\nrestarting the following units:")
1037 assert_contains(out, "\nstarting the following units: test.service\n")
1038 assert_lacks(out, "the following new units were started:")
1039 assert_contains(out, "warning: the following units failed: test.service\n")
1040 assert_contains(out, "Main PID:") # output of systemctl
1041
1042 # A unit that gets into autorestart without failing is not treated as failed
1043 out = switch_to_specialisation("${machine}", "autorestartService")
1044 assert_lacks(out, "stopping the following units:")
1045 assert_lacks(out, "NOT restarting the following changed units:")
1046 assert_lacks(out, "reloading the following units:")
1047 assert_lacks(out, "\nrestarting the following units:")
1048 assert_lacks(out, "\nstarting the following units:")
1049 assert_contains(out, "the following new units were started: autorestart.service\n")
1050 machine.systemctl('stop autorestart.service') # cancel the 20y timer
1051
1052 # Switching to the same system should do nothing (especially not treat the unit as failed)
1053 out = switch_to_specialisation("${machine}", "autorestartService")
1054 assert_lacks(out, "stopping the following units:")
1055 assert_lacks(out, "NOT restarting the following changed units:")
1056 assert_lacks(out, "reloading the following units:")
1057 assert_lacks(out, "\nrestarting the following units:")
1058 assert_lacks(out, "\nstarting the following units:")
1059 assert_contains(out, "the following new units were started: autorestart.service\n")
1060 machine.systemctl('stop autorestart.service') # cancel the 20y timer
1061
1062 # If systemd thinks the unit has failed and is in autorestart, we should show it as failed
1063 out = switch_to_specialisation("${machine}", "autorestartServiceFailing", fail=True)
1064 assert_lacks(out, "stopping the following units:")
1065 assert_lacks(out, "NOT restarting the following changed units:")
1066 assert_lacks(out, "reloading the following units:")
1067 assert_lacks(out, "\nrestarting the following units:")
1068 assert_lacks(out, "\nstarting the following units:")
1069 assert_lacks(out, "the following new units were started:")
1070 assert_contains(out, "warning: the following units failed: autorestart.service\n")
1071 assert_contains(out, "Main PID:") # output of systemctl
1072
1073 with subtest("unit file parser"):
1074 # Switch to a well-known state
1075 switch_to_specialisation("${machine}", "simpleServiceNostop")
1076
1077 # Add a section
1078 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSection")
1079 assert_lacks(out, "stopping the following units:")
1080 assert_lacks(out, "NOT restarting the following changed units:")
1081 assert_lacks(out, "reloading the following units:")
1082 assert_contains(out, "\nrestarting the following units: test.service\n")
1083 assert_lacks(out, "\nstarting the following units:")
1084 assert_lacks(out, "the following new units were started:")
1085
1086 # Rename it
1087 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSectionOtherName")
1088 assert_lacks(out, "stopping the following units:")
1089 assert_lacks(out, "NOT restarting the following changed units:")
1090 assert_lacks(out, "reloading the following units:")
1091 assert_contains(out, "\nrestarting the following units: test.service\n")
1092 assert_lacks(out, "\nstarting the following units:")
1093 assert_lacks(out, "the following new units were started:")
1094
1095 # Remove it
1096 out = switch_to_specialisation("${machine}", "simpleServiceNostop")
1097 assert_lacks(out, "stopping the following units:")
1098 assert_lacks(out, "NOT restarting the following changed units:")
1099 assert_lacks(out, "reloading the following units:")
1100 assert_contains(out, "\nrestarting the following units: test.service\n")
1101 assert_lacks(out, "\nstarting the following units:")
1102 assert_lacks(out, "the following new units were started:")
1103
1104 # [Install] section is ignored
1105 out = switch_to_specialisation("${machine}", "simpleServiceWithInstallSection")
1106 assert_lacks(out, "stopping the following units:")
1107 assert_lacks(out, "NOT restarting the following changed units:")
1108 assert_lacks(out, "reloading the following units:")
1109 assert_lacks(out, "\nrestarting the following units:")
1110 assert_lacks(out, "\nstarting the following units:")
1111 assert_lacks(out, "the following new units were started:")
1112
1113 # Add a key
1114 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKey")
1115 assert_lacks(out, "stopping the following units:")
1116 assert_lacks(out, "NOT restarting the following changed units:")
1117 assert_lacks(out, "reloading the following units:")
1118 assert_contains(out, "\nrestarting the following units: test.service\n")
1119 assert_lacks(out, "\nstarting the following units:")
1120 assert_lacks(out, "the following new units were started:")
1121
1122 # Change its value
1123 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherValue")
1124 assert_lacks(out, "stopping the following units:")
1125 assert_lacks(out, "NOT restarting the following changed units:")
1126 assert_lacks(out, "reloading the following units:")
1127 assert_contains(out, "\nrestarting the following units: test.service\n")
1128 assert_lacks(out, "\nstarting the following units:")
1129 assert_lacks(out, "the following new units were started:")
1130
1131 # Rename it
1132 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherName")
1133 assert_lacks(out, "stopping the following units:")
1134 assert_lacks(out, "NOT restarting the following changed units:")
1135 assert_lacks(out, "reloading the following units:")
1136 assert_contains(out, "\nrestarting the following units: test.service\n")
1137 assert_lacks(out, "\nstarting the following units:")
1138 assert_lacks(out, "the following new units were started:")
1139
1140 # Remove it
1141 out = switch_to_specialisation("${machine}", "simpleServiceNostop")
1142 assert_lacks(out, "stopping the following units:")
1143 assert_lacks(out, "NOT restarting the following changed units:")
1144 assert_lacks(out, "reloading the following units:")
1145 assert_contains(out, "\nrestarting the following units: test.service\n")
1146 assert_lacks(out, "\nstarting the following units:")
1147 assert_lacks(out, "the following new units were started:")
1148
1149 # Add a reload trigger
1150 out = switch_to_specialisation("${machine}", "simpleServiceReloadTrigger")
1151 assert_lacks(out, "stopping the following units:")
1152 assert_lacks(out, "NOT restarting the following changed units:")
1153 assert_contains(out, "reloading the following units: test.service\n")
1154 assert_lacks(out, "\nrestarting the following units:")
1155 assert_lacks(out, "\nstarting the following units:")
1156 assert_lacks(out, "the following new units were started:")
1157
1158 # Modify the reload trigger
1159 out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModified")
1160 assert_lacks(out, "stopping the following units:")
1161 assert_lacks(out, "NOT restarting the following changed units:")
1162 assert_contains(out, "reloading the following units: test.service\n")
1163 assert_lacks(out, "\nrestarting the following units:")
1164 assert_lacks(out, "\nstarting the following units:")
1165 assert_lacks(out, "the following new units were started:")
1166
1167 # Modify the reload trigger and something else
1168 out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedAndSomethingElse")
1169 assert_lacks(out, "stopping the following units:")
1170 assert_lacks(out, "NOT restarting the following changed units:")
1171 assert_lacks(out, "reloading the following units:")
1172 assert_contains(out, "\nrestarting the following units: test.service\n")
1173 assert_lacks(out, "\nstarting the following units:")
1174 assert_lacks(out, "the following new units were started:")
1175
1176 # Remove the reload trigger
1177 out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedSomethingElse")
1178 assert_lacks(out, "stopping the following units:")
1179 assert_lacks(out, "NOT restarting the following changed units:")
1180 assert_lacks(out, "reloading the following units:")
1181 assert_lacks(out, "\nrestarting the following units:")
1182 assert_lacks(out, "\nstarting the following units:")
1183 assert_lacks(out, "the following new units were started:")
1184
1185 with subtest("restart and reload by activation script"):
1186 switch_to_specialisation("${machine}", "simpleServiceNorestart")
1187 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
1188 assert_contains(out, "stopping the following units: test.service\n")
1189 assert_lacks(out, "NOT restarting the following changed units:")
1190 assert_lacks(out, "reloading the following units:")
1191 assert_lacks(out, "restarting the following units:")
1192 assert_contains(out, "\nstarting the following units: ${
1193 sortedUnits [
1194 "no-restart-service.service"
1195 "reload-triggers-and-restart-by-as.service"
1196 "simple-reload-service.service"
1197 "simple-restart-service.service"
1198 "simple-service.service"
1199 "templated-no-restart-service@instance.service"
1200 "templated-reload-triggers-and-restart-by-as@instance.service"
1201 "templated-simple-reload-service@instance.service"
1202 "templated-simple-restart-service@instance.service"
1203 "templated-simple-service@instance.service"
1204 ]
1205 }\n")
1206 assert_contains(out, "the following new units were started: ${
1207 sortedUnits [
1208 "no-restart-service.service"
1209 "reload-triggers-and-restart-by-as.service"
1210 "reload-triggers-and-restart.service"
1211 "reload-triggers.service"
1212 "simple-reload-service.service"
1213 "simple-restart-service.service"
1214 "simple-service.service"
1215 "system-templated\\\\x2dno\\\\x2drestart\\\\x2dservice.slice"
1216 "system-templated\\\\x2dreload\\\\x2dtriggers.slice"
1217 "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart.slice"
1218 "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart\\\\x2dby\\\\x2das.slice"
1219 "system-templated\\\\x2dsimple\\\\x2dreload\\\\x2dservice.slice"
1220 "system-templated\\\\x2dsimple\\\\x2drestart\\\\x2dservice.slice"
1221 "system-templated\\\\x2dsimple\\\\x2dservice.slice"
1222 "templated-no-restart-service@instance.service"
1223 "templated-reload-triggers-and-restart-by-as@instance.service"
1224 "templated-reload-triggers-and-restart@instance.service"
1225 "templated-reload-triggers@instance.service"
1226 "templated-simple-reload-service@instance.service"
1227 "templated-simple-restart-service@instance.service"
1228 "templated-simple-service@instance.service"
1229 ]
1230 }\n")
1231 # Switch to the same system where the example services get restarted
1232 # and reloaded by the activation script
1233 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
1234 assert_lacks(out, "stopping the following units:")
1235 assert_lacks(out, "NOT restarting the following changed units:")
1236 assert_contains(out, "reloading the following units: ${
1237 sortedUnits [
1238 "reload-triggers-and-restart.service"
1239 "reload-triggers.service"
1240 "simple-reload-service.service"
1241 "templated-reload-triggers-and-restart@instance.service"
1242 "templated-reload-triggers@instance.service"
1243 "templated-simple-reload-service@instance.service"
1244 ]
1245 }\n")
1246 assert_contains(out, "restarting the following units: ${
1247 sortedUnits [
1248 "reload-triggers-and-restart-by-as.service"
1249 "simple-restart-service.service"
1250 "simple-service.service"
1251 "templated-reload-triggers-and-restart-by-as@instance.service"
1252 "templated-simple-restart-service@instance.service"
1253 "templated-simple-service@instance.service"
1254 ]
1255 }\n")
1256 assert_lacks(out, "\nstarting the following units:")
1257 assert_lacks(out, "the following new units were started:")
1258 # Switch to the same system and see if the service gets restarted when it's modified
1259 # while the fact that it's supposed to be reloaded by the activation script is ignored.
1260 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified")
1261 assert_lacks(out, "stopping the following units:")
1262 assert_lacks(out, "NOT restarting the following changed units:")
1263 assert_contains(out, "reloading the following units: ${
1264 sortedUnits [
1265 "reload-triggers.service"
1266 "simple-reload-service.service"
1267 "templated-reload-triggers@instance.service"
1268 "templated-simple-reload-service@instance.service"
1269 ]
1270 }\n")
1271 assert_contains(out, "restarting the following units: ${
1272 sortedUnits [
1273 "reload-triggers-and-restart-by-as.service"
1274 "reload-triggers-and-restart.service"
1275 "simple-restart-service.service"
1276 "simple-service.service"
1277 "templated-reload-triggers-and-restart-by-as@instance.service"
1278 "templated-reload-triggers-and-restart@instance.service"
1279 "templated-simple-restart-service@instance.service"
1280 "templated-simple-service@instance.service"
1281 ]
1282 }\n")
1283 assert_lacks(out, "\nstarting the following units:")
1284 assert_lacks(out, "the following new units were started:")
1285 # The same, but in dry mode
1286 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate")
1287 assert_lacks(out, "would stop the following units:")
1288 assert_lacks(out, "would NOT stop the following changed units:")
1289 assert_contains(out, "would reload the following units: ${
1290 sortedUnits [
1291 "reload-triggers.service"
1292 "simple-reload-service.service"
1293 "templated-reload-triggers@instance.service"
1294 "templated-simple-reload-service@instance.service"
1295 ]
1296 }\n")
1297 assert_contains(out, "would restart the following units: ${
1298 sortedUnits [
1299 "reload-triggers-and-restart-by-as.service"
1300 "reload-triggers-and-restart.service"
1301 "simple-restart-service.service"
1302 "simple-service.service"
1303 "templated-reload-triggers-and-restart-by-as@instance.service"
1304 "templated-reload-triggers-and-restart@instance.service"
1305 "templated-simple-restart-service@instance.service"
1306 "templated-simple-service@instance.service"
1307 ]
1308 }\n")
1309 assert_lacks(out, "\nwould start the following units:")
1310
1311 with subtest("socket-activated services"):
1312 # Socket-activated services don't get started, just the socket
1313 machine.fail("[ -S /run/test.sock ]")
1314 out = switch_to_specialisation("${machine}", "simple-socket")
1315 # assert_lacks(out, "stopping the following units:") not relevant
1316 assert_lacks(out, "NOT restarting the following changed units:")
1317 assert_lacks(out, "reloading the following units:")
1318 assert_lacks(out, "\nrestarting the following units:")
1319 assert_lacks(out, "\nstarting the following units:")
1320 assert_contains(out, "the following new units were started: socket-activated.socket\n")
1321 machine.succeed("[ -S /run/test.sock ]")
1322
1323 # Changing a non-activated service does nothing
1324 out = switch_to_specialisation("${machine}", "simple-socket-service-modified")
1325 assert_lacks(out, "stopping the following units:")
1326 assert_lacks(out, "NOT restarting the following changed units:")
1327 assert_lacks(out, "reloading the following units:")
1328 assert_lacks(out, "\nrestarting the following units:")
1329 assert_lacks(out, "\nstarting the following units:")
1330 assert_lacks(out, "the following new units were started:")
1331 machine.succeed("[ -S /run/test.sock ]")
1332 # The unit is properly activated when the socket is accessed
1333 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1334 raise Exception("Socket was not properly activated") # idk how that would happen tbh
1335
1336 # Changing an activated service with stopIfChanged=false restarts the service
1337 out = switch_to_specialisation("${machine}", "simple-socket")
1338 assert_lacks(out, "stopping the following units:")
1339 assert_lacks(out, "NOT restarting the following changed units:")
1340 assert_lacks(out, "reloading the following units:")
1341 assert_contains(out, "\nrestarting the following units: socket-activated.service\n")
1342 assert_lacks(out, "\nstarting the following units:")
1343 assert_lacks(out, "the following new units were started:")
1344 machine.succeed("[ -S /run/test.sock ]")
1345 # Socket-activation of the unit still works
1346 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1347 raise Exception("Socket was not properly activated after the service was restarted")
1348
1349 # Changing an activated service with stopIfChanged=true stops the service and
1350 # socket and starts the socket
1351 out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed")
1352 assert_contains(out, "stopping the following units: socket-activated.service, socket-activated.socket\n")
1353 assert_lacks(out, "NOT restarting the following changed units:")
1354 assert_lacks(out, "reloading the following units:")
1355 assert_lacks(out, "\nrestarting the following units:")
1356 assert_contains(out, "\nstarting the following units: socket-activated.socket\n")
1357 assert_lacks(out, "the following new units were started:")
1358 machine.succeed("[ -S /run/test.sock ]")
1359 # Socket-activation of the unit still works
1360 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1361 raise Exception("Socket was not properly activated after the service was restarted")
1362
1363 # Changing a reload trigger of a socket-activated unit only reloads it
1364 out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed-and-reloadtrigger")
1365 assert_lacks(out, "stopping the following units:")
1366 assert_lacks(out, "NOT restarting the following changed units:")
1367 assert_contains(out, "reloading the following units: socket-activated.service\n")
1368 assert_lacks(out, "\nrestarting the following units:")
1369 assert_lacks(out, "\nstarting the following units: socket-activated.socket")
1370 assert_lacks(out, "the following new units were started:")
1371 machine.succeed("[ -S /run/test.sock ]")
1372 # Socket-activation of the unit still works
1373 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
1374 raise Exception("Socket was not properly activated after the service was restarted")
1375
1376 with subtest("mounts"):
1377 switch_to_specialisation("${machine}", "mount")
1378 out = machine.succeed("mount | grep 'on /testmount'")
1379 assert_contains(out, "size=1024k")
1380 # Changing options reloads the unit
1381 out = switch_to_specialisation("${machine}", "mountOptionsModified")
1382 assert_lacks(out, "stopping the following units:")
1383 assert_lacks(out, "NOT restarting the following changed units:")
1384 assert_contains(out, "reloading the following units: testmount.mount\n")
1385 assert_lacks(out, "\nrestarting the following units:")
1386 assert_lacks(out, "\nstarting the following units:")
1387 assert_lacks(out, "the following new units were started:")
1388 # It changed
1389 out = machine.succeed("mount | grep 'on /testmount'")
1390 assert_contains(out, "size=10240k")
1391 # Changing anything but `Options=` restarts the unit
1392 out = switch_to_specialisation("${machine}", "mountModified")
1393 assert_lacks(out, "stopping the following units:")
1394 assert_lacks(out, "NOT restarting the following changed units:")
1395 assert_lacks(out, "reloading the following units:")
1396 assert_contains(out, "\nrestarting the following units: testmount.mount\n")
1397 assert_lacks(out, "\nstarting the following units:")
1398 assert_lacks(out, "the following new units were started:")
1399 # It changed
1400 out = machine.succeed("mount | grep 'on /testmount'")
1401 assert_contains(out, "ramfs")
1402
1403 with subtest("timers"):
1404 switch_to_specialisation("${machine}", "timer")
1405 out = machine.succeed("systemctl show test-timer.timer")
1406 assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC")
1407 out = switch_to_specialisation("${machine}", "timerModified")
1408 assert_lacks(out, "stopping the following units:")
1409 assert_lacks(out, "NOT restarting the following units:")
1410 assert_lacks(out, "reloading the following units:")
1411 assert_contains(out, "\nrestarting the following units: test-timer.timer\n")
1412 assert_lacks(out, "\nstarting the following units:")
1413 assert_lacks(out, "the following new units were started:")
1414 # It changed
1415 out = machine.succeed("systemctl show test-timer.timer")
1416 assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00")
1417
1418 with subtest("targets"):
1419 # Modifying some special targets like hybrid-sleep.target does nothing
1420 out = switch_to_specialisation("${machine}", "hybridSleepModified")
1421 assert_contains(out, "stopping the following units: test-timer.timer\n")
1422 assert_lacks(out, "NOT restarting the following changed units:")
1423 assert_lacks(out, "reloading the following units:")
1424 assert_lacks(out, "\nrestarting the following units:")
1425 assert_lacks(out, "\nstarting the following units:")
1426 assert_lacks(out, "the following new units were started:")
1427
1428 # Adding a new target starts it
1429 out = switch_to_specialisation("${machine}", "target")
1430 assert_lacks(out, "stopping the following units:")
1431 assert_lacks(out, "NOT restarting the following changed units:")
1432 assert_lacks(out, "reloading the following units:")
1433 assert_lacks(out, "\nrestarting the following units:")
1434 assert_lacks(out, "\nstarting the following units:")
1435 assert_contains(out, "the following new units were started: test-target.target\n")
1436
1437 # Changing a target doesn't print anything because the unit is filtered
1438 machine.systemctl("start test-service.service")
1439 out = switch_to_specialisation("${machine}", "targetModified")
1440 assert_lacks(out, "stopping the following units:")
1441 assert_lacks(out, "NOT restarting the following changed units:")
1442 assert_lacks(out, "reloading the following units:")
1443 assert_lacks(out, "\nrestarting the following units:")
1444 assert_lacks(out, "\nstarting the following units:")
1445 assert_lacks(out, "the following new units were started:")
1446 machine.succeed("systemctl is-active test-service.service") # target was not restarted
1447
1448 # With X-StopOnReconfiguration, the target gets stopped and started
1449 out = switch_to_specialisation("${machine}", "targetModifiedStopOnReconfig")
1450 assert_lacks(out, "stopping the following units:")
1451 assert_lacks(out, "NOT restarting the following changed units:")
1452 assert_lacks(out, "reloading the following units:")
1453 assert_lacks(out, "\nrestarting the following units:")
1454 assert_lacks(out, "\nstarting the following units:")
1455 assert_lacks(out, "the following new units were started:")
1456 machine.fail("systemctl is-active test-service.servce") # target was restarted
1457
1458 # Remove the target by switching to the old specialisation
1459 out = switch_to_specialisation("${machine}", "timerModified")
1460 assert_contains(out, "stopping the following units: test-target.target\n")
1461 assert_lacks(out, "NOT restarting the following changed units:")
1462 assert_lacks(out, "reloading the following units:")
1463 assert_lacks(out, "\nrestarting the following units:")
1464 assert_lacks(out, "\nstarting the following units:")
1465 assert_contains(out, "the following new units were started: test-timer.timer\n")
1466
1467 with subtest("paths"):
1468 out = switch_to_specialisation("${machine}", "path")
1469 assert_contains(out, "stopping the following units: test-timer.timer\n")
1470 assert_lacks(out, "NOT restarting the following changed units:")
1471 assert_lacks(out, "reloading the following units:")
1472 assert_lacks(out, "\nrestarting the following units:")
1473 assert_lacks(out, "\nstarting the following units:")
1474 assert_contains(out, "the following new units were started: test-watch.path\n")
1475 machine.fail("test -f /testpath-modified")
1476
1477 # touch the file, unit should be triggered
1478 machine.succeed("touch /testpath")
1479 machine.wait_until_succeeds("test -f /testpath-modified")
1480 machine.succeed("rm /testpath /testpath-modified")
1481 machine.systemctl("stop test-watch.service")
1482 switch_to_specialisation("${machine}", "pathModified")
1483 machine.succeed("touch /testpath")
1484 machine.fail("test -f /testpath-modified")
1485 machine.succeed("touch /testpath2")
1486 machine.wait_until_succeeds("test -f /testpath-modified")
1487
1488 # This test ensures that changes to slice configuration get applied.
1489 # We test this by having a slice that allows no memory allocation at
1490 # all and starting a service within it. If the service crashes, the slice
1491 # is applied and if we modify the slice to allow memory allocation, the
1492 # service should successfully start.
1493 with subtest("slices"):
1494 machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom") # allow OOMing
1495 out = switch_to_specialisation("${machine}", "slice")
1496 # assert_lacks(out, "stopping the following units:") not relevant
1497 assert_lacks(out, "NOT restarting the following changed units:")
1498 assert_lacks(out, "reloading the following units:")
1499 assert_lacks(out, "\nrestarting the following units:")
1500 assert_lacks(out, "\nstarting the following units:")
1501 assert_lacks(out, "the following new units were started:")
1502 machine.fail("systemctl start testservice.service")
1503
1504 out = switch_to_specialisation("${machine}", "sliceModified")
1505 assert_lacks(out, "stopping the following units:")
1506 assert_lacks(out, "NOT restarting the following changed units:")
1507 assert_lacks(out, "reloading the following units:")
1508 assert_lacks(out, "\nrestarting the following units:")
1509 assert_lacks(out, "\nstarting the following units:")
1510 assert_lacks(out, "the following new units were started:")
1511 machine.succeed("systemctl start testservice.service")
1512 machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom") # disallow OOMing
1513
1514 with subtest("dbus reloads"):
1515 out = switch_to_specialisation("${machine}", "")
1516 out = switch_to_specialisation("${machine}", "dbusReload")
1517 assert_lacks(out, "stopping the following units:")
1518 assert_lacks(out, "NOT restarting the following changed units:")
1519 assert_contains(out, "reloading the following units: ${dbusService}\n")
1520 assert_lacks(out, "\nrestarting the following units:")
1521 assert_lacks(out, "\nstarting the following units:")
1522 assert_lacks(out, "the following new units were started:")
1523 '';
1524}