Merge pull request #232230 from oddlama/fix-activation-template-unit-specializations

Fix detection of changed template unit specializations in switch-to-configuration.pl

authored by

Janne Heß and committed by
GitHub
bc9b484d 1d482993

+218 -32
+30
nixos/doc/manual/administration/service-mgmt.chapter.md
··· 118 118 Hence [garbage collection](#sec-nix-gc) will remove that file and you 119 119 will wind up with a broken symlink in your systemd configuration, which 120 120 in turn will not make the service / timer start on login. 121 + 122 + ## Template units {#sect-nixos-systemd-template-units} 123 + 124 + systemd supports templated units where a base unit can be started multiple 125 + times with a different parameter. The syntax to accomplish this is 126 + `service-name@instance-name.service`. Units get the instance name passed to 127 + them (see `systemd.unit(5)`). NixOS has support for these kinds of units and 128 + for template-specific overrides. A service needs to be defined twice, once 129 + for the base unit and once for the instance. All instances must include 130 + `overrideStrategy = "asDropin"` for the change detection to work. This 131 + example illustrates this: 132 + ```nix 133 + { 134 + systemd.services = { 135 + "base-unit@".serviceConfig = { 136 + ExecStart = "..."; 137 + User = "..."; 138 + }; 139 + "base-unit@instance-a" = { 140 + overrideStrategy = "asDropin"; # needed for templates to work 141 + wantedBy = [ "multi-user.target" ]; # causes NixOS to manage the instance 142 + }; 143 + "base-unit@instance-b" = { 144 + overrideStrategy = "asDropin"; # needed for templates to work 145 + wantedBy = [ "multi-user.target" ]; # causes NixOS to manage the instance 146 + serviceConfig.User = "root"; # also override something for this specific instance 147 + }; 148 + }; 149 + } 150 + ```
+35 -23
nixos/modules/system/activation/switch-to-configuration.pl
··· 253 253 # If a directory with the same basename ending in .d exists next to the unit file, it will be 254 254 # assumed to contain override files which will be parsed as well and handled properly. 255 255 sub parse_unit { 256 - my ($unit_path) = @_; 256 + my ($unit_path, $base_unit_path) = @_; 257 257 258 258 # Parse the main unit and all overrides 259 259 my %unit_data; 260 260 # Replace \ with \\ so glob() still works with units that have a \ in them 261 261 # Valid characters in unit names are ASCII letters, digits, ":", "-", "_", ".", and "\" 262 + $base_unit_path =~ s/\\/\\\\/gmsx; 262 263 $unit_path =~ s/\\/\\\\/gmsx; 263 - foreach (glob("${unit_path}{,.d/*.conf}")) { 264 + 265 + foreach (glob("${base_unit_path}{,.d/*.conf}")) { 264 266 parse_systemd_ini(\%unit_data, "$_") 267 + } 268 + # Handle drop-in template-unit instance overrides 269 + if ($unit_path ne $base_unit_path) { 270 + foreach (glob("${unit_path}.d/*.conf")) { 271 + parse_systemd_ini(\%unit_data, "$_") 272 + } 265 273 } 266 274 return %unit_data; 267 275 } ··· 423 431 # Called when a unit exists in both the old systemd and the new system and the units 424 432 # differ. This figures out of what units are to be stopped, restarted, reloaded, started, and skipped. 425 433 sub handle_modified_unit { ## no critic(Subroutines::ProhibitManyArgs, Subroutines::ProhibitExcessComplexity) 426 - my ($unit, $base_name, $new_unit_file, $new_unit_info, $active_cur, $units_to_stop, $units_to_start, $units_to_reload, $units_to_restart, $units_to_skip) = @_; 434 + my ($unit, $base_name, $new_unit_file, $new_base_unit_file, $new_unit_info, $active_cur, $units_to_stop, $units_to_start, $units_to_reload, $units_to_restart, $units_to_skip) = @_; 427 435 428 436 if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.path$/msx || $unit =~ /\.slice$/msx) { 429 437 # Do nothing. These cannot be restarted directly. ··· 442 450 # Revert of the attempt: https://github.com/NixOS/nixpkgs/pull/147609 443 451 # More details: https://github.com/NixOS/nixpkgs/issues/74899#issuecomment-981142430 444 452 } else { 445 - my %new_unit_info = $new_unit_info ? %{$new_unit_info} : parse_unit($new_unit_file); 453 + my %new_unit_info = $new_unit_info ? %{$new_unit_info} : parse_unit($new_unit_file, $new_base_unit_file); 446 454 if (parse_systemd_bool(\%new_unit_info, "Service", "X-ReloadIfChanged", 0) and not $units_to_restart->{$unit} and not $units_to_stop->{$unit}) { 447 455 $units_to_reload->{$unit} = 1; 448 456 record_unit($reload_list_file, $unit); ··· 538 546 539 547 my $active_cur = get_active_units(); 540 548 while (my ($unit, $state) = each(%{$active_cur})) { 549 + my $cur_unit_file = "/etc/systemd/system/$unit"; 550 + my $new_unit_file = "$toplevel/etc/systemd/system/$unit"; 551 + 541 552 my $base_unit = $unit; 542 - 543 - my $cur_unit_file = "/etc/systemd/system/$base_unit"; 544 - my $new_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 553 + my $cur_base_unit_file = $cur_unit_file; 554 + my $new_base_unit_file = $new_unit_file; 545 555 546 556 # Detect template instances. 547 557 if (!-e $cur_unit_file && !-e $new_unit_file && $unit =~ /^(.*)@[^\.]*\.(.*)$/msx) { 548 558 $base_unit = "$1\@.$2"; 549 - $cur_unit_file = "/etc/systemd/system/$base_unit"; 550 - $new_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 559 + $cur_base_unit_file = "/etc/systemd/system/$base_unit"; 560 + $new_base_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 551 561 } 552 562 553 563 my $base_name = $base_unit; 554 564 $base_name =~ s/\.[[:lower:]]*$//msx; 555 565 556 - if (-e $cur_unit_file && ($state->{state} eq "active" || $state->{state} eq "activating")) { 557 - if (! -e $new_unit_file || abs_path($new_unit_file) eq "/dev/null") { 558 - my %cur_unit_info = parse_unit($cur_unit_file); 566 + if (-e $cur_base_unit_file && ($state->{state} eq "active" || $state->{state} eq "activating")) { 567 + if (! -e $new_base_unit_file || abs_path($new_base_unit_file) eq "/dev/null") { 568 + my %cur_unit_info = parse_unit($cur_unit_file, $cur_base_unit_file); 559 569 if (parse_systemd_bool(\%cur_unit_info, "Unit", "X-StopOnRemoval", 1)) { 560 570 $units_to_stop{$unit} = 1; 561 571 } 562 572 } 563 573 564 574 elsif ($unit =~ /\.target$/msx) { 565 - my %new_unit_info = parse_unit($new_unit_file); 575 + my %new_unit_info = parse_unit($new_unit_file, $new_base_unit_file); 566 576 567 577 # Cause all active target units to be restarted below. 568 578 # This should start most changed units we stop here as ··· 596 606 } 597 607 598 608 else { 599 - my %cur_unit_info = parse_unit($cur_unit_file); 600 - my %new_unit_info = parse_unit($new_unit_file); 609 + my %cur_unit_info = parse_unit($cur_unit_file, $cur_base_unit_file); 610 + my %new_unit_info = parse_unit($new_unit_file, $new_base_unit_file); 601 611 my $diff = compare_units(\%cur_unit_info, \%new_unit_info); 602 612 if ($diff == 1) { 603 - handle_modified_unit($unit, $base_name, $new_unit_file, \%new_unit_info, $active_cur, \%units_to_stop, \%units_to_start, \%units_to_reload, \%units_to_restart, \%units_to_skip); 613 + handle_modified_unit($unit, $base_name, $new_unit_file, $new_base_unit_file, \%new_unit_info, $active_cur, \%units_to_stop, \%units_to_start, \%units_to_reload, \%units_to_restart, \%units_to_skip); 604 614 } elsif ($diff == 2 and not $units_to_restart{$unit}) { 605 615 $units_to_reload{$unit} = 1; 606 616 record_unit($reload_list_file, $unit); ··· 710 720 # Handle the activation script requesting the restart or reload of a unit. 711 721 foreach (split(/\n/msx, read_file($dry_restart_by_activation_file, err_mode => "quiet") // "")) { 712 722 my $unit = $_; 723 + my $new_unit_file = "$toplevel/etc/systemd/system/$unit"; 713 724 my $base_unit = $unit; 714 - my $new_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 725 + my $new_base_unit_file = $new_unit_file; 715 726 716 727 # Detect template instances. 717 728 if (!-e $new_unit_file && $unit =~ /^(.*)@[^\.]*\.(.*)$/msx) { 718 729 $base_unit = "$1\@.$2"; 719 - $new_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 730 + $new_base_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 720 731 } 721 732 722 733 my $base_name = $base_unit; ··· 728 739 next; 729 740 } 730 741 731 - handle_modified_unit($unit, $base_name, $new_unit_file, undef, $active_cur, \%units_to_restart, \%units_to_restart, \%units_to_reload, \%units_to_restart, \%units_to_skip); 742 + handle_modified_unit($unit, $base_name, $new_unit_file, $new_base_unit_file, undef, $active_cur, \%units_to_restart, \%units_to_restart, \%units_to_reload, \%units_to_restart, \%units_to_skip); 732 743 } 733 744 unlink($dry_restart_by_activation_file); 734 745 ··· 782 793 # Handle the activation script requesting the restart or reload of a unit. 783 794 foreach (split(/\n/msx, read_file($restart_by_activation_file, err_mode => "quiet") // "")) { 784 795 my $unit = $_; 796 + my $new_unit_file = "$toplevel/etc/systemd/system/$unit"; 785 797 my $base_unit = $unit; 786 - my $new_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 798 + my $new_base_unit_file = $new_unit_file; 787 799 788 800 # Detect template instances. 789 801 if (!-e $new_unit_file && $unit =~ /^(.*)@[^\.]*\.(.*)$/msx) { 790 802 $base_unit = "$1\@.$2"; 791 - $new_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 803 + $new_base_unit_file = "$toplevel/etc/systemd/system/$base_unit"; 792 804 } 793 805 794 806 my $base_name = $base_unit; ··· 801 813 next; 802 814 } 803 815 804 - handle_modified_unit($unit, $base_name, $new_unit_file, undef, $active_cur, \%units_to_restart, \%units_to_restart, \%units_to_reload, \%units_to_restart, \%units_to_skip); 816 + handle_modified_unit($unit, $base_name, $new_unit_file, $new_base_unit_file, undef, $active_cur, \%units_to_restart, \%units_to_restart, \%units_to_reload, \%units_to_restart, \%units_to_skip); 805 817 } 806 818 # We can remove the file now because it has been propagated to the other restart/reload files 807 819 unlink($restart_by_activation_file); ··· 859 871 for my $unit (keys(%units_to_reload)) { 860 872 if (!unit_is_active($unit)) { 861 873 # Figure out if we need to start the unit 862 - my %unit_info = parse_unit("$toplevel/etc/systemd/system/$unit"); 874 + my %unit_info = parse_unit("$toplevel/etc/systemd/system/$unit", "$toplevel/etc/systemd/system/$unit"); 863 875 if (!(parse_systemd_bool(\%unit_info, "Unit", "RefuseManualStart", 0) || parse_systemd_bool(\%unit_info, "Unit", "X-OnlyManualStart", 0))) { 864 876 $units_to_start{$unit} = 1; 865 877 record_unit($start_list_file, $unit);
+153 -9
nixos/tests/switch-test.nix
··· 1 1 # Test configuration switching. 2 2 3 - import ./make-test-python.nix ({ pkgs, ...} : let 3 + import ./make-test-python.nix ({ lib, pkgs, ...} : let 4 4 5 5 # Simple service that can either be socket-activated or that will 6 6 # listen on port 1234 if not socket-activated. ··· 279 279 systemd.services.test-service.unitConfig.RefuseManualStart = true; 280 280 }; 281 281 282 + unitWithTemplate.configuration = { 283 + systemd.services."instantiated@".serviceConfig = { 284 + Type = "oneshot"; 285 + RemainAfterExit = true; 286 + ExecStart = "${pkgs.coreutils}/bin/true"; 287 + ExecReload = "${pkgs.coreutils}/bin/true"; 288 + }; 289 + systemd.services."instantiated@one" = { 290 + wantedBy = [ "multi-user.target" ]; 291 + overrideStrategy = "asDropin"; 292 + }; 293 + systemd.services."instantiated@two" = { 294 + wantedBy = [ "multi-user.target" ]; 295 + overrideStrategy = "asDropin"; 296 + }; 297 + }; 298 + 299 + unitWithTemplateModified.configuration = { 300 + imports = [ unitWithTemplate.configuration ]; 301 + systemd.services."instantiated@".serviceConfig.X-Test = "test"; 302 + }; 303 + 282 304 restart-and-reload-by-activation-script.configuration = { 283 305 systemd.services = rec { 284 306 simple-service = { ··· 290 312 ExecReload = "${pkgs.coreutils}/bin/true"; 291 313 }; 292 314 }; 315 + "templated-simple-service@" = simple-service; 316 + "templated-simple-service@instance".overrideStrategy = "asDropin"; 293 317 294 318 simple-restart-service = simple-service // { 295 319 stopIfChanged = false; 296 320 }; 321 + "templated-simple-restart-service@" = simple-restart-service; 322 + "templated-simple-restart-service@instance".overrideStrategy = "asDropin"; 297 323 298 324 simple-reload-service = simple-service // { 299 325 reloadIfChanged = true; 300 326 }; 327 + "templated-simple-reload-service@" = simple-reload-service; 328 + "templated-simple-reload-service@instance".overrideStrategy = "asDropin"; 301 329 302 330 no-restart-service = simple-service // { 303 331 restartIfChanged = false; 304 332 }; 333 + "templated-no-restart-service@" = no-restart-service; 334 + "templated-no-restart-service@instance".overrideStrategy = "asDropin"; 305 335 306 336 reload-triggers = simple-service // { 307 337 wantedBy = [ "multi-user.target" ]; 308 338 }; 339 + "templated-reload-triggers@" = simple-service; 340 + "templated-reload-triggers@instance" = { 341 + overrideStrategy = "asDropin"; 342 + wantedBy = [ "multi-user.target" ]; 343 + }; 309 344 310 345 reload-triggers-and-restart-by-as = simple-service; 346 + "templated-reload-triggers-and-restart-by-as@" = reload-triggers-and-restart-by-as; 347 + "templated-reload-triggers-and-restart-by-as@instance".overrideStrategy = "asDropin"; 311 348 312 349 reload-triggers-and-restart = simple-service // { 313 350 stopIfChanged = false; # easier to check for this 314 351 wantedBy = [ "multi-user.target" ]; 315 352 }; 353 + "templated-reload-triggers-and-restart@" = simple-service; 354 + "templated-reload-triggers-and-restart@instance" = { 355 + overrideStrategy = "asDropin"; 356 + stopIfChanged = false; # easier to check for this 357 + wantedBy = [ "multi-user.target" ]; 358 + }; 316 359 }; 317 360 318 361 system.activationScripts.restart-and-reload-test = { ··· 332 375 simple-reload-service.service 333 376 no-restart-service.service 334 377 reload-triggers-and-restart-by-as.service 378 + templated-simple-service@instance.service 379 + templated-simple-restart-service@instance.service 380 + templated-simple-reload-service@instance.service 381 + templated-no-restart-service@instance.service 382 + templated-reload-triggers-and-restart-by-as@instance.service 335 383 EOF 336 384 337 385 cat <<EOF >> "$g" 338 386 reload-triggers.service 339 387 reload-triggers-and-restart-by-as.service 340 388 reload-triggers-and-restart.service 389 + templated-reload-triggers@instance.service 390 + templated-reload-triggers-and-restart-by-as@instance.service 391 + templated-reload-triggers-and-restart@instance.service 341 392 EOF 342 393 ''; 343 394 }; ··· 346 397 restart-and-reload-by-activation-script-modified.configuration = { 347 398 imports = [ restart-and-reload-by-activation-script.configuration ]; 348 399 systemd.services.reload-triggers-and-restart.serviceConfig.X-Modified = "test"; 400 + systemd.services."templated-reload-triggers-and-restart@instance" = { 401 + overrideStrategy = "asDropin"; 402 + serviceConfig.X-Modified = "test"; 403 + }; 349 404 }; 350 405 351 406 simple-socket.configuration = { ··· 507 562 set -o pipefail 508 563 exec env -i "$@" | tee /dev/stderr 509 564 ''; 565 + 566 + # Returns a comma separated representation of the given list in sorted 567 + # order, that matches the output format of switch-to-configuration.pl 568 + sortedUnits = xs: lib.concatStringsSep ", " (builtins.sort builtins.lessThan xs); 510 569 in /* python */ '' 511 570 def switch_to_specialisation(system, name, action="test", fail=False): 512 571 if name == "": ··· 733 792 assert_contains(out, "\nstarting the following units: required-service.service\n") 734 793 assert_lacks(out, "the following new units were started:") 735 794 795 + # Ensure templated units are restarted when the base unit changes 796 + switch_to_specialisation("${machine}", "unitWithTemplate") 797 + out = switch_to_specialisation("${machine}", "unitWithTemplateModified") 798 + assert_contains(out, "stopping the following units: instantiated@one.service, instantiated@two.service\n") 799 + assert_lacks(out, "NOT restarting the following changed units:") 800 + assert_lacks(out, "reloading the following units:") 801 + assert_lacks(out, "\nrestarting the following units:") 802 + assert_contains(out, "\nstarting the following units: instantiated@one.service, instantiated@two.service\n") 803 + assert_lacks(out, "the following new units were started:") 804 + 736 805 with subtest("failing units"): 737 806 # Let the simple service fail 738 807 switch_to_specialisation("${machine}", "simpleServiceModified") ··· 896 965 assert_lacks(out, "NOT restarting the following changed units:") 897 966 assert_lacks(out, "reloading the following units:") 898 967 assert_lacks(out, "restarting the following units:") 899 - 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") 900 - 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") 968 + assert_contains(out, "\nstarting the following units: ${sortedUnits [ 969 + "no-restart-service.service" 970 + "reload-triggers-and-restart-by-as.service" 971 + "simple-reload-service.service" 972 + "simple-restart-service.service" 973 + "simple-service.service" 974 + "templated-no-restart-service@instance.service" 975 + "templated-reload-triggers-and-restart-by-as@instance.service" 976 + "templated-simple-reload-service@instance.service" 977 + "templated-simple-restart-service@instance.service" 978 + "templated-simple-service@instance.service" 979 + ]}\n") 980 + assert_contains(out, "the following new units were started: ${sortedUnits [ 981 + "no-restart-service.service" 982 + "reload-triggers-and-restart-by-as.service" 983 + "reload-triggers-and-restart.service" 984 + "reload-triggers.service" 985 + "simple-reload-service.service" 986 + "simple-restart-service.service" 987 + "simple-service.service" 988 + "system-templated\\\\x2dno\\\\x2drestart\\\\x2dservice.slice" 989 + "system-templated\\\\x2dreload\\\\x2dtriggers.slice" 990 + "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart.slice" 991 + "system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart\\\\x2dby\\\\x2das.slice" 992 + "system-templated\\\\x2dsimple\\\\x2dreload\\\\x2dservice.slice" 993 + "system-templated\\\\x2dsimple\\\\x2drestart\\\\x2dservice.slice" 994 + "system-templated\\\\x2dsimple\\\\x2dservice.slice" 995 + "templated-no-restart-service@instance.service" 996 + "templated-reload-triggers-and-restart-by-as@instance.service" 997 + "templated-reload-triggers-and-restart@instance.service" 998 + "templated-reload-triggers@instance.service" 999 + "templated-simple-reload-service@instance.service" 1000 + "templated-simple-restart-service@instance.service" 1001 + "templated-simple-service@instance.service" 1002 + ]}\n") 901 1003 # Switch to the same system where the example services get restarted 902 1004 # and reloaded by the activation script 903 1005 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script") 904 1006 assert_lacks(out, "stopping the following units:") 905 1007 assert_lacks(out, "NOT restarting the following changed units:") 906 - assert_contains(out, "reloading the following units: reload-triggers-and-restart.service, reload-triggers.service, simple-reload-service.service\n") 907 - assert_contains(out, "restarting the following units: reload-triggers-and-restart-by-as.service, simple-restart-service.service, simple-service.service\n") 1008 + assert_contains(out, "reloading the following units: ${sortedUnits [ 1009 + "reload-triggers-and-restart.service" 1010 + "reload-triggers.service" 1011 + "simple-reload-service.service" 1012 + "templated-reload-triggers-and-restart@instance.service" 1013 + "templated-reload-triggers@instance.service" 1014 + "templated-simple-reload-service@instance.service" 1015 + ]}\n") 1016 + assert_contains(out, "restarting the following units: ${sortedUnits [ 1017 + "reload-triggers-and-restart-by-as.service" 1018 + "simple-restart-service.service" 1019 + "simple-service.service" 1020 + "templated-reload-triggers-and-restart-by-as@instance.service" 1021 + "templated-simple-restart-service@instance.service" 1022 + "templated-simple-service@instance.service" 1023 + ]}\n") 908 1024 assert_lacks(out, "\nstarting the following units:") 909 1025 assert_lacks(out, "the following new units were started:") 910 1026 # Switch to the same system and see if the service gets restarted when it's modified ··· 912 1028 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified") 913 1029 assert_lacks(out, "stopping the following units:") 914 1030 assert_lacks(out, "NOT restarting the following changed units:") 915 - assert_contains(out, "reloading the following units: reload-triggers.service, simple-reload-service.service\n") 916 - 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") 1031 + assert_contains(out, "reloading the following units: ${sortedUnits [ 1032 + "reload-triggers.service" 1033 + "simple-reload-service.service" 1034 + "templated-reload-triggers@instance.service" 1035 + "templated-simple-reload-service@instance.service" 1036 + ]}\n") 1037 + assert_contains(out, "restarting the following units: ${sortedUnits [ 1038 + "reload-triggers-and-restart-by-as.service" 1039 + "reload-triggers-and-restart.service" 1040 + "simple-restart-service.service" 1041 + "simple-service.service" 1042 + "templated-reload-triggers-and-restart-by-as@instance.service" 1043 + "templated-reload-triggers-and-restart@instance.service" 1044 + "templated-simple-restart-service@instance.service" 1045 + "templated-simple-service@instance.service" 1046 + ]}\n") 917 1047 assert_lacks(out, "\nstarting the following units:") 918 1048 assert_lacks(out, "the following new units were started:") 919 1049 # The same, but in dry mode 920 1050 out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate") 921 1051 assert_lacks(out, "would stop the following units:") 922 1052 assert_lacks(out, "would NOT stop the following changed units:") 923 - assert_contains(out, "would reload the following units: reload-triggers.service, simple-reload-service.service\n") 924 - 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") 1053 + assert_contains(out, "would reload the following units: ${sortedUnits [ 1054 + "reload-triggers.service" 1055 + "simple-reload-service.service" 1056 + "templated-reload-triggers@instance.service" 1057 + "templated-simple-reload-service@instance.service" 1058 + ]}\n") 1059 + assert_contains(out, "would restart the following units: ${sortedUnits [ 1060 + "reload-triggers-and-restart-by-as.service" 1061 + "reload-triggers-and-restart.service" 1062 + "simple-restart-service.service" 1063 + "simple-service.service" 1064 + "templated-reload-triggers-and-restart-by-as@instance.service" 1065 + "templated-reload-triggers-and-restart@instance.service" 1066 + "templated-simple-restart-service@instance.service" 1067 + "templated-simple-service@instance.service" 1068 + ]}\n") 925 1069 assert_lacks(out, "\nwould start the following units:") 926 1070 927 1071 with subtest("socket-activated services"):