Add testcases for example services, make docker instantiatable, move process models for process managers into the backend folders

This commit is contained in:
Sander van der Burg 2021-04-01 20:30:30 +02:00 committed by Sander van der Burg
parent 7b46303479
commit 33c70b550f
21 changed files with 438 additions and 21 deletions

View File

@ -38,7 +38,7 @@ in
};
docker = import ./docker {
inherit createManagedProcess;
inherit createManagedProcess runtimeDir libDir;
inherit (pkgs) docker kmod;
};

View File

@ -1,13 +1,23 @@
{createManagedProcess, docker, kmod}:
{createManagedProcess, docker, kmod, runtimeDir, libDir}:
{instanceSuffix ? "", instanceName ? "docker${instanceSuffix}", extraArgs ? []}:
let
user = "docker";
group = "docker";
user = instanceName;
group = instanceName;
in
createManagedProcess {
name = "docker";
inherit instanceName;
foregroundProcess = "${docker}/bin/dockerd";
args = [ "--group=${group}" "--host=unix://" "--log-driver=json-file" ];
args = [
"--group=${group}"
"--host=unix://${runtimeDir}/${instanceName}.sock"
# Add -alt suffix. We only need PID files for the backends that requires processes to daemonize on their own.
# The `daemon` command will create PID files for them. Without the -alt suffix they will conflict causing the Docker daemon to refuse to start.
"--pidfile=${runtimeDir}/${instanceName}-alt.pid"
"--data-root=${libDir}/${instanceName}"
"--exec-root=${runtimeDir}/${instanceName}"
"--log-driver=json-file"
] ++ extraArgs;
path = [ kmod ];
credentials = {

View File

@ -29,6 +29,6 @@ rec {
};
docker = {
pkg = constructors.docker;
pkg = constructors.docker {};
};
}

View File

@ -7,12 +7,13 @@ let
processesEnvProcessManager = import ../../sysvinit/build-sysvinit-env.nix ({
inherit pkgs system;
exprFile = ../../../../tests/processes-docker.nix;
exprFile = ./processes-docker.nix;
} // profileSettings.params);
processesEnvSystem = import ../build-docker-env.nix ({
inherit pkgs system exprFile extraParams;
} // profileSettings.params);
}
// profileSettings.params);
in
{
nixosModules = [];

View File

@ -11,12 +11,12 @@
}:
let
constructors = import ../examples/services-agnostic/constructors/constructors.nix {
constructors = import ../../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
};
in
rec {
docker = {
pkg = constructors.docker;
pkg = constructors.docker {};
};
}

View File

@ -7,7 +7,7 @@ let
processesEnvProcessManager = import ../../sysvinit/build-sysvinit-env.nix ({
inherit pkgs system;
exprFile = ../../../../tests/processes-s6-svscan.nix;
exprFile = ./processes-s6-svscan.nix;
} // profileSettings.params);
processesEnvSystem = import ../build-s6-rc-env.nix ({

View File

@ -11,7 +11,7 @@
}:
let
constructors = import ../examples/services-agnostic/constructors/constructors.nix {
constructors = import ../../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
};
in

View File

@ -7,7 +7,7 @@ let
processesEnvProcessManager = import ../../sysvinit/build-sysvinit-env.nix ({
inherit pkgs system;
exprFile = ../../../../tests/processes-supervisord.nix;
exprFile = ./processes-supervisord.nix;
} // profileSettings.params);
processesEnvSystem = import ../build-supervisord-env.nix ({

View File

@ -11,7 +11,7 @@
}:
let
constructors = import ../examples/services-agnostic/constructors/constructors.nix {
constructors = import ../../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
};
in

View File

@ -0,0 +1,28 @@
{ pkgs ? import <nixpkgs> { inherit system; }
, system ? builtins.currentSystem
, processManagers ? [ "supervisord" "sysvinit" "systemd" "docker" "disnix" "s6-rc" ]
, profiles ? [ "privileged" "unprivileged" ]
}:
let
testService = import ../../nixproc/test-driver/universal.nix {
inherit system;
};
in
{
docker = import ./docker {
inherit pkgs processManagers profiles testService;
};
nginx-reverse-proxy-hostbased = import ./nginx-reverse-proxy-hostbased {
inherit pkgs processManagers profiles testService;
};
s6-svscan = import ./s6-svscan {
inherit pkgs processManagers profiles testService;
};
supervisord = import ./supervisord {
inherit pkgs processManagers profiles testService;
};
}

View File

@ -0,0 +1,26 @@
{ pkgs, testService, processManagers, profiles }:
testService {
exprFile = ./processes.nix;
systemPackages = [ pkgs.docker ];
readiness = {instanceName, instance, runtimeDir, ...}:
''
machine.wait_for_file("${runtimeDir}/${instanceName}.sock")
'';
tests = {instanceName, instance, stateDir, runtimeDir, forceDisableUserChange, ...}:
# The primary instance should be connectible with the default parameters
if instanceName == "docker" && !forceDisableUserChange then ''
machine.succeed("docker info | grep 'Docker Root Dir: ${stateDir}/lib/${instanceName}'")
'' else ''
machine.succeed(
"docker --host=unix://${runtimeDir}/${instanceName}.sock info | grep 'Docker Root Dir: ${stateDir}/lib/${instanceName}'"
)
'';
inherit processManagers;
# There's an experimental rootless feature for Docker, but a hassle to setup. As a result, we disable unprivileged mode
profiles = builtins.filter (profile: profile == "privileged") profiles;
}

View File

@ -0,0 +1,29 @@
{ pkgs ? import <nixpkgs> { inherit system; }
, system ? builtins.currentSystem
, stateDir ? "/var"
, runtimeDir ? "${stateDir}/run"
, logDir ? "${stateDir}/log"
, cacheDir ? "${stateDir}/cache"
, libDir ? "${stateDir}/lib"
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
, forceDisableUserChange ? false
, processManager
}:
let
constructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
};
in
rec {
docker = {
pkg = constructors.docker {};
};
docker-secondary = rec {
pkg = constructors.docker {
instanceSuffix = "-secondary";
extraArgs = [ "--iptables=false" ]; # Avoids conflicting NAT settings with the primary instances
};
};
}

View File

@ -0,0 +1,20 @@
{ pkgs, testService, processManagers, profiles }:
testService {
exprFile = ./processes.nix;
readiness = {instanceName, instance, ...}:
''
machine.wait_for_open_port(${toString instance.port})
'';
tests = {instanceName, instance, ...}:
pkgs.lib.optionalString (instanceName == "nginx" || instanceName == "nginx2")
(pkgs.lib.concatMapStrings (webapp: ''
machine.succeed(
"curl --fail -H 'Host: ${webapp.dnsName}' http://localhost:${toString instance.port} | grep ': ${toString webapp.port}'"
)
'') instance.webapps);
inherit processManagers profiles;
}

View File

@ -0,0 +1,102 @@
{ pkgs ? import <nixpkgs> { inherit system; }
, system ? builtins.currentSystem
, stateDir ? "/var"
, runtimeDir ? "${stateDir}/run"
, logDir ? "${stateDir}/log"
, cacheDir ? "${stateDir}/cache"
, libDir ? "${stateDir}/lib"
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
, forceDisableUserChange ? false
, processManager
}:
let
sharedConstructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir cacheDir libDir tmpDir forceDisableUserChange processManager;
};
constructors = import ../../../examples/webapps-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager;
webappMode = null;
};
in
rec {
webapp1 = rec {
port = 5000;
dnsName = "webapp1.local";
pkg = constructors.webapp {
inherit port;
instanceSuffix = "1";
};
};
webapp2 = rec {
port = 5001;
dnsName = "webapp2.local";
pkg = constructors.webapp {
inherit port;
instanceSuffix = "2";
};
};
webapp3 = rec {
port = 5002;
dnsName = "webapp3.local";
pkg = constructors.webapp {
inherit port;
instanceSuffix = "3";
};
};
webapp4 = rec {
port = 5003;
dnsName = "webapp4.local";
pkg = constructors.webapp {
inherit port;
instanceSuffix = "4";
};
};
nginx = rec {
port = if forceDisableUserChange then 8080 else 80;
webapps = [ webapp1 webapp2 webapp3 webapp4 ];
pkg = sharedConstructors.nginxReverseProxyHostBased {
inherit port webapps;
} {};
};
webapp5 = rec {
port = 5004;
dnsName = "webapp5.local";
pkg = constructors.webapp {
inherit port;
instanceSuffix = "5";
};
};
webapp6 = rec {
port = 5005;
dnsName = "webapp6.local";
pkg = constructors.webapp {
inherit port;
instanceSuffix = "6";
};
};
nginx2 = rec {
port = if forceDisableUserChange then 8081 else 8080;
webapps = [ webapp5 webapp6 ];
pkg = sharedConstructors.nginxReverseProxyHostBased {
inherit port webapps;
instanceSuffix = "2";
} {};
};
}

View File

@ -0,0 +1,81 @@
{ pkgs, testService, processManagers, profiles }:
let
generateTestExecutable = instanceName:
pkgs.writeTextFile {
name = "test-${instanceName}";
text = ''
#! ${pkgs.stdenv.shell} -e
while true
do
echo "Hello ${instanceName}!" >&2
sleep 1
done
'';
executable = true;
};
generateTestConfigDir = instanceName:
pkgs.stdenv.mkDerivation {
name = "sv";
buildCommand = ''
mkdir -p $out/test-${instanceName}
cd $out/test-${instanceName}
# Generate longrun service for test process
echo "longrun" > type
cat > run <<EOF
#!${pkgs.execline}/bin/execlineb -P
exec ${generateTestExecutable instanceName}
EOF
# Generate default bundle containing the above service
mkdir -p ../default
cd ../default
echo "bundle" > type
cat > contents <<EOF
test-${instanceName}
EOF
'';
};
in
testService {
exprFile = ./processes.nix;
systemPackages = [ pkgs.s6-rc ];
readiness = {instanceName, instance, runtimeDir, ...}:
''
machine.wait_for_file("${runtimeDir}/service${instance.instanceSuffix}/.s6-svscan")
'';
tests = {instanceName, instance, stateDir, runtimeDir, forceDisableUserChange, ...}:
let
liveDir = "${stateDir}/run/s6-rc${instance.instanceSuffix}";
compileDir = "${stateDir}/etc/s6${instance.instanceSuffix}/rc";
compiledDatabasePath = "${compileDir}/compiled";
in
''
# fmt: off
machine.succeed(
"${pkgs.lib.optionalString forceDisableUserChange "su unprivileged -c '"}mkdir -p ${compileDir}${pkgs.lib.optionalString forceDisableUserChange "'"}"
)
machine.succeed(
"${pkgs.lib.optionalString forceDisableUserChange "su unprivileged -c '"}s6-rc-compile ${compiledDatabasePath} ${generateTestConfigDir instanceName}${pkgs.lib.optionalString forceDisableUserChange "'"}"
)
machine.succeed(
"${pkgs.lib.optionalString forceDisableUserChange "su unprivileged -c '"}s6-rc-init -c ${compiledDatabasePath} -l ${liveDir} ${runtimeDir}/service${instance.instanceSuffix}${pkgs.lib.optionalString forceDisableUserChange "'"}"
)
machine.succeed(
"${pkgs.lib.optionalString forceDisableUserChange "su unprivileged -c '"}s6-rc -l ${liveDir} -u change default${pkgs.lib.optionalString forceDisableUserChange "'"}"
)
# fmt: on
machine.succeed("sleep 1")
machine.succeed(
"pgrep -f '${generateTestExecutable instanceName}'"
)
'';
inherit processManagers profiles;
}

View File

@ -0,0 +1,32 @@
{ pkgs ? import <nixpkgs> { inherit system; }
, system ? builtins.currentSystem
, stateDir ? "/var"
, runtimeDir ? "${stateDir}/run"
, logDir ? "${stateDir}/log"
, cacheDir ? "${stateDir}/cache"
, libDir ? "${stateDir}/lib"
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
, forceDisableUserChange ? false
, processManager
}:
let
constructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
};
in
rec {
s6-svscan-primary = rec {
instanceSuffix = "-primary";
pkg = constructors.s6-svscan {
inherit instanceSuffix;
};
};
s6-svscan-secondary = rec {
instanceSuffix = "-secondary";
pkg = constructors.s6-svscan {
inherit instanceSuffix;
};
};
}

View File

@ -0,0 +1,51 @@
{ pkgs, testService, processManagers, profiles }:
let
generateTestExecutable = instanceName:
pkgs.writeTextFile {
name = "test-${instanceName}";
text = ''
#! ${pkgs.stdenv.shell} -e
while true
do
echo "Hello ${instanceName}!" >&2
sleep 1
done
'';
executable = true;
};
generateTestConf = instanceName:
pkgs.writeTextFile {
name = "test-${instanceName}.conf";
text = ''
[program:test-${instanceName}]
command=${generateTestExecutable instanceName}
'';
};
in
testService {
exprFile = ./processes.nix;
systemPackages = [ pkgs.pythonPackages.supervisor ];
readiness = {instanceName, instance, ...}:
''
machine.wait_for_open_port(${toString instance.port})
'';
tests = {instanceName, instance, stateDir, ...}:
''
machine.succeed(
"cp ${generateTestConf instanceName} ${stateDir}/lib/${instanceName}/conf.d"
)
machine.succeed("supervisorctl --serverurl http://localhost:${toString instance.port} reread")
machine.succeed("supervisorctl --serverurl http://localhost:${toString instance.port} update")
machine.succeed("sleep 1")
machine.succeed(
"pgrep -f '${generateTestExecutable instanceName}'"
)
'';
inherit processManagers profiles;
}

View File

@ -0,0 +1,37 @@
{ pkgs ? import <nixpkgs> { inherit system; }
, system ? builtins.currentSystem
, stateDir ? "/var"
, runtimeDir ? "${stateDir}/run"
, logDir ? "${stateDir}/log"
, cacheDir ? "${stateDir}/cache"
, libDir ? "${stateDir}/lib"
, tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
, forceDisableUserChange ? false
, processManager
}:
let
constructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
};
in
rec {
supervisord-primary = rec {
# Special situation: we can only bootstrap supervisord with supervisord if we don't conflict with the managing supervisord's port
port = if processManager == "supervisord" then 9003 else 9001;
pkg = constructors.extendableSupervisord {
inetHTTPServerPort = port;
instanceSuffix = "-primary";
};
};
supervisord-secondary = rec {
port = 9002;
pkg = constructors.extendableSupervisord {
inetHTTPServerPort = port;
instanceSuffix = "-secondary";
};
};
}

View File

@ -6,7 +6,7 @@ let
stateDir = "/dockervar";
dockerProcessEnv = import ../nixproc/backends/systemd/build-systemd-env.nix {
exprFile = ./processes-docker.nix;
exprFile = ../nixproc/backends/docker/test-module/processes-docker.nix;
inherit stateDir;
};
@ -112,7 +112,7 @@ makeTest {
# Deploy Docker as a systemd unit
machine.succeed(
"${env} nixproc-systemd-switch ${nix-processmgmt}/tests/processes-docker.nix"
"${env} nixproc-systemd-switch ${nix-processmgmt}/nixproc/backends/docker/test-module/processes-docker.nix"
)
machine.wait_for_unit("nix-process-docker")

View File

@ -4,7 +4,7 @@ with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.curren
let
s6-svscanProcessEnv = import ../nixproc/backends/systemd/build-systemd-env.nix {
exprFile = ./processes-s6-svscan.nix;
exprFile = ../nixproc/backends/s6-rc/test-module/processes-s6-svscan.nix;
};
processesEnvForeground = import ../nixproc/backends/s6-rc/build-s6-rc-env.nix {
@ -108,7 +108,7 @@ makeTest {
# Deploy s6-svscan as a systemd unit
machine.succeed(
"${env} nixproc-systemd-switch ${nix-processmgmt}/tests/processes-s6-svscan.nix"
"${env} nixproc-systemd-switch ${nix-processmgmt}/nixproc/backends/s6-rc/test-module/processes-s6-svscan.nix"
)
# Deploy the system with foreground webapp processes

View File

@ -4,7 +4,7 @@ with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.curren
let
supervisordProcessEnv = import ../nixproc/backends/systemd/build-systemd-env.nix {
exprFile = ./processes-supervisord.nix;
exprFile = ../nixproc/backends/supervisord/test-module/processes-supervisord.nix;
};
processesEnvForeground = import ../nixproc/backends/supervisord/build-supervisord-env.nix {
@ -107,7 +107,7 @@ makeTest {
# Deploy supervisord as a systemd unit
machine.succeed(
"${env} nixproc-systemd-switch ${nix-processmgmt}/tests/processes-supervisord.nix"
"${env} nixproc-systemd-switch ${nix-processmgmt}/nixproc/backends/supervisord/test-module/processes-supervisord.nix"
)
machine.wait_for_open_port(9001)