c96180c53f
Some unit keys don't need to restart the service to make them effective. Reduce the amount of service restarts by ignoring these keys
960 lines
45 KiB
Nix
960 lines
45 KiB
Nix
# Test configuration switching.
|
|
|
|
import ./make-test-python.nix ({ pkgs, ...} : let
|
|
|
|
# Simple service that can either be socket-activated or that will
|
|
# listen on port 1234 if not socket-activated.
|
|
# A connection to the socket causes 'hello' to be written to the client.
|
|
socketTest = pkgs.writeScript "socket-test.py" /* python */ ''
|
|
#!${pkgs.python3}/bin/python3
|
|
|
|
from socketserver import TCPServer, StreamRequestHandler
|
|
import socket
|
|
import os
|
|
|
|
|
|
class Handler(StreamRequestHandler):
|
|
def handle(self):
|
|
self.wfile.write("hello".encode("utf-8"))
|
|
|
|
|
|
class Server(TCPServer):
|
|
def __init__(self, server_address, handler_cls):
|
|
listenFds = os.getenv('LISTEN_FDS')
|
|
if listenFds is None or int(listenFds) < 1:
|
|
print(f'Binding to {server_address}')
|
|
TCPServer.__init__(
|
|
self, server_address, handler_cls, bind_and_activate=True)
|
|
else:
|
|
TCPServer.__init__(
|
|
self, server_address, handler_cls, bind_and_activate=False)
|
|
# Override socket
|
|
print(f'Got activated by {os.getenv("LISTEN_FDNAMES")} '
|
|
f'with {listenFds} FDs')
|
|
self.socket = socket.fromfd(3, self.address_family,
|
|
self.socket_type)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
server = Server(("localhost", 1234), Handler)
|
|
server.serve_forever()
|
|
'';
|
|
|
|
in {
|
|
name = "switch-test";
|
|
meta = with pkgs.lib.maintainers; {
|
|
maintainers = [ gleber das_j ];
|
|
};
|
|
|
|
nodes = {
|
|
machine = { pkgs, lib, ... }: {
|
|
environment.systemPackages = [ pkgs.socat ]; # for the socket activation stuff
|
|
users.mutableUsers = false;
|
|
|
|
specialisation = rec {
|
|
simpleService.configuration = {
|
|
systemd.services.test = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
simpleServiceDifferentDescription.configuration = {
|
|
imports = [ simpleService.configuration ];
|
|
systemd.services.test.description = "Test unit";
|
|
};
|
|
|
|
simpleServiceModified.configuration = {
|
|
imports = [ simpleService.configuration ];
|
|
systemd.services.test.serviceConfig.X-Test = true;
|
|
};
|
|
|
|
simpleServiceNostop.configuration = {
|
|
imports = [ simpleService.configuration ];
|
|
systemd.services.test.stopIfChanged = false;
|
|
};
|
|
|
|
simpleServiceReload.configuration = {
|
|
imports = [ simpleService.configuration ];
|
|
systemd.services.test = {
|
|
reloadIfChanged = true;
|
|
serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
|
|
simpleServiceNorestart.configuration = {
|
|
imports = [ simpleService.configuration ];
|
|
systemd.services.test.restartIfChanged = false;
|
|
};
|
|
|
|
simpleServiceFailing.configuration = {
|
|
imports = [ simpleServiceModified.configuration ];
|
|
systemd.services.test.serviceConfig.ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false";
|
|
};
|
|
|
|
autorestartService.configuration = {
|
|
# A service that immediately goes into restarting (but without failing)
|
|
systemd.services.autorestart = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
Restart = "always";
|
|
RestartSec = "20y"; # Should be long enough
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
autorestartServiceFailing.configuration = {
|
|
imports = [ autorestartService.configuration ];
|
|
systemd.services.autorestart.serviceConfig = {
|
|
ExecStart = lib.mkForce "${pkgs.coreutils}/bin/false";
|
|
};
|
|
};
|
|
|
|
simpleServiceWithExtraSection.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.packages = [ (pkgs.writeTextFile {
|
|
name = "systemd-extra-section";
|
|
destination = "/etc/systemd/system/test.service";
|
|
text = ''
|
|
[X-Test]
|
|
X-Test-Value=a
|
|
'';
|
|
}) ];
|
|
};
|
|
|
|
simpleServiceWithExtraSectionOtherName.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.packages = [ (pkgs.writeTextFile {
|
|
name = "systemd-extra-section";
|
|
destination = "/etc/systemd/system/test.service";
|
|
text = ''
|
|
[X-Test2]
|
|
X-Test-Value=a
|
|
'';
|
|
}) ];
|
|
};
|
|
|
|
simpleServiceWithInstallSection.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.packages = [ (pkgs.writeTextFile {
|
|
name = "systemd-extra-section";
|
|
destination = "/etc/systemd/system/test.service";
|
|
text = ''
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
'';
|
|
}) ];
|
|
};
|
|
|
|
simpleServiceWithExtraKey.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test.serviceConfig."X-Test" = "test";
|
|
};
|
|
|
|
simpleServiceWithExtraKeyOtherValue.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test.serviceConfig."X-Test" = "test2";
|
|
};
|
|
|
|
simpleServiceWithExtraKeyOtherName.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test.serviceConfig."X-Test2" = "test";
|
|
};
|
|
|
|
simpleServiceReloadTrigger.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test.reloadTriggers = [ "/dev/null" ];
|
|
};
|
|
|
|
simpleServiceReloadTriggerModified.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test.reloadTriggers = [ "/dev/zero" ];
|
|
};
|
|
|
|
simpleServiceReloadTriggerModifiedAndSomethingElse.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test = {
|
|
reloadTriggers = [ "/dev/zero" ];
|
|
serviceConfig."X-Test" = "test";
|
|
};
|
|
};
|
|
|
|
simpleServiceReloadTriggerModifiedSomethingElse.configuration = {
|
|
imports = [ simpleServiceNostop.configuration ];
|
|
systemd.services.test.serviceConfig."X-Test" = "test";
|
|
};
|
|
|
|
unitWithBackslash.configuration = {
|
|
systemd.services."escaped\\x2ddash" = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
unitWithBackslashModified.configuration = {
|
|
imports = [ unitWithBackslash.configuration ];
|
|
systemd.services."escaped\\x2ddash".serviceConfig.X-Test = "test";
|
|
};
|
|
|
|
restart-and-reload-by-activation-script.configuration = {
|
|
systemd.services = rec {
|
|
simple-service = {
|
|
# No wantedBy so we can check if the activation script restart triggers them
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
|
|
simple-restart-service = simple-service // {
|
|
stopIfChanged = false;
|
|
};
|
|
|
|
simple-reload-service = simple-service // {
|
|
reloadIfChanged = true;
|
|
};
|
|
|
|
no-restart-service = simple-service // {
|
|
restartIfChanged = false;
|
|
};
|
|
|
|
reload-triggers = simple-service // {
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
|
|
reload-triggers-and-restart-by-as = simple-service;
|
|
|
|
reload-triggers-and-restart = simple-service // {
|
|
stopIfChanged = false; # easier to check for this
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
};
|
|
|
|
system.activationScripts.restart-and-reload-test = {
|
|
supportsDryActivation = true;
|
|
deps = [];
|
|
text = ''
|
|
if [ "$NIXOS_ACTION" = dry-activate ]; then
|
|
f=/run/nixos/dry-activation-restart-list
|
|
g=/run/nixos/dry-activation-reload-list
|
|
else
|
|
f=/run/nixos/activation-restart-list
|
|
g=/run/nixos/activation-reload-list
|
|
fi
|
|
cat <<EOF >> "$f"
|
|
simple-service.service
|
|
simple-restart-service.service
|
|
simple-reload-service.service
|
|
no-restart-service.service
|
|
reload-triggers-and-restart-by-as.service
|
|
EOF
|
|
|
|
cat <<EOF >> "$g"
|
|
reload-triggers.service
|
|
reload-triggers-and-restart-by-as.service
|
|
reload-triggers-and-restart.service
|
|
EOF
|
|
'';
|
|
};
|
|
};
|
|
|
|
restart-and-reload-by-activation-script-modified.configuration = {
|
|
imports = [ restart-and-reload-by-activation-script.configuration ];
|
|
systemd.services.reload-triggers-and-restart.serviceConfig.X-Modified = "test";
|
|
};
|
|
|
|
simple-socket.configuration = {
|
|
systemd.services.socket-activated = {
|
|
description = "A socket-activated service";
|
|
stopIfChanged = lib.mkDefault false;
|
|
serviceConfig = {
|
|
ExecStart = socketTest;
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
systemd.sockets.socket-activated = {
|
|
wantedBy = [ "sockets.target" ];
|
|
listenStreams = [ "/run/test.sock" ];
|
|
socketConfig.SocketMode = lib.mkDefault "0777";
|
|
};
|
|
};
|
|
|
|
simple-socket-service-modified.configuration = {
|
|
imports = [ simple-socket.configuration ];
|
|
systemd.services.socket-activated.serviceConfig.X-Test = "test";
|
|
};
|
|
|
|
simple-socket-stop-if-changed.configuration = {
|
|
imports = [ simple-socket.configuration ];
|
|
systemd.services.socket-activated.stopIfChanged = true;
|
|
};
|
|
|
|
simple-socket-stop-if-changed-and-reloadtrigger.configuration = {
|
|
imports = [ simple-socket.configuration ];
|
|
systemd.services.socket-activated = {
|
|
stopIfChanged = true;
|
|
reloadTriggers = [ "test" ];
|
|
};
|
|
};
|
|
|
|
mount.configuration = {
|
|
systemd.mounts = [
|
|
{
|
|
description = "Testmount";
|
|
what = "tmpfs";
|
|
type = "tmpfs";
|
|
where = "/testmount";
|
|
options = "size=1M";
|
|
wantedBy = [ "local-fs.target" ];
|
|
}
|
|
];
|
|
};
|
|
|
|
mountModified.configuration = {
|
|
systemd.mounts = [
|
|
{
|
|
description = "Testmount";
|
|
what = "tmpfs";
|
|
type = "tmpfs";
|
|
where = "/testmount";
|
|
options = "size=10M";
|
|
wantedBy = [ "local-fs.target" ];
|
|
}
|
|
];
|
|
};
|
|
|
|
timer.configuration = {
|
|
systemd.timers.test-timer = {
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig.OnCalendar = "@1395716396"; # chosen by fair dice roll
|
|
};
|
|
systemd.services.test-timer = {
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
timerModified.configuration = {
|
|
imports = [ timer.configuration ];
|
|
systemd.timers.test-timer.timerConfig.OnCalendar = lib.mkForce "Fri 2012-11-23 16:00:00";
|
|
};
|
|
|
|
hybridSleepModified.configuration = {
|
|
systemd.targets.hybrid-sleep.unitConfig.X-Test = true;
|
|
};
|
|
|
|
target.configuration = {
|
|
systemd.targets.test-target.wantedBy = [ "multi-user.target" ];
|
|
# We use this service to figure out whether the target was modified.
|
|
# This is the only way because targets are filtered and therefore not
|
|
# printed when they are started/stopped.
|
|
systemd.services.test-service = {
|
|
bindsTo = [ "test-target.target" ];
|
|
serviceConfig.ExecStart = "${pkgs.coreutils}/bin/sleep infinity";
|
|
};
|
|
};
|
|
|
|
targetModified.configuration = {
|
|
imports = [ target.configuration ];
|
|
systemd.targets.test-target.unitConfig.X-Test = true;
|
|
};
|
|
|
|
targetModifiedStopOnReconfig.configuration = {
|
|
imports = [ target.configuration ];
|
|
systemd.targets.test-target.unitConfig.X-StopOnReconfiguration = true;
|
|
};
|
|
|
|
path.configuration = {
|
|
systemd.paths.test-watch = {
|
|
wantedBy = [ "paths.target" ];
|
|
pathConfig.PathExists = "/testpath";
|
|
};
|
|
systemd.services.test-watch = {
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/touch /testpath-modified";
|
|
};
|
|
};
|
|
};
|
|
|
|
pathModified.configuration = {
|
|
imports = [ path.configuration ];
|
|
systemd.paths.test-watch.pathConfig.PathExists = lib.mkForce "/testpath2";
|
|
};
|
|
|
|
slice.configuration = {
|
|
systemd.slices.testslice.sliceConfig.MemoryMax = "1"; # don't allow memory allocation
|
|
systemd.services.testservice = {
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
Slice = "testslice.slice";
|
|
};
|
|
};
|
|
};
|
|
|
|
sliceModified.configuration = {
|
|
imports = [ slice.configuration ];
|
|
systemd.slices.testslice.sliceConfig.MemoryMax = lib.mkForce null;
|
|
};
|
|
};
|
|
};
|
|
|
|
other = {
|
|
users.mutableUsers = true;
|
|
};
|
|
};
|
|
|
|
testScript = { nodes, ... }: let
|
|
originalSystem = nodes.machine.config.system.build.toplevel;
|
|
otherSystem = nodes.other.config.system.build.toplevel;
|
|
machine = nodes.machine.config.system.build.toplevel;
|
|
|
|
# Ensures failures pass through using pipefail, otherwise failing to
|
|
# switch-to-configuration is hidden by the success of `tee`.
|
|
stderrRunner = pkgs.writeScript "stderr-runner" ''
|
|
#! ${pkgs.runtimeShell}
|
|
set -e
|
|
set -o pipefail
|
|
exec env -i "$@" | tee /dev/stderr
|
|
'';
|
|
in /* python */ ''
|
|
def switch_to_specialisation(system, name, action="test", fail=False):
|
|
if name == "":
|
|
stc = f"{system}/bin/switch-to-configuration"
|
|
else:
|
|
stc = f"{system}/specialisation/{name}/bin/switch-to-configuration"
|
|
out = machine.fail(f"{stc} {action} 2>&1") if fail \
|
|
else machine.succeed(f"{stc} {action} 2>&1")
|
|
assert_lacks(out, "switch-to-configuration line") # Perl warnings
|
|
return out
|
|
|
|
def assert_contains(haystack, needle):
|
|
if needle not in haystack:
|
|
print("The haystack that will cause the following exception is:")
|
|
print("---")
|
|
print(haystack)
|
|
print("---")
|
|
raise Exception(f"Expected string '{needle}' was not found")
|
|
|
|
def assert_lacks(haystack, needle):
|
|
if needle in haystack:
|
|
print("The haystack that will cause the following exception is:")
|
|
print("---")
|
|
print(haystack, end="")
|
|
print("---")
|
|
raise Exception(f"Unexpected string '{needle}' was found")
|
|
|
|
|
|
machine.wait_for_unit("multi-user.target")
|
|
|
|
machine.succeed(
|
|
"${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
|
|
)
|
|
machine.succeed(
|
|
"${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
|
|
)
|
|
|
|
with subtest("services"):
|
|
switch_to_specialisation("${machine}", "")
|
|
# Nothing happens when nothing is changed
|
|
out = switch_to_specialisation("${machine}", "")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Start a simple service
|
|
out = switch_to_specialisation("${machine}", "simpleService")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: dbus.service\n") # huh
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: test.service\n")
|
|
|
|
# Not changing anything doesn't do anything
|
|
out = switch_to_specialisation("${machine}", "simpleService")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Only changing the description does nothing
|
|
out = switch_to_specialisation("${machine}", "simpleServiceDifferentDescription")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Restart the simple service
|
|
out = switch_to_specialisation("${machine}", "simpleServiceModified")
|
|
assert_contains(out, "stopping the following units: test.service\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_contains(out, "\nstarting the following units: test.service\n")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Restart the service with stopIfChanged=false
|
|
out = switch_to_specialisation("${machine}", "simpleServiceNostop")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Reload the service with reloadIfChanged=true
|
|
out = switch_to_specialisation("${machine}", "simpleServiceReload")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: test.service\n")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Nothing happens when restartIfChanged=false
|
|
out = switch_to_specialisation("${machine}", "simpleServiceNorestart")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_contains(out, "NOT restarting the following changed units: test.service\n")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Dry mode shows different messages
|
|
out = switch_to_specialisation("${machine}", "simpleService", action="dry-activate")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
assert_contains(out, "would start the following units: test.service\n")
|
|
|
|
# Ensure \ works in unit names
|
|
out = switch_to_specialisation("${machine}", "unitWithBackslash")
|
|
assert_contains(out, "stopping the following units: test.service\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: escaped\\x2ddash.service\n")
|
|
|
|
out = switch_to_specialisation("${machine}", "unitWithBackslashModified")
|
|
assert_contains(out, "stopping the following units: escaped\\x2ddash.service\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_contains(out, "\nstarting the following units: escaped\\x2ddash.service\n")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
with subtest("failing units"):
|
|
# Let the simple service fail
|
|
switch_to_specialisation("${machine}", "simpleServiceModified")
|
|
out = switch_to_specialisation("${machine}", "simpleServiceFailing", fail=True)
|
|
assert_contains(out, "stopping the following units: test.service\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_contains(out, "\nstarting the following units: test.service\n")
|
|
assert_lacks(out, "the following new units were started:")
|
|
assert_contains(out, "warning: the following units failed: test.service\n")
|
|
assert_contains(out, "Main PID:") # output of systemctl
|
|
|
|
# A unit that gets into autorestart without failing is not treated as failed
|
|
out = switch_to_specialisation("${machine}", "autorestartService")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: autorestart.service\n")
|
|
machine.systemctl('stop autorestart.service') # cancel the 20y timer
|
|
|
|
# Switching to the same system should do nothing (especially not treat the unit as failed)
|
|
out = switch_to_specialisation("${machine}", "autorestartService")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: autorestart.service\n")
|
|
machine.systemctl('stop autorestart.service') # cancel the 20y timer
|
|
|
|
# If systemd thinks the unit has failed and is in autorestart, we should show it as failed
|
|
out = switch_to_specialisation("${machine}", "autorestartServiceFailing", fail=True)
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
assert_contains(out, "warning: the following units failed: autorestart.service\n")
|
|
assert_contains(out, "Main PID:") # output of systemctl
|
|
|
|
with subtest("unit file parser"):
|
|
# Switch to a well-known state
|
|
switch_to_specialisation("${machine}", "simpleServiceNostop")
|
|
|
|
# Add a section
|
|
out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSection")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Rename it
|
|
out = switch_to_specialisation("${machine}", "simpleServiceWithExtraSectionOtherName")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Remove it
|
|
out = switch_to_specialisation("${machine}", "simpleServiceNostop")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# [Install] section is ignored
|
|
out = switch_to_specialisation("${machine}", "simpleServiceWithInstallSection")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Add a key
|
|
out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKey")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Change its value
|
|
out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherValue")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Rename it
|
|
out = switch_to_specialisation("${machine}", "simpleServiceWithExtraKeyOtherName")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Remove it
|
|
out = switch_to_specialisation("${machine}", "simpleServiceNostop")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Add a reload trigger
|
|
out = switch_to_specialisation("${machine}", "simpleServiceReloadTrigger")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: test.service\n")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Modify the reload trigger
|
|
out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: test.service\n")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Modify the reload trigger and something else
|
|
out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedAndSomethingElse")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Remove the reload trigger
|
|
out = switch_to_specialisation("${machine}", "simpleServiceReloadTriggerModifiedSomethingElse")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
with subtest("restart and reload by activation script"):
|
|
switch_to_specialisation("${machine}", "simpleServiceNorestart")
|
|
out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
|
|
assert_contains(out, "stopping the following units: test.service\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "restarting the following units:")
|
|
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")
|
|
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")
|
|
# Switch to the same system where the example services get restarted
|
|
# and reloaded by the activation script
|
|
out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: reload-triggers-and-restart.service, reload-triggers.service, simple-reload-service.service\n")
|
|
assert_contains(out, "restarting the following units: reload-triggers-and-restart-by-as.service, simple-restart-service.service, simple-service.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
# Switch to the same system and see if the service gets restarted when it's modified
|
|
# while the fact that it's supposed to be reloaded by the activation script is ignored.
|
|
out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script-modified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: reload-triggers.service, simple-reload-service.service\n")
|
|
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")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
# The same, but in dry mode
|
|
out = switch_to_specialisation("${machine}", "restart-and-reload-by-activation-script", action="dry-activate")
|
|
assert_lacks(out, "would stop the following units:")
|
|
assert_lacks(out, "would NOT stop the following changed units:")
|
|
assert_contains(out, "would reload the following units: reload-triggers.service, simple-reload-service.service\n")
|
|
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")
|
|
assert_lacks(out, "\nwould start the following units:")
|
|
|
|
with subtest("socket-activated services"):
|
|
# Socket-activated services don't get started, just the socket
|
|
machine.fail("[ -S /run/test.sock ]")
|
|
out = switch_to_specialisation("${machine}", "simple-socket")
|
|
# assert_lacks(out, "stopping the following units:") not relevant
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: socket-activated.socket\n")
|
|
machine.succeed("[ -S /run/test.sock ]")
|
|
|
|
# Changing a non-activated service does nothing
|
|
out = switch_to_specialisation("${machine}", "simple-socket-service-modified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.succeed("[ -S /run/test.sock ]")
|
|
# The unit is properly activated when the socket is accessed
|
|
if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
|
|
raise Exception("Socket was not properly activated") # idk how that would happen tbh
|
|
|
|
# Changing an activated service with stopIfChanged=false restarts the service
|
|
out = switch_to_specialisation("${machine}", "simple-socket")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: socket-activated.service\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.succeed("[ -S /run/test.sock ]")
|
|
# Socket-activation of the unit still works
|
|
if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
|
|
raise Exception("Socket was not properly activated after the service was restarted")
|
|
|
|
# Changing an activated service with stopIfChanged=true stops the service and
|
|
# socket and starts the socket
|
|
out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed")
|
|
assert_contains(out, "stopping the following units: socket-activated.service, socket-activated.socket\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_contains(out, "\nstarting the following units: socket-activated.socket\n")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.succeed("[ -S /run/test.sock ]")
|
|
# Socket-activation of the unit still works
|
|
if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
|
|
raise Exception("Socket was not properly activated after the service was restarted")
|
|
|
|
# Changing a reload trigger of a socket-activated unit only reloads it
|
|
out = switch_to_specialisation("${machine}", "simple-socket-stop-if-changed-and-reloadtrigger")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: socket-activated.service\n")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units: socket-activated.socket")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.succeed("[ -S /run/test.sock ]")
|
|
# Socket-activation of the unit still works
|
|
if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
|
|
raise Exception("Socket was not properly activated after the service was restarted")
|
|
|
|
with subtest("mounts"):
|
|
switch_to_specialisation("${machine}", "mount")
|
|
out = machine.succeed("mount | grep 'on /testmount'")
|
|
assert_contains(out, "size=1024k")
|
|
out = switch_to_specialisation("${machine}", "mountModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: testmount.mount\n")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
# It changed
|
|
out = machine.succeed("mount | grep 'on /testmount'")
|
|
assert_contains(out, "size=10240k")
|
|
|
|
with subtest("timers"):
|
|
switch_to_specialisation("${machine}", "timer")
|
|
out = machine.succeed("systemctl show test-timer.timer")
|
|
assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC")
|
|
out = switch_to_specialisation("${machine}", "timerModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_contains(out, "\nrestarting the following units: test-timer.timer\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
# It changed
|
|
out = machine.succeed("systemctl show test-timer.timer")
|
|
assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00")
|
|
|
|
with subtest("targets"):
|
|
# Modifying some special targets like hybrid-sleep.target does nothing
|
|
out = switch_to_specialisation("${machine}", "hybridSleepModified")
|
|
assert_contains(out, "stopping the following units: test-timer.timer\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Adding a new target starts it
|
|
out = switch_to_specialisation("${machine}", "target")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: test-target.target\n")
|
|
|
|
# Changing a target doesn't print anything because the unit is filtered
|
|
machine.systemctl("start test-service.service")
|
|
out = switch_to_specialisation("${machine}", "targetModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.succeed("systemctl is-active test-service.service") # target was not restarted
|
|
|
|
# With X-StopOnReconfiguration, the target gets stopped and started
|
|
out = switch_to_specialisation("${machine}", "targetModifiedStopOnReconfig")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.fail("systemctl is-active test-service.servce") # target was restarted
|
|
|
|
# Remove the target by switching to the old specialisation
|
|
out = switch_to_specialisation("${machine}", "timerModified")
|
|
assert_contains(out, "stopping the following units: test-target.target\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: test-timer.timer\n")
|
|
|
|
with subtest("paths"):
|
|
out = switch_to_specialisation("${machine}", "path")
|
|
assert_contains(out, "stopping the following units: test-timer.timer\n")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: test-watch.path\n")
|
|
machine.fail("test -f /testpath-modified")
|
|
|
|
# touch the file, unit should be triggered
|
|
machine.succeed("touch /testpath")
|
|
machine.wait_until_succeeds("test -f /testpath-modified")
|
|
machine.succeed("rm /testpath /testpath-modified")
|
|
machine.systemctl("stop test-watch.service")
|
|
switch_to_specialisation("${machine}", "pathModified")
|
|
machine.succeed("touch /testpath")
|
|
machine.fail("test -f /testpath-modified")
|
|
machine.succeed("touch /testpath2")
|
|
machine.wait_until_succeeds("test -f /testpath-modified")
|
|
|
|
# This test ensures that changes to slice configuration get applied.
|
|
# We test this by having a slice that allows no memory allocation at
|
|
# all and starting a service within it. If the service crashes, the slice
|
|
# is applied and if we modify the slice to allow memory allocation, the
|
|
# service should successfully start.
|
|
with subtest("slices"):
|
|
machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom") # allow OOMing
|
|
out = switch_to_specialisation("${machine}", "slice")
|
|
# assert_lacks(out, "stopping the following units:") not relevant
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.fail("systemctl start testservice.service")
|
|
|
|
out = switch_to_specialisation("${machine}", "sliceModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
machine.succeed("systemctl start testservice.service")
|
|
machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom") # disallow OOMing
|
|
'';
|
|
})
|