mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-12-28 00:24:18 +00:00
6e192c4489
Add an option for shell script fragments that are ran before switching to a new NixOS system configuration (pre installation of bootloader or system activation). Also add a new subcommand for switch-to-configuration called "check" that will cause the program to always exit after checks are ran.
1459 lines
69 KiB
Nix
1459 lines
69 KiB
Nix
# Test configuration switching.
|
|
|
|
import ./make-test-python.nix ({ lib, pkgs, ng, ...} : 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, ... }: {
|
|
system.switch.enableNg = ng;
|
|
|
|
environment.systemPackages = [ pkgs.socat ]; # for the socket activation stuff
|
|
users.mutableUsers = false;
|
|
|
|
# Test that no boot loader still switches, e.g. in the ISO
|
|
boot.loader.grub.enable = false;
|
|
|
|
specialisation = rec {
|
|
brokenInitInterface.configuration.config.system.extraSystemBuilderCmds = ''
|
|
echo "systemd 0" > $out/init-interface-version
|
|
'';
|
|
|
|
modifiedSystemConf.configuration.systemd.extraConfig = ''
|
|
# Hello world!
|
|
'';
|
|
|
|
addedMount.configuration.virtualisation.fileSystems."/test" = {
|
|
device = "tmpfs";
|
|
fsType = "tmpfs";
|
|
};
|
|
|
|
addedMountOptsModified.configuration = {
|
|
imports = [ addedMount.configuration ];
|
|
virtualisation.fileSystems."/test".options = [ "x-test" ];
|
|
};
|
|
|
|
addedMountDevModified.configuration = {
|
|
imports = [ addedMountOptsModified.configuration ];
|
|
virtualisation.fileSystems."/test".device = lib.mkForce "ramfs";
|
|
};
|
|
|
|
storeMountModified.configuration = {
|
|
virtualisation.fileSystems."/".device = lib.mkForce "auto";
|
|
};
|
|
|
|
swap.configuration.swapDevices = lib.mkVMOverride [
|
|
{ device = "/swapfile"; size = 1; }
|
|
];
|
|
|
|
simpleService.configuration = {
|
|
systemd.services.test = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
simpleServiceSeparateActivationScript.configuration = {
|
|
system.activatable = false;
|
|
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";
|
|
};
|
|
|
|
unitWithMultilineValue.configuration = {
|
|
systemd.services.test.serviceConfig.ExecStart = ''
|
|
${pkgs.coreutils}/bin/true \
|
|
# ignored
|
|
; ignored
|
|
blah blah
|
|
'';
|
|
};
|
|
|
|
unitStartingWithDash.configuration = {
|
|
systemd.services."-" = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
unitStartingWithDashModified.configuration = {
|
|
imports = [ unitStartingWithDash.configuration ];
|
|
systemd.services."-" = {
|
|
reloadIfChanged = true;
|
|
serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
|
|
unitWithRequirement.configuration = {
|
|
systemd.services.required-service = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
systemd.services.test-service = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
requires = [ "required-service.service" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
};
|
|
};
|
|
|
|
unitWithRequirementModified.configuration = {
|
|
imports = [ unitWithRequirement.configuration ];
|
|
systemd.services.required-service.serviceConfig.X-Test = "test";
|
|
systemd.services.test-service.reloadTriggers = [ "test" ];
|
|
};
|
|
|
|
unitWithRequirementModifiedNostart.configuration = {
|
|
imports = [ unitWithRequirement.configuration ];
|
|
systemd.services.test-service.unitConfig.RefuseManualStart = true;
|
|
};
|
|
|
|
unitWithTemplate.configuration = {
|
|
systemd.services."instantiated@".serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${pkgs.coreutils}/bin/true";
|
|
ExecReload = "${pkgs.coreutils}/bin/true";
|
|
};
|
|
systemd.services."instantiated@one" = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
overrideStrategy = "asDropin";
|
|
};
|
|
systemd.services."instantiated@two" = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
overrideStrategy = "asDropin";
|
|
};
|
|
};
|
|
|
|
unitWithTemplateModified.configuration = {
|
|
imports = [ unitWithTemplate.configuration ];
|
|
systemd.services."instantiated@".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";
|
|
};
|
|
};
|
|
"templated-simple-service@" = simple-service;
|
|
"templated-simple-service@instance".overrideStrategy = "asDropin";
|
|
|
|
simple-restart-service = simple-service // {
|
|
stopIfChanged = false;
|
|
};
|
|
"templated-simple-restart-service@" = simple-restart-service;
|
|
"templated-simple-restart-service@instance".overrideStrategy = "asDropin";
|
|
|
|
simple-reload-service = simple-service // {
|
|
reloadIfChanged = true;
|
|
};
|
|
"templated-simple-reload-service@" = simple-reload-service;
|
|
"templated-simple-reload-service@instance".overrideStrategy = "asDropin";
|
|
|
|
no-restart-service = simple-service // {
|
|
restartIfChanged = false;
|
|
};
|
|
"templated-no-restart-service@" = no-restart-service;
|
|
"templated-no-restart-service@instance".overrideStrategy = "asDropin";
|
|
|
|
reload-triggers = simple-service // {
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
"templated-reload-triggers@" = simple-service;
|
|
"templated-reload-triggers@instance" = {
|
|
overrideStrategy = "asDropin";
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
|
|
reload-triggers-and-restart-by-as = simple-service;
|
|
"templated-reload-triggers-and-restart-by-as@" = reload-triggers-and-restart-by-as;
|
|
"templated-reload-triggers-and-restart-by-as@instance".overrideStrategy = "asDropin";
|
|
|
|
reload-triggers-and-restart = simple-service // {
|
|
stopIfChanged = false; # easier to check for this
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
"templated-reload-triggers-and-restart@" = simple-service;
|
|
"templated-reload-triggers-and-restart@instance" = {
|
|
overrideStrategy = "asDropin";
|
|
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
|
|
templated-simple-service@instance.service
|
|
templated-simple-restart-service@instance.service
|
|
templated-simple-reload-service@instance.service
|
|
templated-no-restart-service@instance.service
|
|
templated-reload-triggers-and-restart-by-as@instance.service
|
|
EOF
|
|
|
|
cat <<EOF >> "$g"
|
|
reload-triggers.service
|
|
reload-triggers-and-restart-by-as.service
|
|
reload-triggers-and-restart.service
|
|
templated-reload-triggers@instance.service
|
|
templated-reload-triggers-and-restart-by-as@instance.service
|
|
templated-reload-triggers-and-restart@instance.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";
|
|
systemd.services."templated-reload-triggers-and-restart@instance" = {
|
|
overrideStrategy = "asDropin";
|
|
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" ];
|
|
}
|
|
];
|
|
};
|
|
|
|
mountOptionsModified.configuration = {
|
|
systemd.mounts = [
|
|
{
|
|
description = "Testmount";
|
|
what = "tmpfs";
|
|
type = "tmpfs";
|
|
where = "/testmount";
|
|
options = "size=10M";
|
|
wantedBy = [ "local-fs.target" ];
|
|
}
|
|
];
|
|
};
|
|
|
|
mountModified.configuration = {
|
|
systemd.mounts = [
|
|
{
|
|
description = "Testmount";
|
|
what = "ramfs";
|
|
type = "ramfs";
|
|
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;
|
|
};
|
|
|
|
dbusReload.configuration = { config, ... }: let
|
|
dbusService = {
|
|
"dbus" = "dbus";
|
|
"broker" = "dbus-broker";
|
|
}.${config.services.dbus.implementation};
|
|
in {
|
|
# We want to make sure that stc catches this as a reload,
|
|
# not a restart.
|
|
systemd.services.${dbusService}.restartTriggers = [
|
|
(pkgs.writeText "dbus-reload-dummy" "dbus reload dummy")
|
|
];
|
|
};
|
|
};
|
|
};
|
|
|
|
other = {
|
|
system.switch.enable = true;
|
|
users.mutableUsers = true;
|
|
specialisation.failingCheck.configuration.system.preSwitchChecks.failEveryTime = ''
|
|
echo this will fail
|
|
false
|
|
'';
|
|
};
|
|
};
|
|
|
|
testScript = { nodes, ... }: let
|
|
originalSystem = nodes.machine.system.build.toplevel;
|
|
otherSystem = nodes.other.system.build.toplevel;
|
|
machine = nodes.machine.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
|
|
'';
|
|
|
|
# Returns a comma separated representation of the given list in sorted
|
|
# order, that matches the output format of switch-to-configuration.pl
|
|
sortedUnits = xs: lib.concatStringsSep ", " (builtins.sort builtins.lessThan xs);
|
|
|
|
dbusService = {
|
|
"dbus" = "dbus.service";
|
|
"broker" = "dbus-broker.service";
|
|
}.${nodes.machine.services.dbus.implementation};
|
|
in /* python */ ''
|
|
def switch_to_specialisation(system, name, action="test", fail=False):
|
|
if name == "":
|
|
switcher = f"{system}/bin/switch-to-configuration"
|
|
else:
|
|
switcher = f"{system}/specialisation/{name}/bin/switch-to-configuration"
|
|
return run_switch(switcher, action, fail)
|
|
|
|
# like above but stc = switcher
|
|
def run_switch(switcher, action="test", fail=False):
|
|
out = machine.fail(f"{switcher} {action} 2>&1") if fail \
|
|
else machine.succeed(f"{switcher} {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"
|
|
)
|
|
# This tests whether the /etc/os-release parser works which is a fallback
|
|
# when /etc/NIXOS is missing. If the parser does not work, switch-to-configuration
|
|
# would fail.
|
|
machine.succeed("rm /etc/NIXOS")
|
|
machine.succeed(
|
|
"${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
|
|
)
|
|
|
|
boot_loader_text = "Warning: do not know how to make this configuration bootable; please enable a boot loader."
|
|
|
|
with subtest("pre-switch checks"):
|
|
machine.succeed("${stderrRunner} ${otherSystem}/bin/switch-to-configuration check")
|
|
out = switch_to_specialisation("${otherSystem}", "failingCheck", action="check", fail=True)
|
|
assert_contains(out, "this will fail")
|
|
|
|
with subtest("actions"):
|
|
# boot action
|
|
out = switch_to_specialisation("${machine}", "simpleService", action="boot")
|
|
assert_contains(out, boot_loader_text)
|
|
assert_lacks(out, "activating the configuration...") # good indicator of a system activation
|
|
|
|
# switch action
|
|
out = switch_to_specialisation("${machine}", "", action="switch")
|
|
assert_contains(out, boot_loader_text)
|
|
assert_contains(out, "activating the configuration...") # good indicator of a system activation
|
|
|
|
# test and dry-activate actions are tested further down below
|
|
|
|
# invalid action fails the script
|
|
switch_to_specialisation("${machine}", "", action="broken-action", fail=True)
|
|
# no action fails the script
|
|
assert "Usage:" in machine.fail("${machine}/bin/switch-to-configuration 2>&1")
|
|
|
|
with subtest("init interface version"):
|
|
# Do not try to switch to an invalid init interface version
|
|
assert "incompatible" in switch_to_specialisation("${machine}", "brokenInitInterface", fail=True)
|
|
|
|
with subtest("systemd restarts"):
|
|
# systemd is restarted when its system.conf changes
|
|
out = switch_to_specialisation("${machine}", "modifiedSystemConf")
|
|
assert_contains(out, "restarting systemd...")
|
|
|
|
with subtest("continuing from an aborted switch"):
|
|
# An aborted switch will write into a file what it tried to start
|
|
# and a second switch should continue from this
|
|
machine.succeed("echo ${dbusService} > /run/nixos/start-list")
|
|
out = switch_to_specialisation("${machine}", "modifiedSystemConf")
|
|
assert_contains(out, "starting the following units: ${dbusService}\n")
|
|
|
|
with subtest("fstab mounts"):
|
|
switch_to_specialisation("${machine}", "")
|
|
# add a mountpoint
|
|
out = switch_to_specialisation("${machine}", "addedMount")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed 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.mount\n")
|
|
# modify the mountpoint's options
|
|
out = switch_to_specialisation("${machine}", "addedMountOptsModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: test.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:")
|
|
# modify the device
|
|
out = switch_to_specialisation("${machine}", "addedMountDevModified")
|
|
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.mount\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
# modify both
|
|
out = switch_to_specialisation("${machine}", "addedMount")
|
|
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.mount\n")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
# remove the mount
|
|
out = switch_to_specialisation("${machine}", "")
|
|
assert_contains(out, "stopping the following units: test.mount\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:")
|
|
# change something about the / mount
|
|
out = switch_to_specialisation("${machine}", "storeMountModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_contains(out, "NOT restarting the following changed units: -.mount")
|
|
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("swaps"):
|
|
switch_to_specialisation("${machine}", "")
|
|
# add a swap
|
|
out = switch_to_specialisation("${machine}", "swap")
|
|
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: swapfile.swap")
|
|
# remove it
|
|
out = switch_to_specialisation("${machine}", "")
|
|
assert_contains(out, "stopping swap device: /swapfile")
|
|
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("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, boot_loader_text) # test does not install a bootloader
|
|
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.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")
|
|
|
|
out = switch_to_specialisation("${machine}", "", action="test")
|
|
|
|
# Ensure the service can be started when the activation script isn't in toplevel
|
|
# This is a lot like "Start a simple service", except activation-only deps could be gc-ed
|
|
out = run_switch("${nodes.machine.specialisation.simpleServiceSeparateActivationScript.configuration.system.build.separateActivationScript}/bin/switch-to-configuration");
|
|
assert_lacks(out, boot_loader_text) # test does not install a bootloader
|
|
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.service\n")
|
|
machine.succeed("! test -e /run/current-system/activate")
|
|
machine.succeed("! test -e /run/current-system/dry-activate")
|
|
machine.succeed("! test -e /run/current-system/bin/switch-to-configuration")
|
|
|
|
# Ensure units with multiline values work
|
|
out = switch_to_specialisation("${machine}", "unitWithMultilineValue")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_lacks(out, "reloading the following units:")
|
|
assert_lacks(out, "restarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
assert_contains(out, "starting the following units: test.service")
|
|
|
|
# Ensure \ works in unit names
|
|
out = switch_to_specialisation("${machine}", "unitWithBackslash")
|
|
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:")
|
|
|
|
# Ensure units can start with a dash
|
|
out = switch_to_specialisation("${machine}", "unitStartingWithDash")
|
|
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_lacks(out, "\nstarting the following units:")
|
|
assert_contains(out, "the following new units were started: -.service\n")
|
|
|
|
# The regression only occurs when reloading units
|
|
out = switch_to_specialisation("${machine}", "unitStartingWithDashModified")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: -.service")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Ensure units that require changed units are properly reloaded
|
|
out = switch_to_specialisation("${machine}", "unitWithRequirement")
|
|
assert_contains(out, "stopping the following units: -.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: required-service.service, test-service.service\n")
|
|
|
|
out = switch_to_specialisation("${machine}", "unitWithRequirementModified")
|
|
assert_contains(out, "stopping the following units: required-service.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: required-service.service, test-service.service\n")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Unless the unit asks to be not restarted
|
|
out = switch_to_specialisation("${machine}", "unitWithRequirementModifiedNostart")
|
|
assert_contains(out, "stopping the following units: required-service.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: required-service.service\n")
|
|
assert_lacks(out, "the following new units were started:")
|
|
|
|
# Ensure templated units are restarted when the base unit changes
|
|
switch_to_specialisation("${machine}", "unitWithTemplate")
|
|
out = switch_to_specialisation("${machine}", "unitWithTemplateModified")
|
|
assert_contains(out, "stopping the following units: instantiated@one.service, instantiated@two.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: instantiated@one.service, instantiated@two.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: ${sortedUnits [
|
|
"no-restart-service.service"
|
|
"reload-triggers-and-restart-by-as.service"
|
|
"simple-reload-service.service"
|
|
"simple-restart-service.service"
|
|
"simple-service.service"
|
|
"templated-no-restart-service@instance.service"
|
|
"templated-reload-triggers-and-restart-by-as@instance.service"
|
|
"templated-simple-reload-service@instance.service"
|
|
"templated-simple-restart-service@instance.service"
|
|
"templated-simple-service@instance.service"
|
|
]}\n")
|
|
assert_contains(out, "the following new units were started: ${sortedUnits [
|
|
"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"
|
|
"system-templated\\\\x2dno\\\\x2drestart\\\\x2dservice.slice"
|
|
"system-templated\\\\x2dreload\\\\x2dtriggers.slice"
|
|
"system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart.slice"
|
|
"system-templated\\\\x2dreload\\\\x2dtriggers\\\\x2dand\\\\x2drestart\\\\x2dby\\\\x2das.slice"
|
|
"system-templated\\\\x2dsimple\\\\x2dreload\\\\x2dservice.slice"
|
|
"system-templated\\\\x2dsimple\\\\x2drestart\\\\x2dservice.slice"
|
|
"system-templated\\\\x2dsimple\\\\x2dservice.slice"
|
|
"templated-no-restart-service@instance.service"
|
|
"templated-reload-triggers-and-restart-by-as@instance.service"
|
|
"templated-reload-triggers-and-restart@instance.service"
|
|
"templated-reload-triggers@instance.service"
|
|
"templated-simple-reload-service@instance.service"
|
|
"templated-simple-restart-service@instance.service"
|
|
"templated-simple-service@instance.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: ${sortedUnits [
|
|
"reload-triggers-and-restart.service"
|
|
"reload-triggers.service"
|
|
"simple-reload-service.service"
|
|
"templated-reload-triggers-and-restart@instance.service"
|
|
"templated-reload-triggers@instance.service"
|
|
"templated-simple-reload-service@instance.service"
|
|
]}\n")
|
|
assert_contains(out, "restarting the following units: ${sortedUnits [
|
|
"reload-triggers-and-restart-by-as.service"
|
|
"simple-restart-service.service"
|
|
"simple-service.service"
|
|
"templated-reload-triggers-and-restart-by-as@instance.service"
|
|
"templated-simple-restart-service@instance.service"
|
|
"templated-simple-service@instance.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: ${sortedUnits [
|
|
"reload-triggers.service"
|
|
"simple-reload-service.service"
|
|
"templated-reload-triggers@instance.service"
|
|
"templated-simple-reload-service@instance.service"
|
|
]}\n")
|
|
assert_contains(out, "restarting the following units: ${sortedUnits [
|
|
"reload-triggers-and-restart-by-as.service"
|
|
"reload-triggers-and-restart.service"
|
|
"simple-restart-service.service"
|
|
"simple-service.service"
|
|
"templated-reload-triggers-and-restart-by-as@instance.service"
|
|
"templated-reload-triggers-and-restart@instance.service"
|
|
"templated-simple-restart-service@instance.service"
|
|
"templated-simple-service@instance.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: ${sortedUnits [
|
|
"reload-triggers.service"
|
|
"simple-reload-service.service"
|
|
"templated-reload-triggers@instance.service"
|
|
"templated-simple-reload-service@instance.service"
|
|
]}\n")
|
|
assert_contains(out, "would restart the following units: ${sortedUnits [
|
|
"reload-triggers-and-restart-by-as.service"
|
|
"reload-triggers-and-restart.service"
|
|
"simple-restart-service.service"
|
|
"simple-service.service"
|
|
"templated-reload-triggers-and-restart-by-as@instance.service"
|
|
"templated-reload-triggers-and-restart@instance.service"
|
|
"templated-simple-restart-service@instance.service"
|
|
"templated-simple-service@instance.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")
|
|
# Changing options reloads the unit
|
|
out = switch_to_specialisation("${machine}", "mountOptionsModified")
|
|
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")
|
|
# Changing anything but `Options=` restarts the unit
|
|
out = switch_to_specialisation("${machine}", "mountModified")
|
|
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: testmount.mount\n")
|
|
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, "ramfs")
|
|
|
|
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
|
|
|
|
with subtest("dbus reloads"):
|
|
out = switch_to_specialisation("${machine}", "")
|
|
out = switch_to_specialisation("${machine}", "dbusReload")
|
|
assert_lacks(out, "stopping the following units:")
|
|
assert_lacks(out, "NOT restarting the following changed units:")
|
|
assert_contains(out, "reloading the following units: ${dbusService}\n")
|
|
assert_lacks(out, "\nrestarting the following units:")
|
|
assert_lacks(out, "\nstarting the following units:")
|
|
assert_lacks(out, "the following new units were started:")
|
|
'';
|
|
})
|