diff --git a/examples/services-agnostic/constructors/constructors.nix b/examples/services-agnostic/constructors/constructors.nix index 91f2ac0..9400ca6 100644 --- a/examples/services-agnostic/constructors/constructors.nix +++ b/examples/services-agnostic/constructors/constructors.nix @@ -38,7 +38,7 @@ in }; docker = import ./docker { - inherit createManagedProcess; + inherit createManagedProcess runtimeDir libDir; inherit (pkgs) docker kmod; }; diff --git a/examples/services-agnostic/constructors/docker/default.nix b/examples/services-agnostic/constructors/docker/default.nix index 16e3f13..c98cc2d 100644 --- a/examples/services-agnostic/constructors/docker/default.nix +++ b/examples/services-agnostic/constructors/docker/default.nix @@ -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 = { diff --git a/examples/services-agnostic/processes.nix b/examples/services-agnostic/processes.nix index 8790199..38c84bd 100644 --- a/examples/services-agnostic/processes.nix +++ b/examples/services-agnostic/processes.nix @@ -29,6 +29,6 @@ rec { }; docker = { - pkg = constructors.docker; + pkg = constructors.docker {}; }; } diff --git a/nixproc/backends/docker/test-module/default.nix b/nixproc/backends/docker/test-module/default.nix index 7bfffef..e4d9c6a 100644 --- a/nixproc/backends/docker/test-module/default.nix +++ b/nixproc/backends/docker/test-module/default.nix @@ -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 = []; diff --git a/tests/processes-docker.nix b/nixproc/backends/docker/test-module/processes-docker.nix similarity index 79% rename from tests/processes-docker.nix rename to nixproc/backends/docker/test-module/processes-docker.nix index 603e546..84acf34 100644 --- a/tests/processes-docker.nix +++ b/nixproc/backends/docker/test-module/processes-docker.nix @@ -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 {}; }; } diff --git a/nixproc/backends/s6-rc/test-module/default.nix b/nixproc/backends/s6-rc/test-module/default.nix index e612629..8dba800 100644 --- a/nixproc/backends/s6-rc/test-module/default.nix +++ b/nixproc/backends/s6-rc/test-module/default.nix @@ -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 ({ diff --git a/tests/processes-s6-svscan.nix b/nixproc/backends/s6-rc/test-module/processes-s6-svscan.nix similarity index 85% rename from tests/processes-s6-svscan.nix rename to nixproc/backends/s6-rc/test-module/processes-s6-svscan.nix index 99cdaa3..606ae8c 100644 --- a/tests/processes-s6-svscan.nix +++ b/nixproc/backends/s6-rc/test-module/processes-s6-svscan.nix @@ -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 diff --git a/nixproc/backends/supervisord/test-module/default.nix b/nixproc/backends/supervisord/test-module/default.nix index 00a8565..1b92edd 100644 --- a/nixproc/backends/supervisord/test-module/default.nix +++ b/nixproc/backends/supervisord/test-module/default.nix @@ -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 ({ diff --git a/tests/processes-supervisord.nix b/nixproc/backends/supervisord/test-module/processes-supervisord.nix similarity index 85% rename from tests/processes-supervisord.nix rename to nixproc/backends/supervisord/test-module/processes-supervisord.nix index 3fba6b3..062cef7 100644 --- a/tests/processes-supervisord.nix +++ b/nixproc/backends/supervisord/test-module/processes-supervisord.nix @@ -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 diff --git a/tests/services/default.nix b/tests/services/default.nix new file mode 100644 index 0000000..545fd66 --- /dev/null +++ b/tests/services/default.nix @@ -0,0 +1,28 @@ +{ pkgs ? import { 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; + }; +} diff --git a/tests/services/docker/default.nix b/tests/services/docker/default.nix new file mode 100644 index 0000000..e68dd08 --- /dev/null +++ b/tests/services/docker/default.nix @@ -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; +} diff --git a/tests/services/docker/processes.nix b/tests/services/docker/processes.nix new file mode 100644 index 0000000..de33254 --- /dev/null +++ b/tests/services/docker/processes.nix @@ -0,0 +1,29 @@ +{ pkgs ? import { 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 + }; + }; +} diff --git a/tests/services/nginx-reverse-proxy-hostbased/default.nix b/tests/services/nginx-reverse-proxy-hostbased/default.nix new file mode 100644 index 0000000..6045c3f --- /dev/null +++ b/tests/services/nginx-reverse-proxy-hostbased/default.nix @@ -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; +} diff --git a/tests/services/nginx-reverse-proxy-hostbased/processes.nix b/tests/services/nginx-reverse-proxy-hostbased/processes.nix new file mode 100644 index 0000000..2a33849 --- /dev/null +++ b/tests/services/nginx-reverse-proxy-hostbased/processes.nix @@ -0,0 +1,102 @@ +{ pkgs ? import { 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"; + } {}; + }; +} diff --git a/tests/services/s6-svscan/default.nix b/tests/services/s6-svscan/default.nix new file mode 100644 index 0000000..d198cdb --- /dev/null +++ b/tests/services/s6-svscan/default.nix @@ -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 < type + cat > contents < { 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; + }; + }; +} diff --git a/tests/services/supervisord/default.nix b/tests/services/supervisord/default.nix new file mode 100644 index 0000000..ff5891d --- /dev/null +++ b/tests/services/supervisord/default.nix @@ -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; +} diff --git a/tests/services/supervisord/processes.nix b/tests/services/supervisord/processes.nix new file mode 100644 index 0000000..25da4d4 --- /dev/null +++ b/tests/services/supervisord/processes.nix @@ -0,0 +1,37 @@ +{ pkgs ? import { 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"; + }; + }; +} diff --git a/tests/webapps-agnostic-docker.nix b/tests/webapps-agnostic-docker.nix index 9b20652..41ec232 100644 --- a/tests/webapps-agnostic-docker.nix +++ b/tests/webapps-agnostic-docker.nix @@ -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") diff --git a/tests/webapps-agnostic-s6-rc.nix b/tests/webapps-agnostic-s6-rc.nix index 519b245..2acc6a2 100644 --- a/tests/webapps-agnostic-s6-rc.nix +++ b/tests/webapps-agnostic-s6-rc.nix @@ -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 diff --git a/tests/webapps-agnostic-supervisord.nix b/tests/webapps-agnostic-supervisord.nix index 7e91dec..1ac4fde 100644 --- a/tests/webapps-agnostic-supervisord.nix +++ b/tests/webapps-agnostic-supervisord.nix @@ -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)