at 23.11-pre 53 kB view raw
1# Test configuration switching. 2 3import ./make-test-python.nix ({ pkgs, ...} : let 4 5 # Simple service that can either be socket-activated or that will 6 # listen on port 1234 if not socket-activated. 7 # A connection to the socket causes 'hello' to be written to the client. 8 socketTest = pkgs.writeScript "socket-test.py" /* python */ '' 9 #!${pkgs.python3}/bin/python3 10 11 from socketserver import TCPServer, StreamRequestHandler 12 import socket 13 import os 14 15 16 class Handler(StreamRequestHandler): 17 def handle(self): 18 self.wfile.write("hello".encode("utf-8")) 19 20 21 class Server(TCPServer): 22 def __init__(self, server_address, handler_cls): 23 listenFds = os.getenv('LISTEN_FDS') 24 if listenFds is None or int(listenFds) < 1: 25 print(f'Binding to {server_address}') 26 TCPServer.__init__( 27 self, server_address, handler_cls, bind_and_activate=True) 28 else: 29 TCPServer.__init__( 30 self, server_address, handler_cls, bind_and_activate=False) 31 # Override socket 32 print(f'Got activated by {os.getenv("LISTEN_FDNAMES")} ' 33 f'with {listenFds} FDs') 34 self.socket = socket.fromfd(3, self.address_family, 35 self.socket_type) 36 37 38 if __name__ == "__main__": 39 server = Server(("localhost", 1234), Handler) 40 server.serve_forever() 41 ''; 42 43in { 44 name = "switch-test"; 45 meta = with pkgs.lib.maintainers; { 46 maintainers = [ gleber das_j ]; 47 }; 48 49 nodes = { 50 machine = { pkgs, lib, ... }: { 51 environment.systemPackages = [ pkgs.socat ]; # for the socket activation stuff 52 users.mutableUsers = false; 53 54 # For boot/switch testing 55 system.build.installBootLoader = lib.mkForce (pkgs.writeShellScript "install-dummy-loader" '' 56 echo "installing dummy bootloader" 57 touch /tmp/bootloader-installed 58 ''); 59 60 specialisation = rec { 61 simpleService.configuration = { 62 systemd.services.test = { 63 wantedBy = [ "multi-user.target" ]; 64 serviceConfig = { 65 Type = "oneshot"; 66 RemainAfterExit = true; 67 ExecStart = "${pkgs.coreutils}/bin/true"; 68 ExecReload = "${pkgs.coreutils}/bin/true"; 69 }; 70 }; 71 }; 72 73 simpleServiceDifferentDescription.configuration = { 74 imports = [ simpleService.configuration ]; 75 systemd.services.test.description = "Test unit"; 76 }; 77 78 simpleServiceModified.configuration = { 79 imports = [ simpleService.configuration ]; 80 systemd.services.test.serviceConfig.X-Test = true; 81 }; 82 83 simpleServiceNostop.configuration = { 84 imports = [ simpleService.configuration ]; 85 systemd.services.test.stopIfChanged = false; 86 }; 87 88 simpleServiceReload.configuration = { 89 imports = [ simpleService.configuration ]; 90 systemd.services.test = { 91 reloadIfChanged = true; 92 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true"; 93 }; 94 }; 95 96 simpleServiceNorestart.configuration = { 97 imports = [ simpleService.configuration ]; 98 systemd.services.test.restartIfChanged = false; 99 }; 100 101 simpleServiceFailing.configuration = { 102 imports = [ simpleServiceModified.configuration ]; 103 systemd.services.test.serviceConfig.ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false"; 104 }; 105 106 autorestartService.configuration = { 107 # A service that immediately goes into restarting (but without failing) 108 systemd.services.autorestart = { 109 wantedBy = [ "multi-user.target" ]; 110 serviceConfig = { 111 Type = "simple"; 112 Restart = "always"; 113 RestartSec = "20y"; # Should be long enough 114 ExecStart = "${pkgs.coreutils}/bin/true"; 115 }; 116 }; 117 }; 118 119 autorestartServiceFailing.configuration = { 120 imports = [ autorestartService.configuration ]; 121 systemd.services.autorestart.serviceConfig = { 122 ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false"; 123 }; 124 }; 125 126 simpleServiceWithExtraSection.configuration = { 127 imports = [ simpleServiceNostop.configuration ]; 128 systemd.packages = [ (pkgs.writeTextFile { 129 name = "systemd-extra-section"; 130 destination = "/etc/systemd/system/test.service"; 131 text = '' 132 [X-Test] 133 X-Test-Value=a 134 ''; 135 }) ]; 136 }; 137 138 simpleServiceWithExtraSectionOtherName.configuration = { 139 imports = [ simpleServiceNostop.configuration ]; 140 systemd.packages = [ (pkgs.writeTextFile { 141 name = "systemd-extra-section"; 142 destination = "/etc/systemd/system/test.service"; 143 text = '' 144 [X-Test2] 145 X-Test-Value=a 146 ''; 147 }) ]; 148 }; 149 150 simpleServiceWithInstallSection.configuration = { 151 imports = [ simpleServiceNostop.configuration ]; 152 systemd.packages = [ (pkgs.writeTextFile { 153 name = "systemd-extra-section"; 154 destination = "/etc/systemd/system/test.service"; 155 text = '' 156 [Install] 157 WantedBy=multi-user.target 158 ''; 159 }) ]; 160 }; 161 162 simpleServiceWithExtraKey.configuration = { 163 imports = [ simpleServiceNostop.configuration ]; 164 systemd.services.test.serviceConfig."X-Test" = "test"; 165 }; 166 167 simpleServiceWithExtraKeyOtherValue.configuration = { 168 imports = [ simpleServiceNostop.configuration ]; 169 systemd.services.test.serviceConfig."X-Test" = "test2"; 170 }; 171 172 simpleServiceWithExtraKeyOtherName.configuration = { 173 imports = [ simpleServiceNostop.configuration ]; 174 systemd.services.test.serviceConfig."X-Test2" = "test"; 175 }; 176 177 simpleServiceReloadTrigger.configuration = { 178 imports = [ simpleServiceNostop.configuration ]; 179 systemd.services.test.reloadTriggers = [ "/dev/null" ]; 180 }; 181 182 simpleServiceReloadTriggerModified.configuration = { 183 imports = [ simpleServiceNostop.configuration ]; 184 systemd.services.test.reloadTriggers = [ "/dev/zero" ]; 185 }; 186 187 simpleServiceReloadTriggerModifiedAndSomethingElse.configuration = { 188 imports = [ simpleServiceNostop.configuration ]; 189 systemd.services.test = { 190 reloadTriggers = [ "/dev/zero" ]; 191 serviceConfig."X-Test" = "test"; 192 }; 193 }; 194 195 simpleServiceReloadTriggerModifiedSomethingElse.configuration = { 196 imports = [ simpleServiceNostop.configuration ]; 197 systemd.services.test.serviceConfig."X-Test" = "test"; 198 }; 199 200 unitWithBackslash.configuration = { 201 systemd.services."escaped\\x2ddash" = { 202 wantedBy = [ "multi-user.target" ]; 203 serviceConfig = { 204 Type = "oneshot"; 205 RemainAfterExit = true; 206 ExecStart = "${pkgs.coreutils}/bin/true"; 207 ExecReload = "${pkgs.coreutils}/bin/true"; 208 }; 209 }; 210 }; 211 212 unitWithBackslashModified.configuration = { 213 imports = [ unitWithBackslash.configuration ]; 214 systemd.services."escaped\\x2ddash".serviceConfig.X-Test = "test"; 215 }; 216 217 unitStartingWithDash.configuration = { 218 systemd.services."-" = { 219 wantedBy = [ "multi-user.target" ]; 220 serviceConfig = { 221 Type = "oneshot"; 222 RemainAfterExit = true; 223 ExecStart = "${pkgs.coreutils}/bin/true"; 224 }; 225 }; 226 }; 227 228 unitStartingWithDashModified.configuration = { 229 imports = [ unitStartingWithDash.configuration ]; 230 systemd.services."-" = { 231 reloadIfChanged = true; 232 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true"; 233 }; 234 }; 235 236 unitWithRequirement.configuration = { 237 systemd.services.required-service = { 238 wantedBy = [ "multi-user.target" ]; 239 serviceConfig = { 240 Type = "oneshot"; 241 RemainAfterExit = true; 242 ExecStart = "${pkgs.coreutils}/bin/true"; 243 ExecReload = "${pkgs.coreutils}/bin/true"; 244 }; 245 }; 246 systemd.services.test-service = { 247 wantedBy = [ "multi-user.target" ]; 248 requires = [ "required-service.service" ]; 249 serviceConfig = { 250 Type = "oneshot"; 251 RemainAfterExit = true; 252 ExecStart = "${pkgs.coreutils}/bin/true"; 253 ExecReload = "${pkgs.coreutils}/bin/true"; 254 }; 255 }; 256 }; 257 258 unitWithRequirementModified.configuration = { 259 imports = [ unitWithRequirement.configuration ]; 260 systemd.services.required-service.serviceConfig.X-Test = "test"; 261 systemd.services.test-service.reloadTriggers = [ "test" ]; 262 }; 263 264 unitWithRequirementModifiedNostart.configuration = { 265 imports = [ unitWithRequirement.configuration ]; 266 systemd.services.test-service.unitConfig.RefuseManualStart = true; 267 }; 268 269 restart-and-reload-by-activation-script.configuration = { 270 systemd.services = rec { 271 simple-service = { 272 # No wantedBy so we can check if the activation script restart triggers them 273 serviceConfig = { 274 Type = "oneshot"; 275 RemainAfterExit = true; 276 ExecStart = "${pkgs.coreutils}/bin/true"; 277 ExecReload = "${pkgs.coreutils}/bin/true"; 278 }; 279 }; 280 281 simple-restart-service = simple-service // { 282 stopIfChanged = false; 283 }; 284 285 simple-reload-service = simple-service // { 286 reloadIfChanged = true; 287 }; 288 289 no-restart-service = simple-service // { 290 restartIfChanged = false; 291 }; 292 293 reload-triggers = simple-service // { 294 wantedBy = [ "multi-user.target" ]; 295 }; 296 297 reload-triggers-and-restart-by-as = simple-service; 298 299 reload-triggers-and-restart = simple-service // { 300 stopIfChanged = false; # easier to check for this 301 wantedBy = [ "multi-user.target" ]; 302 }; 303 }; 304 305 system.activationScripts.restart-and-reload-test = { 306 supportsDryActivation = true; 307 deps = []; 308 text = '' 309 if [ "$NIXOS_ACTION" = dry-activate ]; then 310 f=/run/nixos/dry-activation-restart-list 311 g=/run/nixos/dry-activation-reload-list 312 else 313 f=/run/nixos/activation-restart-list 314 g=/run/nixos/activation-reload-list 315 fi 316 cat <<EOF >> "$f" 317 simple-service.service 318 simple-restart-service.service 319 simple-reload-service.service 320 no-restart-service.service 321 reload-triggers-and-restart-by-as.service 322 EOF 323 324 cat <<EOF >> "$g" 325 reload-triggers.service 326 reload-triggers-and-restart-by-as.service 327 reload-triggers-and-restart.service 328 EOF 329 ''; 330 }; 331 }; 332 333 restart-and-reload-by-activation-script-modified.configuration = { 334 imports = [ restart-and-reload-by-activation-script.configuration ]; 335 systemd.services.reload-triggers-and-restart.serviceConfig.X-Modified = "test"; 336 }; 337 338 simple-socket.configuration = { 339 systemd.services.socket-activated = { 340 description = "A socket-activated service"; 341 stopIfChanged = lib.mkDefault false; 342 serviceConfig = { 343 ExecStart = socketTest; 344 ExecReload = "${pkgs.coreutils}/bin/true"; 345 }; 346 }; 347 systemd.sockets.socket-activated = { 348 wantedBy = [ "sockets.target" ]; 349 listenStreams = [ "/run/test.sock" ]; 350 socketConfig.SocketMode = lib.mkDefault "0777"; 351 }; 352 }; 353 354 simple-socket-service-modified.configuration = { 355 imports = [ simple-socket.configuration ]; 356 systemd.services.socket-activated.serviceConfig.X-Test = "test"; 357 }; 358 359 simple-socket-stop-if-changed.configuration = { 360 imports = [ simple-socket.configuration ]; 361 systemd.services.socket-activated.stopIfChanged = true; 362 }; 363 364 simple-socket-stop-if-changed-and-reloadtrigger.configuration = { 365 imports = [ simple-socket.configuration ]; 366 systemd.services.socket-activated = { 367 stopIfChanged = true; 368 reloadTriggers = [ "test" ]; 369 }; 370 }; 371 372 mount.configuration = { 373 systemd.mounts = [ 374 { 375 description = "Testmount"; 376 what = "tmpfs"; 377 type = "tmpfs"; 378 where = "/testmount"; 379 options = "size=1M"; 380 wantedBy = [ "local-fs.target" ]; 381 } 382 ]; 383 }; 384 385 mountModified.configuration = { 386 systemd.mounts = [ 387 { 388 description = "Testmount"; 389 what = "tmpfs"; 390 type = "tmpfs"; 391 where = "/testmount"; 392 options = "size=10M"; 393 wantedBy = [ "local-fs.target" ]; 394 } 395 ]; 396 }; 397 398 timer.configuration = { 399 systemd.timers.test-timer = { 400 wantedBy = [ "timers.target" ]; 401 timerConfig.OnCalendar = "@1395716396"; # chosen by fair dice roll 402 }; 403 systemd.services.test-timer = { 404 serviceConfig = { 405 Type = "oneshot"; 406 ExecStart = "${pkgs.coreutils}/bin/true"; 407 }; 408 }; 409 }; 410 411 timerModified.configuration = { 412 imports = [ timer.configuration ]; 413 systemd.timers.test-timer.timerConfig.OnCalendar = lib.mkForce "Fri 2012-11-23 16:00:00"; 414 }; 415 416 hybridSleepModified.configuration = { 417 systemd.targets.hybrid-sleep.unitConfig.X-Test = true; 418 }; 419 420 target.configuration = { 421 systemd.targets.test-target.wantedBy = [ "multi-user.target" ]; 422 # We use this service to figure out whether the target was modified. 423 # This is the only way because targets are filtered and therefore not 424 # printed when they are started/stopped. 425 systemd.services.test-service = { 426 bindsTo = [ "test-target.target" ]; 427 serviceConfig.ExecStart = "${pkgs.coreutils}/bin/sleep infinity"; 428 }; 429 }; 430 431 targetModified.configuration = { 432 imports = [ target.configuration ]; 433 systemd.targets.test-target.unitConfig.X-Test = true; 434 }; 435 436 targetModifiedStopOnReconfig.configuration = { 437 imports = [ target.configuration ]; 438 systemd.targets.test-target.unitConfig.X-StopOnReconfiguration = true; 439 }; 440 441 path.configuration = { 442 systemd.paths.test-watch = { 443 wantedBy = [ "paths.target" ]; 444 pathConfig.PathExists = "/testpath"; 445 }; 446 systemd.services.test-watch = { 447 serviceConfig = { 448 Type = "oneshot"; 449 RemainAfterExit = true; 450 ExecStart = "${pkgs.coreutils}/bin/touch /testpath-modified"; 451 }; 452 }; 453 }; 454 455 pathModified.configuration = { 456 imports = [ path.configuration ]; 457 systemd.paths.test-watch.pathConfig.PathExists = lib.mkForce "/testpath2"; 458 }; 459 460 slice.configuration = { 461 systemd.slices.testslice.sliceConfig.MemoryMax = "1"; # don't allow memory allocation 462 systemd.services.testservice = { 463 serviceConfig = { 464 Type = "oneshot"; 465 RemainAfterExit = true; 466 ExecStart = "${pkgs.coreutils}/bin/true"; 467 Slice = "testslice.slice"; 468 }; 469 }; 470 }; 471 472 sliceModified.configuration = { 473 imports = [ slice.configuration ]; 474 systemd.slices.testslice.sliceConfig.MemoryMax = lib.mkForce null; 475 }; 476 }; 477 }; 478 479 other = { 480 users.mutableUsers = true; 481 }; 482 }; 483 484 testScript = { nodes, ... }: let 485 originalSystem = nodes.machine.config.system.build.toplevel; 486 otherSystem = nodes.other.config.system.build.toplevel; 487 machine = nodes.machine.config.system.build.toplevel; 488 489 # Ensures failures pass through using pipefail, otherwise failing to 490 # switch-to-configuration is hidden by the success of `tee`. 491 stderrRunner = pkgs.writeScript "stderr-runner" '' 492 #! ${pkgs.runtimeShell} 493 set -e 494 set -o pipefail 495 exec env -i "$@" | tee /dev/stderr 496 ''; 497 in /* python */ '' 498 def switch_to_specialisation(system, name, action="test", fail=False): 499 if name == "": 500 stc = f"{system}/bin/switch-to-configuration" 501 else: 502 stc = f"{system}/specialisation/{name}/bin/switch-to-configuration" 503 out = machine.fail(f"{stc} {action} 2>&1") if fail \ 504 else machine.succeed(f"{stc} {action} 2>&1") 505 assert_lacks(out, "switch-to-configuration line") # Perl warnings 506 return out 507 508 def assert_contains(haystack, needle): 509 if needle not in haystack: 510 print("The haystack that will cause the following exception is:") 511 print("---") 512 print(haystack) 513 print("---") 514 raise Exception(f"Expected string '{needle}' was not found") 515 516 def assert_lacks(haystack, needle): 517 if needle in haystack: 518 print("The haystack that will cause the following exception is:") 519 print("---") 520 print(haystack, end="") 521 print("---") 522 raise Exception(f"Unexpected string '{needle}' was found") 523 524 525 machine.wait_for_unit("multi-user.target") 526 527 machine.succeed( 528 "${stderrRunner} ${originalSystem}/bin/switch-to-configuration test" 529 ) 530 # This tests whether the /etc/os-release parser works which is a fallback 531 # when /etc/NIXOS is missing. If the parser does not work, switch-to-configuration 532 # would fail. 533 machine.succeed("rm /etc/NIXOS") 534 machine.succeed( 535 "${stderrRunner} ${otherSystem}/bin/switch-to-configuration test" 536 ) 537 538 539 with subtest("actions"): 540 # boot action 541 machine.fail("test -f /tmp/bootloader-installed") 542 out = switch_to_specialisation("${machine}", "simpleService", action="boot") 543 assert_contains(out, "installing dummy bootloader") 544 assert_lacks(out, "activating the configuration...") # good indicator of a system activation 545 machine.succeed("test -f /tmp/bootloader-installed") 546 machine.succeed("rm /tmp/bootloader-installed") 547 548 # switch action 549 machine.fail("test -f /tmp/bootloader-installed") 550 out = switch_to_specialisation("${machine}", "", action="switch") 551 assert_contains(out, "installing dummy bootloader") 552 assert_contains(out, "activating the configuration...") # good indicator of a system activation 553 machine.succeed("test -f /tmp/bootloader-installed") 554 555 # test and dry-activate actions are tested further down below 556 557 with subtest("services"): 558 switch_to_specialisation("${machine}", "") 559 # Nothing happens when nothing is changed 560 out = switch_to_specialisation("${machine}", "") 561 assert_lacks(out, "stopping the following units:") 562 assert_lacks(out, "NOT restarting the following changed units:") 563 assert_lacks(out, "reloading the following units:") 564 assert_lacks(out, "\nrestarting the following units:") 565 assert_lacks(out, "\nstarting the following units:") 566 assert_lacks(out, "the following new units were started:") 567 568 # Start a simple service 569 out = switch_to_specialisation("${machine}", "simpleService") 570 assert_lacks(out, "installing dummy bootloader") # test does not install a bootloader 571 assert_lacks(out, "stopping the following units:") 572 assert_lacks(out, "NOT restarting the following changed units:") 573 assert_contains(out, "reloading the following units: dbus.service\n") # huh 574 assert_lacks(out, "\nrestarting the following units:") 575 assert_lacks(out, "\nstarting the following units:") 576 assert_contains(out, "the following new units were started: test.service\n") 577 578 # Not changing anything doesn't do anything 579 out = switch_to_specialisation("${machine}", "simpleService") 580 assert_lacks(out, "stopping the following units:") 581 assert_lacks(out, "NOT restarting the following changed units:") 582 assert_lacks(out, "reloading the following units:") 583 assert_lacks(out, "\nrestarting the following units:") 584 assert_lacks(out, "\nstarting the following units:") 585 assert_lacks(out, "the following new units were started:") 586 587 # Only changing the description does nothing 588 out = switch_to_specialisation("${machine}", "simpleServiceDifferentDescription") 589 assert_lacks(out, "stopping the following units:") 590 assert_lacks(out, "NOT restarting the following changed units:") 591 assert_lacks(out, "reloading the following units:") 592 assert_lacks(out, "\nrestarting the following units:") 593 assert_lacks(out, "\nstarting the following units:") 594 assert_lacks(out, "the following new units were started:") 595 596 # Restart the simple service 597 out = switch_to_specialisation("${machine}", "simpleServiceModified") 598 assert_contains(out, "stopping the following units: test.service\n") 599 assert_lacks(out, "NOT restarting the following changed units:") 600 assert_lacks(out, "reloading the following units:") 601 assert_lacks(out, "\nrestarting the following units:") 602 assert_contains(out, "\nstarting the following units: test.service\n") 603 assert_lacks(out, "the following new units were started:") 604 605 # Restart the service with stopIfChanged=false 606 out = switch_to_specialisation("${machine}", "simpleServiceNostop") 607 assert_lacks(out, "stopping the following units:") 608 assert_lacks(out, "NOT restarting the following changed units:") 609 assert_lacks(out, "reloading the following units:") 610 assert_contains(out, "\nrestarting the following units: test.service\n") 611 assert_lacks(out, "\nstarting the following units:") 612 assert_lacks(out, "the following new units were started:") 613 614 # Reload the service with reloadIfChanged=true 615 out = switch_to_specialisation("${machine}", "simpleServiceReload") 616 assert_lacks(out, "stopping the following units:") 617 assert_lacks(out, "NOT restarting the following changed units:") 618 assert_contains(out, "reloading the following units: test.service\n") 619 assert_lacks(out, "\nrestarting the following units:") 620 assert_lacks(out, "\nstarting the following units:") 621 assert_lacks(out, "the following new units were started:") 622 623 # Nothing happens when restartIfChanged=false 624 out = switch_to_specialisation("${machine}", "simpleServiceNorestart") 625 assert_lacks(out, "stopping the following units:") 626 assert_contains(out, "NOT restarting the following changed units: test.service\n") 627 assert_lacks(out, "reloading the following units:") 628 assert_lacks(out, "\nrestarting the following units:") 629 assert_lacks(out, "\nstarting the following units:") 630 assert_lacks(out, "the following new units were started:") 631 632 # Dry mode shows different messages 633 out = switch_to_specialisation("${machine}", "simpleService", action="dry-activate") 634 assert_lacks(out, "stopping the following units:") 635 assert_lacks(out, "NOT restarting the following changed units:") 636 assert_lacks(out, "reloading the following units:") 637 assert_lacks(out, "\nrestarting the following units:") 638 assert_lacks(out, "\nstarting the following units:") 639 assert_lacks(out, "the following new units were started:") 640 assert_contains(out, "would start the following units: test.service\n") 641 642 # Ensure \ works in unit names 643 out = switch_to_specialisation("${machine}", "unitWithBackslash") 644 assert_contains(out, "stopping the following units: test.service\n") 645 assert_lacks(out, "NOT restarting the following changed units:") 646 assert_lacks(out, "reloading the following units:") 647 assert_lacks(out, "\nrestarting the following units:") 648 assert_lacks(out, "\nstarting the following units:") 649 assert_contains(out, "the following new units were started: escaped\\x2ddash.service\n") 650 651 out = switch_to_specialisation("${machine}", "unitWithBackslashModified") 652 assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n") 653 assert_lacks(out, "NOT restarting the following changed units:") 654 assert_lacks(out, "reloading the following units:") 655 assert_lacks(out, "\nrestarting the following units:") 656 assert_contains(out, "\nstarting the following units: escaped\\x2ddash.service\n") 657 assert_lacks(out, "the following new units were started:") 658 659 # Ensure units can start with a dash 660 out = switch_to_specialisation("${machine}", "unitStartingWithDash") 661 assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n") 662 assert_lacks(out, "NOT restarting the following changed units:") 663 assert_lacks(out, "reloading the following units:") 664 assert_lacks(out, "\nrestarting the following units:") 665 assert_lacks(out, "\nstarting the following units:") 666 assert_contains(out, "the following new units were started: -.service\n") 667 668 # The regression only occurs when reloading units 669 out = switch_to_specialisation("${machine}", "unitStartingWithDashModified") 670 assert_lacks(out, "stopping the following units:") 671 assert_lacks(out, "NOT restarting the following changed units:") 672 assert_contains(out, "reloading the following units: -.service") 673 assert_lacks(out, "\nrestarting the following units:") 674 assert_lacks(out, "\nstarting the following units:") 675 assert_lacks(out, "the following new units were started:") 676 677 # Ensure units that require changed units are properly reloaded 678 out = switch_to_specialisation("${machine}", "unitWithRequirement") 679 assert_contains(out, "stopping the following units: -.service\n") 680 assert_lacks(out, "NOT restarting the following changed units:") 681 assert_lacks(out, "reloading the following units:") 682 assert_lacks(out, "\nrestarting the following units:") 683 assert_lacks(out, "\nstarting the following units:") 684 assert_contains(out, "the following new units were started: required-service.service, test-service.service\n") 685 686 out = switch_to_specialisation("${machine}", "unitWithRequirementModified") 687 assert_contains(out, "stopping the following units: required-service.service\n") 688 assert_lacks(out, "NOT restarting the following changed units:") 689 assert_lacks(out, "reloading the following units:") 690 assert_lacks(out, "\nrestarting the following units:") 691 assert_contains(out, "\nstarting the following units: required-service.service, test-service.service\n") 692 assert_lacks(out, "the following new units were started:") 693 694 # Unless the unit asks to be not restarted 695 out = switch_to_specialisation("${machine}", "unitWithRequirementModifiedNostart") 696 assert_contains(out, "stopping the following units: required-service.service\n") 697 assert_lacks(out, "NOT restarting the following changed units:") 698 assert_lacks(out, "reloading the following units:") 699 assert_lacks(out, "\nrestarting the following units:") 700 assert_contains(out, "\nstarting the following units: required-service.service\n") 701 assert_lacks(out, "the following new units were started:") 702 703 with subtest("failing units"): 704 # Let the simple service fail 705 switch_to_specialisation("${machine}", "simpleServiceModified") 706 out = switch_to_specialisation("${machine}", "simpleServiceFailing", fail=True) 707 assert_contains(out, "stopping the following units: test.service\n") 708 assert_lacks(out, "NOT restarting the following changed units:") 709 assert_lacks(out, "reloading the following units:") 710 assert_lacks(out, "\nrestarting the following units:") 711 assert_contains(out, "\nstarting the following units: test.service\n") 712 assert_lacks(out, "the following new units were started:") 713 assert_contains(out, "warning: the following units failed: test.service\n") 714 assert_contains(out, "Main PID:") # output of systemctl 715 716 # A unit that gets into autorestart without failing is not treated as failed 717 out = switch_to_specialisation("${machine}", "autorestartService") 718 assert_lacks(out, "stopping the following units:") 719 assert_lacks(out, "NOT restarting the following changed units:") 720 assert_lacks(out, "reloading the following units:") 721 assert_lacks(out, "\nrestarting the following units:") 722 assert_lacks(out, "\nstarting the following units:") 723 assert_contains(out, "the following new units were started: autorestart.service\n") 724 machine.systemctl('stop autorestart.service') # cancel the 20y timer 725 726 # Switching to the same system should do nothing (especially not treat the unit as failed) 727 out = switch_to_specialisation("${machine}", "autorestartService") 728 assert_lacks(out, "stopping the following units:") 729 assert_lacks(out, "NOT restarting the following changed units:") 730 assert_lacks(out, "reloading the following units:") 731 assert_lacks(out, "\nrestarting the following units:") 732 assert_lacks(out, "\nstarting the following units:") 733 assert_contains(out, "the following new units were started: autorestart.service\n") 734 machine.systemctl('stop autorestart.service') # cancel the 20y timer 735 736 # If systemd thinks the unit has failed and is in autorestart, we should show it as failed 737 out = switch_to_specialisation("${machine}", "autorestartServiceFailing", fail=True) 738 assert_lacks(out, "stopping the following units:") 739 assert_lacks(out, "NOT restarting the following changed units:") 740 assert_lacks(out, "reloading the following units:") 741 assert_lacks(out, "\nrestarting the following units:") 742 assert_lacks(out, "\nstarting the following units:") 743 assert_lacks(out, "the following new units were started:") 744 assert_contains(out, "warning: the following units failed: autorestart.service\n") 745 assert_contains(out, "Main PID:") # output of systemctl 746 747 with subtest("unit file parser"): 748 # Switch to a well-known state 749 switch_to_specialisation("${machine}", "simpleServiceNostop") 750 751 # Add a section 752 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSection") 753 assert_lacks(out, "stopping the following units:") 754 assert_lacks(out, "NOT restarting the following changed units:") 755 assert_lacks(out, "reloading the following units:") 756 assert_contains(out, "\nrestarting the following units: test.service\n") 757 assert_lacks(out, "\nstarting the following units:") 758 assert_lacks(out, "the following new units were started:") 759 760 # Rename it 761 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSectionOtherName") 762 assert_lacks(out, "stopping the following units:") 763 assert_lacks(out, "NOT restarting the following changed units:") 764 assert_lacks(out, "reloading the following units:") 765 assert_contains(out, "\nrestarting the following units: test.service\n") 766 assert_lacks(out, "\nstarting the following units:") 767 assert_lacks(out, "the following new units were started:") 768 769 # Remove it 770 out = switch_to_specialisation("${machine}", "simpleServiceNostop") 771 assert_lacks(out, "stopping the following units:") 772 assert_lacks(out, "NOT restarting the following changed units:") 773 assert_lacks(out, "reloading the following units:") 774 assert_contains(out, "\nrestarting the following units: test.service\n") 775 assert_lacks(out, "\nstarting the following units:") 776 assert_lacks(out, "the following new units were started:") 777 778 # [Install] section is ignored 779 out = switch_to_specialisation("${machine}", "simpleServiceWithInstallSection") 780 assert_lacks(out, "stopping the following units:") 781 assert_lacks(out, "NOT restarting the following changed units:") 782 assert_lacks(out, "reloading the following units:") 783 assert_lacks(out, "\nrestarting the following units:") 784 assert_lacks(out, "\nstarting the following units:") 785 assert_lacks(out, "the following new units were started:") 786 787 # Add a key 788 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKey") 789 assert_lacks(out, "stopping the following units:") 790 assert_lacks(out, "NOT restarting the following changed units:") 791 assert_lacks(out, "reloading the following units:") 792 assert_contains(out, "\nrestarting the following units: test.service\n") 793 assert_lacks(out, "\nstarting the following units:") 794 assert_lacks(out, "the following new units were started:") 795 796 # Change its value 797 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherValue") 798 assert_lacks(out, "stopping the following units:") 799 assert_lacks(out, "NOT restarting the following changed units:") 800 assert_lacks(out, "reloading the following units:") 801 assert_contains(out, "\nrestarting the following units: test.service\n") 802 assert_lacks(out, "\nstarting the following units:") 803 assert_lacks(out, "the following new units were started:") 804 805 # Rename it 806 out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherName") 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.service\n") 811 assert_lacks(out, "\nstarting the following units:") 812 assert_lacks(out, "the following new units were started:") 813 814 # Remove it 815 out = switch_to_specialisation("${machine}", "simpleServiceNostop") 816 assert_lacks(out, "stopping the following units:") 817 assert_lacks(out, "NOT restarting the following changed units:") 818 assert_lacks(out, "reloading the following units:") 819 assert_contains(out, "\nrestarting the following units: test.service\n") 820 assert_lacks(out, "\nstarting the following units:") 821 assert_lacks(out, "the following new units were started:") 822 823 # Add a reload trigger 824 out = switch_to_specialisation("${machine}", "simpleServiceReloadTrigger") 825 assert_lacks(out, "stopping the following units:") 826 assert_lacks(out, "NOT restarting the following changed units:") 827 assert_contains(out, "reloading the following units: test.service\n") 828 assert_lacks(out, "\nrestarting the following units:") 829 assert_lacks(out, "\nstarting the following units:") 830 assert_lacks(out, "the following new units were started:") 831 832 # Modify the reload trigger 833 out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModified") 834 assert_lacks(out, "stopping the following units:") 835 assert_lacks(out, "NOT restarting the following changed units:") 836 assert_contains(out, "reloading the following units: test.service\n") 837 assert_lacks(out, "\nrestarting the following units:") 838 assert_lacks(out, "\nstarting the following units:") 839 assert_lacks(out, "the following new units were started:") 840 841 # Modify the reload trigger and something else 842 out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedAndSomethingElse") 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_contains(out, "\nrestarting the following units: test.service\n") 847 assert_lacks(out, "\nstarting the following units:") 848 assert_lacks(out, "the following new units were started:") 849 850 # Remove the reload trigger 851 out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedSomethingElse") 852 assert_lacks(out, "stopping the following units:") 853 assert_lacks(out, "NOT restarting the following changed units:") 854 assert_lacks(out, "reloading the following units:") 855 assert_lacks(out, "\nrestarting the following units:") 856 assert_lacks(out, "\nstarting the following units:") 857 assert_lacks(out, "the following new units were started:") 858 859 with subtest("restart and reload by activation script"): 860 switch_to_specialisation("${machine}", "simpleServiceNorestart") 861 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script") 862 assert_contains(out, "stopping the following units: test.service\n") 863 assert_lacks(out, "NOT restarting the following changed units:") 864 assert_lacks(out, "reloading the following units:") 865 assert_lacks(out, "restarting the following units:") 866 assert_contains(out, "\nstarting the following units: no-restart-service.service, reload-triggers-and-restart-by-as.service, simple-reload-service.service, simple-restart-service.service, simple-service.service\n") 867 assert_contains(out, "the following new units were started: no-restart-service.service, reload-triggers-and-restart-by-as.service, reload-triggers-and-restart.service, reload-triggers.service, simple-reload-service.service, simple-restart-service.service, simple-service.service\n") 868 # Switch to the same system where the example services get restarted 869 # and reloaded by the activation script 870 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script") 871 assert_lacks(out, "stopping the following units:") 872 assert_lacks(out, "NOT restarting the following changed units:") 873 assert_contains(out, "reloading the following units: reload-triggers-and-restart.service, reload-triggers.service, simple-reload-service.service\n") 874 assert_contains(out, "restarting the following units: reload-triggers-and-restart-by-as.service, simple-restart-service.service, simple-service.service\n") 875 assert_lacks(out, "\nstarting the following units:") 876 assert_lacks(out, "the following new units were started:") 877 # Switch to the same system and see if the service gets restarted when it's modified 878 # while the fact that it's supposed to be reloaded by the activation script is ignored. 879 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified") 880 assert_lacks(out, "stopping the following units:") 881 assert_lacks(out, "NOT restarting the following changed units:") 882 assert_contains(out, "reloading the following units: reload-triggers.service, simple-reload-service.service\n") 883 assert_contains(out, "restarting the following units: reload-triggers-and-restart-by-as.service, reload-triggers-and-restart.service, simple-restart-service.service, simple-service.service\n") 884 assert_lacks(out, "\nstarting the following units:") 885 assert_lacks(out, "the following new units were started:") 886 # The same, but in dry mode 887 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate") 888 assert_lacks(out, "would stop the following units:") 889 assert_lacks(out, "would NOT stop the following changed units:") 890 assert_contains(out, "would reload the following units: reload-triggers.service, simple-reload-service.service\n") 891 assert_contains(out, "would restart the following units: reload-triggers-and-restart-by-as.service, reload-triggers-and-restart.service, simple-restart-service.service, simple-service.service\n") 892 assert_lacks(out, "\nwould start the following units:") 893 894 with subtest("socket-activated services"): 895 # Socket-activated services don't get started, just the socket 896 machine.fail("[ -S /run/test.sock ]") 897 out = switch_to_specialisation("${machine}", "simple-socket") 898 # assert_lacks(out, "stopping the following units:") not relevant 899 assert_lacks(out, "NOT restarting the following changed units:") 900 assert_lacks(out, "reloading the following units:") 901 assert_lacks(out, "\nrestarting the following units:") 902 assert_lacks(out, "\nstarting the following units:") 903 assert_contains(out, "the following new units were started: socket-activated.socket\n") 904 machine.succeed("[ -S /run/test.sock ]") 905 906 # Changing a non-activated service does nothing 907 out = switch_to_specialisation("${machine}", "simple-socket-service-modified") 908 assert_lacks(out, "stopping the following units:") 909 assert_lacks(out, "NOT restarting the following changed units:") 910 assert_lacks(out, "reloading the following units:") 911 assert_lacks(out, "\nrestarting the following units:") 912 assert_lacks(out, "\nstarting the following units:") 913 assert_lacks(out, "the following new units were started:") 914 machine.succeed("[ -S /run/test.sock ]") 915 # The unit is properly activated when the socket is accessed 916 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello": 917 raise Exception("Socket was not properly activated") # idk how that would happen tbh 918 919 # Changing an activated service with stopIfChanged=false restarts the service 920 out = switch_to_specialisation("${machine}", "simple-socket") 921 assert_lacks(out, "stopping the following units:") 922 assert_lacks(out, "NOT restarting the following changed units:") 923 assert_lacks(out, "reloading the following units:") 924 assert_contains(out, "\nrestarting the following units: socket-activated.service\n") 925 assert_lacks(out, "\nstarting the following units:") 926 assert_lacks(out, "the following new units were started:") 927 machine.succeed("[ -S /run/test.sock ]") 928 # Socket-activation of the unit still works 929 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello": 930 raise Exception("Socket was not properly activated after the service was restarted") 931 932 # Changing an activated service with stopIfChanged=true stops the service and 933 # socket and starts the socket 934 out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed") 935 assert_contains(out, "stopping the following units: socket-activated.service, socket-activated.socket\n") 936 assert_lacks(out, "NOT restarting the following changed units:") 937 assert_lacks(out, "reloading the following units:") 938 assert_lacks(out, "\nrestarting the following units:") 939 assert_contains(out, "\nstarting the following units: socket-activated.socket\n") 940 assert_lacks(out, "the following new units were started:") 941 machine.succeed("[ -S /run/test.sock ]") 942 # Socket-activation of the unit still works 943 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello": 944 raise Exception("Socket was not properly activated after the service was restarted") 945 946 # Changing a reload trigger of a socket-activated unit only reloads it 947 out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed-and-reloadtrigger") 948 assert_lacks(out, "stopping the following units:") 949 assert_lacks(out, "NOT restarting the following changed units:") 950 assert_contains(out, "reloading the following units: socket-activated.service\n") 951 assert_lacks(out, "\nrestarting the following units:") 952 assert_lacks(out, "\nstarting the following units: socket-activated.socket") 953 assert_lacks(out, "the following new units were started:") 954 machine.succeed("[ -S /run/test.sock ]") 955 # Socket-activation of the unit still works 956 if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello": 957 raise Exception("Socket was not properly activated after the service was restarted") 958 959 with subtest("mounts"): 960 switch_to_specialisation("${machine}", "mount") 961 out = machine.succeed("mount | grep 'on /testmount'") 962 assert_contains(out, "size=1024k") 963 out = switch_to_specialisation("${machine}", "mountModified") 964 assert_lacks(out, "stopping the following units:") 965 assert_lacks(out, "NOT restarting the following changed units:") 966 assert_contains(out, "reloading the following units: testmount.mount\n") 967 assert_lacks(out, "\nrestarting the following units:") 968 assert_lacks(out, "\nstarting the following units:") 969 assert_lacks(out, "the following new units were started:") 970 # It changed 971 out = machine.succeed("mount | grep 'on /testmount'") 972 assert_contains(out, "size=10240k") 973 974 with subtest("timers"): 975 switch_to_specialisation("${machine}", "timer") 976 out = machine.succeed("systemctl show test-timer.timer") 977 assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC") 978 out = switch_to_specialisation("${machine}", "timerModified") 979 assert_lacks(out, "stopping the following units:") 980 assert_lacks(out, "NOT restarting the following units:") 981 assert_lacks(out, "reloading the following units:") 982 assert_contains(out, "\nrestarting the following units: test-timer.timer\n") 983 assert_lacks(out, "\nstarting the following units:") 984 assert_lacks(out, "the following new units were started:") 985 # It changed 986 out = machine.succeed("systemctl show test-timer.timer") 987 assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00") 988 989 with subtest("targets"): 990 # Modifying some special targets like hybrid-sleep.target does nothing 991 out = switch_to_specialisation("${machine}", "hybridSleepModified") 992 assert_contains(out, "stopping the following units: test-timer.timer\n") 993 assert_lacks(out, "NOT restarting the following changed units:") 994 assert_lacks(out, "reloading the following units:") 995 assert_lacks(out, "\nrestarting the following units:") 996 assert_lacks(out, "\nstarting the following units:") 997 assert_lacks(out, "the following new units were started:") 998 999 # Adding a new target starts it 1000 out = switch_to_specialisation("${machine}", "target") 1001 assert_lacks(out, "stopping the following units:") 1002 assert_lacks(out, "NOT restarting the following changed units:") 1003 assert_lacks(out, "reloading the following units:") 1004 assert_lacks(out, "\nrestarting the following units:") 1005 assert_lacks(out, "\nstarting the following units:") 1006 assert_contains(out, "the following new units were started: test-target.target\n") 1007 1008 # Changing a target doesn't print anything because the unit is filtered 1009 machine.systemctl("start test-service.service") 1010 out = switch_to_specialisation("${machine}", "targetModified") 1011 assert_lacks(out, "stopping the following units:") 1012 assert_lacks(out, "NOT restarting the following changed units:") 1013 assert_lacks(out, "reloading the following units:") 1014 assert_lacks(out, "\nrestarting the following units:") 1015 assert_lacks(out, "\nstarting the following units:") 1016 assert_lacks(out, "the following new units were started:") 1017 machine.succeed("systemctl is-active test-service.service") # target was not restarted 1018 1019 # With X-StopOnReconfiguration, the target gets stopped and started 1020 out = switch_to_specialisation("${machine}", "targetModifiedStopOnReconfig") 1021 assert_lacks(out, "stopping the following units:") 1022 assert_lacks(out, "NOT restarting the following changed units:") 1023 assert_lacks(out, "reloading the following units:") 1024 assert_lacks(out, "\nrestarting the following units:") 1025 assert_lacks(out, "\nstarting the following units:") 1026 assert_lacks(out, "the following new units were started:") 1027 machine.fail("systemctl is-active test-service.servce") # target was restarted 1028 1029 # Remove the target by switching to the old specialisation 1030 out = switch_to_specialisation("${machine}", "timerModified") 1031 assert_contains(out, "stopping the following units: test-target.target\n") 1032 assert_lacks(out, "NOT restarting the following changed units:") 1033 assert_lacks(out, "reloading the following units:") 1034 assert_lacks(out, "\nrestarting the following units:") 1035 assert_lacks(out, "\nstarting the following units:") 1036 assert_contains(out, "the following new units were started: test-timer.timer\n") 1037 1038 with subtest("paths"): 1039 out = switch_to_specialisation("${machine}", "path") 1040 assert_contains(out, "stopping the following units: test-timer.timer\n") 1041 assert_lacks(out, "NOT restarting the following changed units:") 1042 assert_lacks(out, "reloading the following units:") 1043 assert_lacks(out, "\nrestarting the following units:") 1044 assert_lacks(out, "\nstarting the following units:") 1045 assert_contains(out, "the following new units were started: test-watch.path\n") 1046 machine.fail("test -f /testpath-modified") 1047 1048 # touch the file, unit should be triggered 1049 machine.succeed("touch /testpath") 1050 machine.wait_until_succeeds("test -f /testpath-modified") 1051 machine.succeed("rm /testpath /testpath-modified") 1052 machine.systemctl("stop test-watch.service") 1053 switch_to_specialisation("${machine}", "pathModified") 1054 machine.succeed("touch /testpath") 1055 machine.fail("test -f /testpath-modified") 1056 machine.succeed("touch /testpath2") 1057 machine.wait_until_succeeds("test -f /testpath-modified") 1058 1059 # This test ensures that changes to slice configuration get applied. 1060 # We test this by having a slice that allows no memory allocation at 1061 # all and starting a service within it. If the service crashes, the slice 1062 # is applied and if we modify the slice to allow memory allocation, the 1063 # service should successfully start. 1064 with subtest("slices"): 1065 machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom") # allow OOMing 1066 out = switch_to_specialisation("${machine}", "slice") 1067 # assert_lacks(out, "stopping the following units:") not relevant 1068 assert_lacks(out, "NOT restarting the following changed units:") 1069 assert_lacks(out, "reloading the following units:") 1070 assert_lacks(out, "\nrestarting the following units:") 1071 assert_lacks(out, "\nstarting the following units:") 1072 assert_lacks(out, "the following new units were started:") 1073 machine.fail("systemctl start testservice.service") 1074 1075 out = switch_to_specialisation("${machine}", "sliceModified") 1076 assert_lacks(out, "stopping the following units:") 1077 assert_lacks(out, "NOT restarting the following changed units:") 1078 assert_lacks(out, "reloading the following units:") 1079 assert_lacks(out, "\nrestarting the following units:") 1080 assert_lacks(out, "\nstarting the following units:") 1081 assert_lacks(out, "the following new units were started:") 1082 machine.succeed("systemctl start testservice.service") 1083 machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom") # disallow OOMing 1084 ''; 1085})