at master 75 kB view raw
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}