├── nixproc
├── backends
│ ├── s6-rc
│ │ ├── image-steps
│ │ │ ├── dynamic-steps.nix
│ │ │ ├── static-steps.nix
│ │ │ ├── s6-rc-dynamic.nix
│ │ │ ├── s6-rc-static.nix
│ │ │ └── s6-rc.nix
│ │ ├── default.nix
│ │ ├── test-module
│ │ │ ├── processes-s6-svscan.nix
│ │ │ └── default.nix
│ │ ├── create-service-bundle.nix
│ │ ├── util.nix
│ │ ├── create-log-service-for-longrun-service.nix
│ │ ├── build-s6-rc-env.nix
│ │ └── create-oneshot-service.nix
│ ├── disnix
│ │ ├── image-steps
│ │ │ ├── dynamic-steps.nix
│ │ │ ├── static-steps.nix
│ │ │ ├── disnix.nix
│ │ │ ├── disnix-static.nix
│ │ │ └── disnix-dynamic.nix
│ │ ├── create-process-script.nix
│ │ ├── test-module
│ │ │ └── default.nix
│ │ ├── services-adapter.nix
│ │ ├── build-disnix-env.nix
│ │ └── generate-process-script.nix
│ ├── sysvinit
│ │ ├── image-steps
│ │ │ ├── dynamic-steps.nix
│ │ │ ├── static-steps.nix
│ │ │ ├── sysvinit.nix
│ │ │ ├── sysvinit-dynamic.nix
│ │ │ └── sysvinit-static.nix
│ │ ├── test-module
│ │ │ └── default.nix
│ │ ├── init-functions.nix
│ │ ├── generate-sysvinit-script.nix
│ │ └── build-sysvinit-env.nix
│ ├── supervisord
│ │ ├── image-steps
│ │ │ ├── dynamic-steps.nix
│ │ │ ├── static-steps.nix
│ │ │ ├── supervisord.nix
│ │ │ ├── supervisord-dynamic.nix
│ │ │ └── supervisord-static.nix
│ │ ├── supervisord.conf
│ │ ├── test-module
│ │ │ ├── processes-supervisord.nix
│ │ │ └── default.nix
│ │ ├── build-supervisord-env.nix
│ │ ├── generate-supervisord-program.nix
│ │ └── create-supervisord-program.nix
│ ├── systemd
│ │ ├── test-module
│ │ │ ├── systemd-path.nix
│ │ │ ├── xserver-autologin-module.nix
│ │ │ └── default.nix
│ │ ├── build-systemd-env.nix
│ │ └── generate-systemd-service.nix
│ ├── util
│ │ ├── generate-prestart-script.nix
│ │ ├── generate-compound-proxy.nix
│ │ ├── generate-foreground-proxy.nix
│ │ └── default.nix
│ ├── bsdrc
│ │ ├── rcsubr.nix
│ │ ├── build-bsdrc-env.nix
│ │ └── generate-bsdrc-script.nix
│ ├── docker
│ │ ├── test-module
│ │ │ ├── processes-docker.nix
│ │ │ └── default.nix
│ │ ├── build-docker-env.nix
│ │ └── create-docker-container.nix
│ ├── launchd
│ │ ├── build-launchd-env.nix
│ │ ├── generate-launchd-daemon.nix
│ │ └── create-launchd-daemon.nix
│ └── cygrunsrv
│ │ ├── build-cygrunsrv-env.nix
│ │ ├── generate-cygrunsrv-params.nix
│ │ └── create-cygrunsrv-params.nix
├── create-image-from-steps
│ ├── generate-config-from-steps.nix
│ ├── steps
│ │ ├── init.nix
│ │ ├── man.nix
│ │ ├── nix-processmgmt-static.nix
│ │ ├── basic.nix
│ │ ├── su-pam.nix
│ │ ├── bootstrap-init.nix
│ │ ├── interactive.nix
│ │ ├── nix-support.nix
│ │ └── nix-processmgmt-dynamic.nix
│ ├── create-image-from-steps.nix
│ ├── create-nix-image.nix
│ ├── create-multi-process-image-universal.nix
│ ├── create-mutable-multi-process-image-universal.nix
│ ├── create-multi-process-image.nix
│ └── create-mutable-multi-process-image.nix
├── test-driver
│ ├── util
│ │ ├── execute-command.nix
│ │ └── execute-deploy.nix
│ ├── profiles
│ │ ├── privileged.nix
│ │ ├── unprivileged-user-module.nix
│ │ └── unprivileged.nix
│ ├── universal.nix
│ └── agnostic.nix
├── create-managed-process
│ └── agnostic
│ │ ├── create-agnostic-config.nix
│ │ ├── create-managed-process-from-config.nix
│ │ └── create-managed-process.nix
├── derive-dysnomia-process-type.nix
└── create-credentials
│ └── default.nix
├── examples
├── webapps-agnostic
│ ├── infra-bootstrap.nix
│ ├── distribution.nix
│ ├── idresources.nix
│ ├── network-physical.nix
│ ├── ids.nix
│ ├── constructors
│ │ ├── constructors.nix
│ │ └── webapp
│ │ │ ├── webapp-fg.nix
│ │ │ ├── default.nix
│ │ │ └── webapp-daemon.nix
│ ├── ids-advanced.nix
│ ├── network-logical.nix
│ ├── processes.nix
│ ├── services.nix
│ └── processes-advanced.nix
├── webapps-sysvinit
│ ├── distribution.nix
│ ├── constructors
│ │ ├── nginx
│ │ │ ├── errorpage
│ │ │ │ └── index.html
│ │ │ ├── default.nix
│ │ │ └── nginx-reverse-proxy.nix
│ │ ├── webapp
│ │ │ └── default.nix
│ │ └── constructors.nix
│ ├── idresources.nix
│ ├── network-physical.nix
│ ├── network-logical.nix
│ ├── ids.nix
│ ├── ids-advanced.nix
│ ├── processes.nix
│ ├── services.nix
│ └── processes-advanced.nix
├── services-agnostic
│ ├── idresources.nix
│ ├── ids.nix
│ ├── constructors
│ │ ├── nginx
│ │ │ ├── errorpage
│ │ │ │ └── index.html
│ │ │ ├── default.nix
│ │ │ └── nginx-reverse-proxy-hostbased.nix
│ │ ├── supervisord
│ │ │ ├── default.nix
│ │ │ └── extendable.nix
│ │ ├── s6-svscan
│ │ │ └── default.nix
│ │ ├── docker
│ │ │ └── default.nix
│ │ └── constructors.nix
│ └── processes.nix
├── multi-process-image
│ └── default.nix
└── service-containers-agnostic
│ ├── constructors.nix
│ └── extendable.nix
├── tools
├── chainload-user
│ ├── default.nix
│ ├── Makefile
│ └── main.c
├── supervisord
│ ├── supervisordchecks
│ └── default.nix
├── generate-config
│ └── default.nix
├── sysvinit
│ ├── sysvinitchecks
│ ├── default.nix
│ └── nixproc-sysvinit-runactivity.in
├── s6-rc
│ ├── s6-rc-checks
│ ├── default.nix
│ └── nixproc-s6-svscan.in
├── idassign
│ └── default.nix
├── disnix
│ └── default.nix
├── systemd
│ └── default.nix
├── cygrunsrv
│ └── default.nix
├── launchd
│ └── default.nix
├── docker
│ └── default.nix
├── common
│ └── default.nix
├── bsdrc
│ ├── default.nix
│ └── nixproc-bsdrc-runactivity.in
└── default.nix
├── webapp
├── default.nix
├── Makefile
├── README.md
├── service.h
├── daemonize.h
└── main.c
├── tests
├── builds.nix
├── services
│ ├── nginx-reverse-proxy-hostbased
│ │ ├── default.nix
│ │ └── processes.nix
│ ├── default.nix
│ ├── docker
│ │ ├── processes.nix
│ │ └── default.nix
│ ├── s6-svscan
│ │ ├── processes.nix
│ │ └── default.nix
│ └── supervisord
│ │ ├── processes.nix
│ │ └── default.nix
├── webapps-agnostic-supervisord-stateless.nix
├── webapps-agnostic-config.nix
└── multi-process-images.nix
├── LICENSE
└── release.nix
/nixproc/backends/s6-rc/image-steps/dynamic-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./s6-rc.nix
3 | ./s6-rc-dynamic.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/image-steps/static-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./s6-rc.nix
3 | ./s6-rc-static.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/image-steps/dynamic-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./disnix.nix
3 | ./disnix-dynamic.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/image-steps/static-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./disnix.nix
3 | ./disnix-static.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/image-steps/dynamic-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./sysvinit.nix
3 | ./sysvinit-dynamic.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/image-steps/static-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./sysvinit.nix
3 | ./sysvinit-static.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/image-steps/dynamic-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./supervisord.nix
3 | ./supervisord-dynamic.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/image-steps/static-steps.nix:
--------------------------------------------------------------------------------
1 | [
2 | ./supervisord.nix
3 | ./supervisord-static.nix
4 | ]
5 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/infra-bootstrap.nix:
--------------------------------------------------------------------------------
1 | {
2 | test1.properties.hostname = "test1";
3 | test2.properties.hostname = "test2";
4 | }
5 |
--------------------------------------------------------------------------------
/nixproc/backends/systemd/test-module/systemd-path.nix:
--------------------------------------------------------------------------------
1 | {...}:
2 |
3 | {
4 | boot.extraSystemdUnitPaths = [ "/etc/systemd-mutable/system" ];
5 | }
6 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/distribution.nix:
--------------------------------------------------------------------------------
1 | {infrastructure}:
2 |
3 | {
4 | webapp = [ infrastructure.test1 ];
5 | nginxReverseProxy = [ infrastructure.test2 ];
6 | }
7 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/image-steps/disnix.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // {
4 | contents = result.contents or [] ++ [ pkgs.disnix pkgs.dysnomia ];
5 | }
6 |
--------------------------------------------------------------------------------
/tools/chainload-user/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-chainload-user";
5 | src = ./.;
6 | makeFlags = "PREFIX=$(out)";
7 | dontStrip = true;
8 | }
9 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/image-steps/sysvinit.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // {
4 | contents = result.contents or [] ++ [ pkgs.sysvinit pkgs.gnugrep pkgs.coreutils ];
5 | }
6 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/distribution.nix:
--------------------------------------------------------------------------------
1 | {infrastructure}:
2 |
3 | {
4 | webapp = [ infrastructure.test1 ];
5 | webapp2 = [ infrastructure.test2 ];
6 | nginx = [ infrastructure.test2 ];
7 | }
8 |
--------------------------------------------------------------------------------
/examples/services-agnostic/idresources.nix:
--------------------------------------------------------------------------------
1 | rec {
2 | uids = {
3 | min = 2000;
4 | max = 3000;
5 | };
6 |
7 | gids = uids;
8 |
9 | inetHTTPPorts = {
10 | min = 9001;
11 | max = 9091;
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/generate-config-from-steps.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common ? {}, input, steps}:
2 |
3 | pkgs.lib.foldl (result: moduleFile:
4 | import moduleFile {
5 | inherit pkgs common input result;
6 | }
7 | ) {} steps
8 |
--------------------------------------------------------------------------------
/nixproc/test-driver/util/execute-command.nix:
--------------------------------------------------------------------------------
1 | {lib}:
2 | {forceDisableUserChange, command}:
3 |
4 | lib.optionalString forceDisableUserChange "su - unprivileged -c '"
5 | + command
6 | + lib.optionalString forceDisableUserChange "'"
7 |
--------------------------------------------------------------------------------
/nixproc/test-driver/profiles/privileged.nix:
--------------------------------------------------------------------------------
1 | {
2 | params = rec {
3 | stateDir = "/var";
4 | runtimeDir = "${stateDir}/run";
5 | forceDisableUserChange = false;
6 | };
7 |
8 | deployArgs = "";
9 |
10 | nixosModules = [];
11 | }
12 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/init.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | buildImageFormalArgs = builtins.functionArgs pkgs.dockerTools.buildImage;
5 | buildImageArgs = builtins.intersectAttrs buildImageFormalArgs input;
6 | in
7 | buildImageArgs
8 |
--------------------------------------------------------------------------------
/examples/services-agnostic/ids.nix:
--------------------------------------------------------------------------------
1 | {
2 | "ids" = {
3 | "gids" = {
4 | };
5 | "inetHTTPPorts" = {
6 | "supervisord" = 9001;
7 | };
8 | "uids" = {
9 | };
10 | };
11 | "lastAssignments" = {
12 | "inetHTTPPorts" = 9001;
13 | };
14 | }
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/create-image-from-steps.nix:
--------------------------------------------------------------------------------
1 | {pkgs, steps, common ? {}, input}:
2 |
3 | let
4 | generatedConfig = import ./generate-config-from-steps.nix {
5 | inherit pkgs common input steps;
6 | };
7 | in
8 | pkgs.dockerTools.buildImage generatedConfig
9 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/nginx/errorpage/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Error page
5 |
6 |
7 |
8 | This web application is unavailable at the moment!
9 |
10 |
11 |
--------------------------------------------------------------------------------
/nixproc/backends/util/generate-prestart-script.nix:
--------------------------------------------------------------------------------
1 | { stdenv, writeTextFile }:
2 | { name, initialize }:
3 |
4 | writeTextFile {
5 | name = "${name}-prestart";
6 | executable = true;
7 | text = ''
8 | #! ${stdenv.shell} -e
9 | ${initialize}
10 | '';
11 | }
12 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/constructors/nginx/errorpage/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Disnix VirtualHosts example
5 |
6 |
7 |
8 | This web application is unavailable at the moment!
9 |
10 |
11 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 |
3 | [include]
4 | files=conf.d/*
5 |
6 | [inet_http_server]
7 | port = 127.0.0.1:9001
8 |
9 | [rpcinterface:supervisor]
10 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
11 |
12 | [supervisorctl]
13 |
--------------------------------------------------------------------------------
/tools/chainload-user/Makefile:
--------------------------------------------------------------------------------
1 | CC = cc
2 |
3 | all:
4 | $(CC) $(CFLAGS) $(LDFLAGS) main.c -o nixproc-chainload-user
5 |
6 | install: all
7 | install -d -m755 $(PREFIX)/bin
8 | install -m755 nixproc-chainload-user $(PREFIX)/bin
9 |
10 | clean:
11 | rm -f *.o
12 | rm -f nixproc-chainload-user
13 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/idresources.nix:
--------------------------------------------------------------------------------
1 | rec {
2 | webappPorts = {
3 | min = 5000;
4 | max = 6000;
5 | };
6 |
7 | nginxPorts = {
8 | min = 8080;
9 | max = 9000;
10 | };
11 |
12 | uids = {
13 | min = 2000;
14 | max = 3000;
15 | };
16 |
17 | gids = uids;
18 | }
19 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/idresources.nix:
--------------------------------------------------------------------------------
1 | rec {
2 | webappPorts = {
3 | min = 5000;
4 | max = 6000;
5 | };
6 |
7 | nginxPorts = {
8 | min = 8080;
9 | max = 9000;
10 | };
11 |
12 | uids = {
13 | min = 2000;
14 | max = 3000;
15 | };
16 |
17 | gids = uids;
18 | }
19 |
--------------------------------------------------------------------------------
/tools/supervisord/supervisordchecks:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | checkSupervisordConfDir()
4 | {
5 | if [ "$SUPERVISORD_CONF_DIR" = "" ]
6 | then
7 | echo "Please set SUPERVISORD_CONF_DIR to the directory where the supervisord.conf configuration resides!" >&2
8 | exit 1
9 | fi
10 | }
11 |
--------------------------------------------------------------------------------
/webapp/default.nix:
--------------------------------------------------------------------------------
1 | with import {};
2 |
3 | stdenv.mkDerivation {
4 | name = "webapp";
5 | src = ./.;
6 | buildInputs = [ libmicrohttpd ];
7 | CFLAGS = "-I${libmicrohttpd.dev}/include";
8 | LDFLAGS = "-L${libmicrohttpd}/lib";
9 | makeFlags = "PREFIX=$(out)";
10 | dontStrip = true;
11 | }
12 |
--------------------------------------------------------------------------------
/webapp/Makefile:
--------------------------------------------------------------------------------
1 | CC = cc
2 |
3 | all:
4 | $(CC) $(CFLAGS) -c daemonize.c
5 | $(CC) $(CFLAGS) -c service.c
6 | $(CC) $(CFLAGS) $(LDFLAGS) daemonize.o service.o main.c -lmicrohttpd -o webapp
7 |
8 | install: all
9 | install -d -m755 $(PREFIX)/bin
10 | install -m755 webapp $(PREFIX)/bin
11 |
12 | clean:
13 | rm -f *.o
14 | rm -f webapp
15 |
--------------------------------------------------------------------------------
/nixproc/test-driver/profiles/unprivileged-user-module.nix:
--------------------------------------------------------------------------------
1 | {
2 | users.extraUsers = {
3 | unprivileged = {
4 | uid = 1000;
5 | group = "users";
6 | shell = "/bin/sh";
7 | description = "Unprivileged user";
8 | home = "/home/unprivileged";
9 | createHome = true;
10 | isNormalUser = true;
11 | };
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/network-physical.nix:
--------------------------------------------------------------------------------
1 | {
2 | test1 = {pkgs, ...}:
3 | {
4 | deployment.targetEnv = "virtualbox";
5 | deployment.virtualbox.memorySize = 4096; # megabytes
6 | };
7 |
8 | test2 = {pkgs, ...}:
9 | {
10 | deployment.targetEnv = "virtualbox";
11 | deployment.virtualbox.memorySize = 4096; # megabytes
12 | };
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/network-physical.nix:
--------------------------------------------------------------------------------
1 | {
2 | test1 = {pkgs, ...}:
3 | {
4 | deployment.targetEnv = "virtualbox";
5 | deployment.virtualbox.memorySize = 4096; # megabytes
6 | };
7 |
8 | test2 = {pkgs, ...}:
9 | {
10 | deployment.targetEnv = "virtualbox";
11 | deployment.virtualbox.memorySize = 4096; # megabytes
12 | };
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/create-nix-image.nix:
--------------------------------------------------------------------------------
1 | {pkgs}:
2 | input:
3 |
4 | import ./create-image-from-steps.nix {
5 | inherit pkgs input;
6 |
7 | common = {
8 | system = builtins.currentSystem;
9 | };
10 |
11 | steps = [
12 | ./steps/init.nix
13 | ./steps/basic.nix
14 | ./steps/interactive.nix
15 | ./steps/man.nix
16 | ./steps/nix-support.nix
17 | ];
18 | }
19 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/man.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // pkgs.lib.optionalAttrs (input ? manpages && input.manpages) {
4 | contents = result.contents ++ (with pkgs; [
5 | man groff gzip
6 | ]);
7 |
8 | config = result.config or {} // {
9 | Env = result.config.Env or [] ++ [ "MANPATH=/share/man:/nix/var/nix/profiles/default/share/man" ];
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/network-logical.nix:
--------------------------------------------------------------------------------
1 | {
2 | test1 = {pkgs, ...}:
3 |
4 | {
5 | services.disnix.enable = true;
6 | services.openssh.enable = true;
7 | networking.firewall.enable = false;
8 | };
9 |
10 | test2 = {pkgs, ...}:
11 |
12 | {
13 | services.disnix.enable = true;
14 | services.openssh.enable = true;
15 | networking.firewall.enable = false;
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/nixproc/test-driver/profiles/unprivileged.nix:
--------------------------------------------------------------------------------
1 | {
2 | params = rec {
3 | stateDir = "/home/unprivileged/var";
4 | runtimeDir = "${stateDir}/run";
5 | forceDisableUserChange = true;
6 | callingUser = "unprivileged";
7 | callingGroup = "users";
8 | };
9 |
10 | deployArgs = [ "--state-dir" "/home/unprivileged/var" "--force-disable-user-change" ];
11 |
12 | nixosModules = [ ./unprivileged-user-module.nix ];
13 | }
14 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/image-steps/supervisord.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // {
4 | contents = result.contents or [] ++ [ pkgs.python3Packages.supervisor ];
5 | config = result.config or {} // {
6 | Cmd = [ "${pkgs.python3Packages.supervisor}/bin/supervisord" "--nodaemon" "--configuration" "/etc/supervisor/supervisord.conf" "--logfile" "/var/log/supervisord.log" "--pidfile" "/var/run/supervisord.pid" ];
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/nixproc/create-managed-process/agnostic/create-agnostic-config.nix:
--------------------------------------------------------------------------------
1 | {stdenv}:
2 | properties:
3 |
4 | let
5 | configJSON = builtins.toJSON properties;
6 | in
7 | stdenv.mkDerivation rec {
8 | name = if properties ? name then properties.name else properties.instanceName;
9 | inherit configJSON;
10 | passAsFile = [ "configJSON" ];
11 | buildCommand = ''
12 | mkdir -p $out
13 | cp $configJSONPath $out/${name}.json
14 | '';
15 | }
16 |
--------------------------------------------------------------------------------
/tools/generate-config/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-generate-config";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@NIXPROC@|${../../nixproc}|" \
11 | ${./nixproc-generate-config.in} > $out/bin/nixproc-generate-config
12 | chmod +x $out/bin/nixproc-generate-config
13 | '';
14 | }
15 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/nix-processmgmt-static.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | commonTools = (import ../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).common;
8 | in
9 | result // {
10 | runAsRoot = result.runAsRoot or "" + ''
11 | # Initialize common state directories
12 | ${commonTools}/bin/nixproc-init-state --state-dir ${input.stateDir} --runtime-dir ${input.runtimeDir}
13 | '';
14 | }
15 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/create-multi-process-image-universal.nix:
--------------------------------------------------------------------------------
1 | {pkgs}:
2 | input:
3 |
4 | import ./create-multi-process-image.nix {
5 | inherit pkgs;
6 | } (input // {
7 | steps = {
8 | disnix = ../backends/disnix/image-steps/static-steps.nix;
9 | s6-rc = ../backends/s6-rc/image-steps/static-steps.nix;
10 | supervisord = ../backends/supervisord/image-steps/static-steps.nix;
11 | sysvinit = ../backends/sysvinit/image-steps/static-steps.nix;
12 | };
13 | })
14 |
--------------------------------------------------------------------------------
/nixproc/test-driver/util/execute-deploy.nix:
--------------------------------------------------------------------------------
1 | {lib}:
2 | {processManager, profileSettings, envVars ? [], extraDeployArgs ? [], processesEnv}:
3 |
4 | let
5 | executeCommand = import ./execute-command.nix {
6 | inherit lib;
7 | };
8 | in
9 | executeCommand {
10 | inherit (profileSettings.params) forceDisableUserChange;
11 | command = "${toString envVars} nixproc-${processManager}-deploy ${toString profileSettings.deployArgs} ${toString extraDeployArgs} ${processesEnv}";
12 | }
13 |
--------------------------------------------------------------------------------
/nixproc/backends/bsdrc/rcsubr.nix:
--------------------------------------------------------------------------------
1 | {stdenv, forceDisableUserChange}:
2 |
3 | if forceDisableUserChange then
4 | # Disable the limits command when we want to deploy processes as an unprivileged user
5 | stdenv.mkDerivation {
6 | name = "rc.subr";
7 | src = /etc/rc.subr;
8 |
9 | buildCommand = ''
10 | sed -e 's|limits -C $_login_class $_limits||' $src > $out
11 | '';
12 | }
13 | else
14 | # Otherwise, simply return the path to the rc subroutines
15 | "/etc/rc.subr"
16 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/ids.nix:
--------------------------------------------------------------------------------
1 | {
2 | "ids" = {
3 | "gids" = {
4 | "nginx" = 2000;
5 | "webapp" = 2001;
6 | };
7 | "nginxPorts" = {
8 | "nginx" = 8080;
9 | };
10 | "uids" = {
11 | "nginx" = 2000;
12 | "webapp" = 2001;
13 | };
14 | "webappPorts" = {
15 | "webapp" = 5000;
16 | };
17 | };
18 | "lastAssignments" = {
19 | "gids" = 2001;
20 | "nginxPorts" = 8080;
21 | "uids" = 2001;
22 | "webappPorts" = 5000;
23 | };
24 | }
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/ids.nix:
--------------------------------------------------------------------------------
1 | {
2 | "ids" = {
3 | "gids" = {
4 | "nginx" = 2000;
5 | "webapp" = 2001;
6 | };
7 | "nginxPorts" = {
8 | "nginx" = 8080;
9 | };
10 | "uids" = {
11 | "nginx" = 2000;
12 | "webapp" = 2001;
13 | };
14 | "webappPorts" = {
15 | "webapp" = 5000;
16 | };
17 | };
18 | "lastAssignments" = {
19 | "gids" = 2001;
20 | "nginxPorts" = 8080;
21 | "uids" = 2001;
22 | "webappPorts" = 5000;
23 | };
24 | }
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/create-mutable-multi-process-image-universal.nix:
--------------------------------------------------------------------------------
1 | {pkgs}:
2 | input:
3 |
4 | import ./create-mutable-multi-process-image.nix {
5 | inherit pkgs;
6 | } (input // {
7 | steps = {
8 | disnix = ../backends/disnix/image-steps/dynamic-steps.nix;
9 | s6-rc = ../backends/s6-rc/image-steps/dynamic-steps.nix;
10 | supervisord = ../backends/supervisord/image-steps/dynamic-steps.nix;
11 | sysvinit = ../backends/sysvinit/image-steps/dynamic-steps.nix;
12 | };
13 | })
14 |
--------------------------------------------------------------------------------
/tests/builds.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import {}
2 | , nix-processmgmt ? ./..
3 | }:
4 |
5 | let
6 | backends = [ "bsdrc" "cygrunsrv" "disnix" "docker" "launchd" "s6-rc" "supervisord" "systemd" "sysvinit" ];
7 | in
8 | pkgs.lib.genAttrs backends (backend: import "${nix-processmgmt}/nixproc/backends/${backend}/build-${backend}-env.nix" ({
9 | exprFile = ../examples/webapps-agnostic/processes.nix;
10 | } // pkgs.lib.optionalAttrs (backend == "disnix") {
11 | disnixDataDir = "${pkgs.disnix}/share/disnix";
12 | }))
13 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/basic.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // {
4 | runAsRoot = result.runAsRoot or "" + ''
5 | ${pkgs.dockerTools.shadowSetup}
6 |
7 | # Always create these global state directories, because they are needed quite often
8 | mkdir -p /run /tmp
9 | chmod 1777 /tmp
10 |
11 | mkdir -p /var/empty
12 | ln -s ../run /var/run
13 |
14 | # Always create nobody/nogroup
15 | groupadd -g 999 -r nogroup
16 | useradd -u 999 -r nobody -g nogroup -d /dev/null
17 | '';
18 | }
19 |
--------------------------------------------------------------------------------
/examples/multi-process-image/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , processManager ? "supervisord"
4 | , forceDisableUserChange ? false
5 | }:
6 |
7 | let
8 | createMultiProcessImage = import ../../nixproc/create-image-from-steps/create-multi-process-image-universal.nix {
9 | inherit pkgs;
10 | };
11 | in
12 | createMultiProcessImage {
13 | name = "multiprocess";
14 | tag = "test";
15 | exprFile = ../webapps-agnostic/processes.nix;
16 | inherit processManager forceDisableUserChange;
17 | }
18 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/image-steps/s6-rc-dynamic.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | s6-rcTools = (import ../../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).s6-rc;
8 | in
9 | result // {
10 | runAsRoot = result.runAsRoot or "" + ''
11 | # Create empty service directory
12 | mkdir -p /etc/s6/sv
13 |
14 | # Initialize s6-rc with a compiled database
15 | mkdir -p /etc/s6/rc
16 | s6-rc-compile /etc/s6/rc/compiled /etc/s6/sv
17 | '';
18 | contents = result.contents or [] ++ [ s6-rcTools ];
19 | }
20 |
--------------------------------------------------------------------------------
/tools/sysvinit/sysvinitchecks:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | checkRunlevel()
4 | {
5 | if [ "$runlevel" = "" ]
6 | then
7 | if command -v runlevel > /dev/null
8 | then
9 | runlevel=$(runlevel | cut -d ' ' -f2)
10 |
11 | # If the runlevel is unknown, fall back to 3
12 | if [ "$runlevel" = "unknown" ]
13 | then
14 | runlevel=3
15 | fi
16 | else
17 | # If no runlevel command exists, then default to 3
18 | runlevel=3
19 | fi
20 | fi
21 | }
22 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/image-steps/supervisord-dynamic.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | supervisordTools = (import ../../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).supervisord;
8 | in
9 | result // {
10 | contents = result.contents or [] ++ [ supervisordTools ];
11 |
12 | runAsRoot = result.runAsRoot or "" + ''
13 | mkdir -p /etc/supervisor/conf.d
14 | cp ${../supervisord.conf} /etc/supervisor/supervisord.conf
15 | '';
16 |
17 | config = result.config or {} // {
18 | Env = result.config.Env or []
19 | ++ [ "SUPERVISORD_CONF_DIR=/etc/supervisor" ];
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/nixproc/test-driver/universal.nix:
--------------------------------------------------------------------------------
1 | { nixpkgs ?
2 | , system ? builtins.currentSystem
3 | }:
4 |
5 | import ./agnostic.nix {
6 | inherit nixpkgs system;
7 |
8 | processManagerModules = {
9 | disnix = ../backends/disnix/test-module;
10 | docker = ../backends/docker/test-module;
11 | s6-rc = ../backends/s6-rc/test-module;
12 | supervisord = ../backends/supervisord/test-module;
13 | systemd = ../backends/systemd/test-module;
14 | sysvinit = ../backends/sysvinit/test-module;
15 | };
16 |
17 | profileSettingModules = {
18 | privileged = ./profiles/privileged.nix;
19 | unprivileged = ./profiles/unprivileged.nix;
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/tools/s6-rc/s6-rc-checks:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | checkStateDir()
4 | {
5 | if [ "$stateDir" = "" ]
6 | then
7 | if [ "$NIXPROC_STATE_DIR" = "" ]
8 | then
9 | stateDir="/var"
10 | else
11 | stateDir="$NIXPROC_STATE_DIR"
12 | fi
13 | fi
14 | }
15 |
16 | checkRuntimeDir()
17 | {
18 | if [ "$runtimeDir" = "" ]
19 | then
20 | if [ "$NIXPROC_RUNTIME_DIR" = "" ]
21 | then
22 | runtimeDir="$stateDir/run"
23 | else
24 | runtimeDir="$NIXPROC_RUNTIME_DIR"
25 | fi
26 | fi
27 | }
28 |
29 | checkScanDir()
30 | {
31 | scanDir="$runtimeDir/service"
32 | }
33 |
--------------------------------------------------------------------------------
/tools/idassign/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-id-assign";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | if [ "$(type -p greadlink)" = "" ]
9 | then
10 | readlink="$(type -p readlink)"
11 | else
12 | readlink="$(type -p greadlink)"
13 | fi
14 |
15 | sed -e "s|/bin/bash|$SHELL|" \
16 | -e "s|@getopt@|${getopt}/bin/getopt|" \
17 | -e "s|@readlink@|$readlink|" \
18 | -e "s|@NIXPROC@|${../../nixproc}|" \
19 | -e "s|@commonchecks@|${../commonchecks}|" \
20 | ${./nixproc-id-assign.in} > $out/bin/nixproc-id-assign
21 | chmod +x $out/bin/nixproc-id-assign
22 | '';
23 | }
24 |
--------------------------------------------------------------------------------
/tools/disnix/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-disnix-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | ${./nixproc-disnix-deploy.in} > $out/bin/nixproc-disnix-deploy
12 | chmod +x $out/bin/nixproc-disnix-deploy
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@commonchecks@|${../commonchecks}|" \
17 | ${./nixproc-disnix-switch.in} > $out/bin/nixproc-disnix-switch
18 | chmod +x $out/bin/nixproc-disnix-switch
19 | '';
20 | }
21 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/image-steps/supervisord-static.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | profile = import ../build-supervisord-env.nix {
5 | inherit pkgs;
6 | inherit (input) exprFile extraParams stateDir runtimeDir forceDisableUserChange;
7 | inherit (common) system;
8 | };
9 | in
10 | result // {
11 | runAsRoot = result.runAsRoot or "" + ''
12 | ln -s ${profile} /etc/supervisor
13 |
14 | ${pkgs.lib.optionalString (!input.forceDisableUserChange) ''
15 | export PATH=$PATH:${pkgs.findutils}/bin:${pkgs.glibc.bin}/bin
16 | ${pkgs.dysnomia}/bin/dysnomia-addgroups ${profile}
17 | ${pkgs.dysnomia}/bin/dysnomia-addusers ${profile}
18 | ''}
19 | '';
20 | }
21 |
--------------------------------------------------------------------------------
/tools/systemd/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-systemd-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | ${./nixproc-systemd-switch.in} > $out/bin/nixproc-systemd-switch
12 | chmod +x $out/bin/nixproc-systemd-switch
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@commonchecks@|${../commonchecks}|" \
17 | ${./nixproc-systemd-deploy.in} > $out/bin/nixproc-systemd-deploy
18 | chmod +x $out/bin/nixproc-systemd-deploy
19 | '';
20 | }
21 |
--------------------------------------------------------------------------------
/nixproc/derive-dysnomia-process-type.nix:
--------------------------------------------------------------------------------
1 | {processManager}:
2 |
3 | if processManager == null then "managed-process"
4 | else if processManager == "sysvinit" then "sysvinit-script"
5 | else if processManager == "systemd" then "systemd-unit"
6 | else if processManager == "supervisord" then "supervisord-program"
7 | else if processManager == "bsdrc" then "bsdrc-script"
8 | else if processManager == "cygrunsrv" then "cygrunsrv-service"
9 | else if processManager == "launchd" then "launchd-daemon"
10 | else if processManager == "disnix" then "process"
11 | else if processManager == "docker" then "docker-container"
12 | else if processManager == "s6-rc" then "s6-rc-service"
13 | else throw "Unknown process manager: ${processManager}"
14 |
--------------------------------------------------------------------------------
/examples/service-containers-agnostic/constructors.nix:
--------------------------------------------------------------------------------
1 | { pkgs
2 | , stateDir
3 | , logDir
4 | , runtimeDir
5 | , cacheDir
6 | , tmpDir
7 | , forceDisableUserChange
8 | , processManager
9 | , ids ? {}
10 | }:
11 |
12 | let
13 | constructors = import ../services-agnostic/constructors.nix {
14 | inherit pkgs stateDir logDir runtimeDir cacheDir tmpDir forceDisableUserChange processManager ids;
15 | };
16 | in
17 | {
18 | extendableSupervisord = import ./extendable.nix {
19 | inherit stateDir;
20 | inherit (pkgs) stdenv;
21 | supervisordConstructorFun = constructors.extendableSupervisord;
22 | dysnomia = pkgs.dysnomia.override (origArgs: {
23 | enableSupervisordProgram = true;
24 | });
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/tools/cygrunsrv/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-cygrunsrv-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | ${./nixproc-cygrunsrv-switch.in} > $out/bin/nixproc-cygrunsrv-switch
12 | chmod +x $out/bin/nixproc-cygrunsrv-switch
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@commonchecks@|${../commonchecks}|" \
17 | ${./nixproc-cygrunsrv-deploy.in} > $out/bin/nixproc-cygrunsrv-deploy
18 | chmod +x $out/bin/nixproc-cygrunsrv-deploy
19 | '';
20 | }
21 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib, execline, createCredentials, logDir, logDirUser ? "s6-log", logDirGroup ? "s6-log", forceDisableUserChange}:
2 |
3 | rec {
4 | createLogServiceForLongRunService = import ./create-log-service-for-longrun-service.nix {
5 | inherit stdenv lib execline logDir logDirUser logDirGroup forceDisableUserChange;
6 | };
7 | createLongRunService = import ./create-longrun-service.nix {
8 | inherit stdenv lib createCredentials createLogServiceForLongRunService;
9 | };
10 | createOneShotService = import ./create-oneshot-service.nix {
11 | inherit stdenv lib createCredentials;
12 | };
13 | createServiceBundle = import ./create-service-bundle.nix {
14 | inherit stdenv lib;
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/create-process-script.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib, createCredentials, forceDisableUserChange}:
2 |
3 | { name
4 | , process
5 | , pidFile ? null
6 | , dependencies ? []
7 | , postInstall ? ""
8 | , credentials ? {}
9 | }:
10 |
11 | let
12 | credentialsSpec = createCredentials credentials;
13 | in
14 | stdenv.mkDerivation {
15 | inherit name;
16 | buildCommand = ''
17 | mkdir -p $out/etc/dysnomia/process
18 | cat > $out/etc/dysnomia/process/${name} < { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager ? "sysvinit"
11 | }:
12 |
13 | let
14 | constructors = import ../../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
16 | };
17 | in
18 | rec {
19 | docker = {
20 | pkg = constructors.docker {};
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/tools/launchd/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-launchd-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | ${./nixproc-launchd-switch.in} > $out/bin/nixproc-launchd-switch
12 | chmod +x $out/bin/nixproc-launchd-switch
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@commonchecks@|${../commonchecks}|" \
17 | -e "s|@readlink@|$(type -p readlink)|" \
18 | ${./nixproc-launchd-deploy.in} > $out/bin/nixproc-launchd-deploy
19 | chmod +x $out/bin/nixproc-launchd-deploy
20 | '';
21 | }
22 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/constructors/webapp/default.nix:
--------------------------------------------------------------------------------
1 | {createSystemVInitScript, tmpDir}:
2 | {port, instanceSuffix ? "", instanceName ? "webapp${instanceSuffix}"}:
3 |
4 | let
5 | webapp = import ../../../../webapp;
6 | in
7 | createSystemVInitScript {
8 | inherit instanceName;
9 |
10 | process = "${webapp}/bin/webapp";
11 | args = [ "-D" ];
12 | environment = {
13 | PORT = port;
14 | PID_FILE = "${tmpDir}/${instanceName}.pid";
15 | };
16 |
17 | runlevels = [ 3 4 5 ];
18 |
19 | user = instanceName;
20 |
21 | credentials = {
22 | groups = {
23 | "${instanceName}" = {};
24 | };
25 | users = {
26 | "${instanceName}" = {
27 | group = instanceName;
28 | description = "Webapp";
29 | };
30 | };
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/test-module/processes-s6-svscan.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager ? "sysvinit"
11 | }:
12 |
13 | let
14 | constructors = import ../../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
16 | };
17 | in
18 | rec {
19 | s6-svscan = {
20 | pkg = constructors.s6-svscan {};
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/tests/services/nginx-reverse-proxy-hostbased/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, testService, processManagers, profiles }:
2 |
3 | testService {
4 | name = "nginx-reverse-proxy-hostbased";
5 | exprFile = ./processes.nix;
6 |
7 | readiness = {instanceName, instance, ...}:
8 | ''
9 | machine.wait_for_open_port(${toString instance.port})
10 | '';
11 |
12 | tests = {instanceName, instance, ...}:
13 | pkgs.lib.optionalString (instanceName == "nginx" || instanceName == "nginx2")
14 | (pkgs.lib.concatMapStrings (webapp: ''
15 | machine.succeed(
16 | "curl --fail -H 'Host: ${webapp.dnsName}' http://localhost:${toString instance.port} | grep ': ${toString webapp.port}'"
17 | )
18 | '') instance.webapps);
19 |
20 | inherit processManagers profiles;
21 | }
22 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/supervisord/default.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, supervisor, runtimeDir, logDir}:
2 | {instanceSuffix ? "", instanceName ? "supervisord${instanceSuffix}", initialize ? "", configFile, postInstall ? ""}:
3 |
4 | let
5 | pidFile = "${runtimeDir}/${instanceName}.pid";
6 | logFile = "${logDir}/${instanceName}.log";
7 | in
8 | createManagedProcess {
9 | inherit instanceName postInstall;
10 | initialize = ''
11 | mkdir -p ${logDir}
12 | ${initialize}
13 | '';
14 | process = "${supervisor}/bin/supervisord";
15 | args = [ "--configuration" configFile "--logfile" logFile "--pidfile" pidFile ];
16 | foregroundProcessExtraArgs = [ "--nodaemon" ];
17 |
18 | overrides = {
19 | sysvinit = {
20 | runlevels = [ 3 4 5 ];
21 | };
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/image-steps/s6-rc-static.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | profile = import ../build-s6-rc-env.nix {
5 | inherit pkgs;
6 | inherit (common) system;
7 | inherit (input) exprFile extraParams stateDir runtimeDir forceDisableUserChange;
8 | };
9 | in
10 | result // {
11 | runAsRoot = result.runAsRoot or "" + ''
12 | # Initialize s6-rc with a compiled database
13 | mkdir -p /etc/s6/rc
14 | s6-rc-compile /etc/s6/rc/compiled ${profile}/etc/s6/sv
15 |
16 | ${pkgs.lib.optionalString (!input.forceDisableUserChange) ''
17 | export PATH=$PATH:${pkgs.findutils}/bin:${pkgs.glibc.bin}/bin
18 | ${pkgs.dysnomia}/bin/dysnomia-addgroups ${profile}
19 | ${pkgs.dysnomia}/bin/dysnomia-addusers ${profile}
20 | ''}
21 | '';
22 | }
23 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/test-module/processes-supervisord.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager ? "sysvinit"
11 | }:
12 |
13 | let
14 | constructors = import ../../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
16 | };
17 | in
18 | rec {
19 | extendableSupervisord = {
20 | pkg = constructors.extendableSupervisord {};
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/create-multi-process-image.nix:
--------------------------------------------------------------------------------
1 | {pkgs}:
2 | {processManager, steps, ...}@input:
3 |
4 | let
5 | _input = rec {
6 | stateDir = "/var";
7 | runtimeDir = "${stateDir}/run";
8 | forceDisableUserChange = false;
9 | extraParams = {};
10 | } // input;
11 |
12 | processManagerSpecificStepsFile = builtins.getAttr processManager steps;
13 | in
14 | import ./create-image-from-steps.nix {
15 | inherit pkgs;
16 | input = _input;
17 |
18 | common = {
19 | system = builtins.currentSystem;
20 | };
21 |
22 | steps = [
23 | ./steps/init.nix
24 | ./steps/basic.nix
25 | ./steps/interactive.nix
26 | ./steps/man.nix
27 | ./steps/nix-processmgmt-static.nix
28 | ./steps/su-pam.nix
29 | ]
30 | ++ import processManagerSpecificStepsFile;
31 | }
32 |
--------------------------------------------------------------------------------
/tools/docker/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-docker-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | ${./nixproc-docker-switch.in} > $out/bin/nixproc-docker-switch
12 | chmod +x $out/bin/nixproc-docker-switch
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@readlink@|$(type -p readlink)|" \
17 | -e "s|@xargs@|$(type -p xargs)|" \
18 | -e "s|@commonchecks@|${../commonchecks}|" \
19 | ${./nixproc-docker-deploy.in} > $out/bin/nixproc-docker-deploy
20 | chmod +x $out/bin/nixproc-docker-deploy
21 | '';
22 | }
23 |
--------------------------------------------------------------------------------
/nixproc/backends/util/generate-compound-proxy.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib, writeTextFile}:
2 | {startCommand, stopCommand, path ? []}:
3 |
4 | writeTextFile {
5 | name = "compound-proxy-script";
6 | text = ''
7 | #! ${stdenv.shell} -e
8 |
9 | _term()
10 | {
11 | echo "${stopCommand}"
12 | ${stopCommand}
13 | kill "$pid"
14 | exit 0
15 | }
16 |
17 | export PATH=${lib.escapeShellArg (builtins.concatStringsSep ":" (map (pathComponent: "${pathComponent}/bin") path))}:$PATH
18 |
19 | ${startCommand}
20 |
21 | # Keep process running, but allow it to respond to the TERM and INT signals so that all scripts are stopped properly
22 |
23 | trap _term TERM
24 | trap _term INT
25 |
26 | tail -f /dev/null & pid=$!
27 | wait "$pid"
28 | '';
29 | executable = true;
30 | }
31 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/test-module/default.nix:
--------------------------------------------------------------------------------
1 | {profileSettings, exprFile, extraParams, tools, pkgs, system}:
2 |
3 | let
4 | executeDeploy = import ../../../test-driver/util/execute-deploy.nix {
5 | inherit (pkgs) lib;
6 | };
7 |
8 | processesEnvSystem = import ../build-sysvinit-env.nix ({
9 | inherit pkgs system exprFile extraParams;
10 | } // profileSettings.params);
11 | in
12 | {
13 | inherit (profileSettings) params;
14 |
15 | nixosModules = [];
16 |
17 | systemPackages = [
18 | tools.sysvinit
19 | ];
20 |
21 | additionalPaths = [ processesEnvSystem ];
22 |
23 | deployProcessManager = "";
24 |
25 | deploySystem = ''
26 | machine.succeed(
27 | "${executeDeploy { inherit profileSettings; processManager = "sysvinit"; processesEnv = processesEnvSystem; }}"
28 | )
29 | '';
30 | }
31 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/create-mutable-multi-process-image.nix:
--------------------------------------------------------------------------------
1 | {pkgs}:
2 | {processManager, steps, ...}@input:
3 |
4 | let
5 | _input = rec {
6 | stateDir = "/var";
7 | runtimeDir = "${stateDir}/run";
8 | } // input;
9 |
10 | processManagerSpecificStepsFile = builtins.getAttr processManager steps;
11 | in
12 | import ./create-image-from-steps.nix {
13 | inherit pkgs;
14 | common = {
15 | system = builtins.currentSystem;
16 | };
17 | input = _input;
18 |
19 | steps = [
20 | ./steps/init.nix
21 | ./steps/basic.nix
22 | ./steps/interactive.nix
23 | ./steps/man.nix
24 | ./steps/nix-processmgmt-dynamic.nix
25 | ./steps/su-pam.nix
26 | ]
27 | ++ import processManagerSpecificStepsFile
28 | ++ [
29 | ./steps/bootstrap-init.nix
30 | ./steps/nix-support.nix
31 | ];
32 | }
33 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/constructors/constructors.nix:
--------------------------------------------------------------------------------
1 | { pkgs
2 | , stateDir
3 | , logDir
4 | , runtimeDir
5 | , tmpDir
6 | , forceDisableUserChange
7 | , processManager
8 | , webappMode # set to 'foreground' to make them all foreground process, 'daemon' to make them all daemons. null is to pick best option for the selected processManager
9 | , ids ? {}
10 | }:
11 |
12 | let
13 | createManagedProcess = import ../../../nixproc/create-managed-process/universal/create-managed-process-universal.nix {
14 | inherit pkgs runtimeDir stateDir logDir tmpDir forceDisableUserChange processManager ids;
15 | };
16 |
17 | webappExpr = if webappMode == "foreground" then ./webapp/webapp-fg.nix
18 | else if webappMode == "daemon" then ./webapp/webapp-daemon.nix
19 | else ./webapp;
20 | in
21 | {
22 | webapp = import webappExpr {
23 | inherit createManagedProcess tmpDir;
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/constructors/webapp/webapp-fg.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, tmpDir}:
2 | {port, instanceSuffix ? "", instanceName ? "webapp${instanceSuffix}"}:
3 |
4 | let
5 | webapp = import ../../../../webapp;
6 | in
7 | createManagedProcess {
8 | description = "Simple web application";
9 | inherit instanceName;
10 |
11 | # This expression only specifies how to run the webapp in foreground mode
12 | foregroundProcess = "${webapp}/bin/webapp";
13 |
14 | environment = {
15 | PORT = port;
16 | };
17 | user = instanceName;
18 | credentials = {
19 | groups = {
20 | "${instanceName}" = {};
21 | };
22 | users = {
23 | "${instanceName}" = {
24 | group = instanceName;
25 | description = "Webapp";
26 | };
27 | };
28 | };
29 |
30 | overrides = {
31 | sysvinit = {
32 | runlevels = [ 3 4 5 ];
33 | };
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/test-module/default.nix:
--------------------------------------------------------------------------------
1 | {profileSettings, exprFile, extraParams, tools, pkgs, system}:
2 |
3 | let
4 | executeDeploy = import ../../../test-driver/util/execute-deploy.nix {
5 | inherit (pkgs) lib;
6 | };
7 |
8 | processesEnvSystem = import ../build-disnix-env.nix ({
9 | inherit pkgs system exprFile extraParams;
10 | disnixDataDir = "${pkgs.disnix}/share/disnix";
11 | } // profileSettings.params);
12 | in
13 | {
14 | inherit (profileSettings) params;
15 |
16 | nixosModules = [];
17 |
18 | systemPackages = [
19 | tools.disnix
20 | pkgs.disnix
21 | ];
22 |
23 | additionalPaths = [ processesEnvSystem ];
24 |
25 | deployProcessManager = "";
26 |
27 | deploySystem = ''
28 | machine.succeed(
29 | "${executeDeploy { inherit profileSettings; processManager = "disnix"; processesEnv = processesEnvSystem; }}"
30 | )
31 | '';
32 | }
33 |
--------------------------------------------------------------------------------
/tests/services/default.nix:
--------------------------------------------------------------------------------
1 | { nixpkgs ?
2 | , system ? builtins.currentSystem
3 | , processManagers ? [ "supervisord" "sysvinit" "systemd" "disnix" "s6-rc" ]
4 | , profiles ? [ "privileged" "unprivileged" ]
5 | }:
6 |
7 | let
8 | pkgs = import nixpkgs { inherit system; };
9 |
10 | testService = import ../../nixproc/test-driver/universal.nix {
11 | inherit nixpkgs system;
12 | };
13 | in
14 | {
15 | docker = import ./docker {
16 | inherit pkgs processManagers profiles testService;
17 | };
18 |
19 | nginx-reverse-proxy-hostbased = import ./nginx-reverse-proxy-hostbased {
20 | inherit pkgs processManagers profiles testService;
21 | };
22 |
23 | s6-svscan = import ./s6-svscan {
24 | inherit pkgs processManagers profiles testService;
25 | };
26 |
27 | supervisord = import ./supervisord {
28 | inherit pkgs processManagers profiles testService;
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/s6-svscan/default.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, s6, execline, runtimeDir}:
2 |
3 | { instanceSuffix ? ""
4 | , instanceName ? "s6-svscan${instanceSuffix}"
5 | , scanDir ? "${runtimeDir}/service${instanceSuffix}"
6 | , logUser ? "s6-log${instanceSuffix}"
7 | , logGroup ? "s6-log${instanceSuffix}"
8 | }:
9 |
10 | createManagedProcess {
11 | inherit instanceName;
12 |
13 | path = [ s6 execline ];
14 | foregroundProcess = "${s6}/bin/s6-svscan";
15 | args = [ scanDir ];
16 | initialize = ''
17 | mkdir -p ${scanDir}
18 | '';
19 |
20 | credentials = {
21 | groups = {
22 | "${logGroup}" = {};
23 | };
24 | users = {
25 | "${logUser}" = {
26 | group = logGroup;
27 | description = "s6-log user";
28 | };
29 | };
30 | };
31 |
32 | overrides = {
33 | sysvinit = {
34 | runlevels = [ 3 4 5 ];
35 | };
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/tools/common/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-common-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | if [ "$(type -p greadlink)" = "" ]
9 | then
10 | readlink="$(type -p readlink)"
11 | else
12 | readlink="$(type -p greadlink)"
13 | fi
14 |
15 | sed -e "s|/bin/bash|$SHELL|" \
16 | -e "s|@getopt@|${getopt}/bin/getopt|" \
17 | -e "s|@readlink@|$readlink|" \
18 | -e "s|@NIXPROC@|${../../nixproc}|" \
19 | ${./nixproc-build.in} > $out/bin/nixproc-build
20 | chmod +x $out/bin/nixproc-build
21 |
22 | sed -e "s|/bin/bash|$SHELL|" \
23 | -e "s|@getopt@|${getopt}/bin/getopt|" \
24 | -e 's|@DEFAULT_RUNTIME_DIR@|${if stdenv.isLinux || stdenv.isCygwin then "/run" else "/var/run"}|' \
25 | ${./nixproc-init-state.in} > $out/bin/nixproc-init-state
26 | chmod +x $out/bin/nixproc-init-state
27 | '';
28 | }
29 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/init-functions.nix:
--------------------------------------------------------------------------------
1 | {stdenv, fetchurl, basePackages, runtimeDir}:
2 |
3 | let
4 | basePath = builtins.concatStringsSep ":" (map (package: "${package}/bin") basePackages) + ":\\$PATH";
5 |
6 | src = fetchurl {
7 | url = http://www.linuxfromscratch.org/lfs/downloads/9.0/lfs-bootscripts-20190524.tar.xz;
8 | sha256 = "0975wmghhh7j5qify0m170ba2d7vl0km7sw05kclnmwpgivimb38";
9 | };
10 | in
11 | stdenv.mkDerivation {
12 | name = "init-functions";
13 |
14 | buildCommand = ''
15 | tar xfv ${src} lfs-bootscripts-20190524/lfs/lib/services/init-functions
16 |
17 | sed \
18 | -e "s|/bin:/usr/bin:/sbin:/usr/sbin|${basePath}|" \
19 | -e "s|/bin/sh|${stdenv.shell}|" \
20 | -e "s|/bin/echo|echo|" \
21 | -e "s|/bin/head|head|" \
22 | -e "s|/var/run|${runtimeDir}|" \
23 | -e "s|/run/bootlog|${runtimeDir}/bootlog|" \
24 | lfs-bootscripts-20190524/lfs/lib/services/init-functions > $out
25 | '';
26 | }
27 |
--------------------------------------------------------------------------------
/webapp/README.md:
--------------------------------------------------------------------------------
1 | Test web application
2 | ====================
3 | This is a very simple test web application that can run in foreground mode and
4 | daemon mode. Its only purpose is to return a very simple static HTML page.
5 |
6 | The most interesting part of this example is probably the daemonize
7 | infrastructure (`daemonize.h`, `daemonize.c`) -- I have been trying to closely
8 | follow systemd's recommendations for implementing traditional SysV daemons
9 | (more info:`man 7 daemon`) sticking myself to POSIX standards as much as
10 | possible.
11 |
12 | To keep the code as clear as possible, I have encapsulated each recommended
13 | step into a function abstraction, and every failure yields a distinct error
14 | code so that we can easily trace the origins of the error.
15 |
16 | The daemonize infrastructure is very generic -- you only need to provide a
17 | pointer to a function that initializes the daemon's state and a pointer to
18 | a function that runs the main loop.
19 |
--------------------------------------------------------------------------------
/tests/services/docker/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | }:
12 |
13 | let
14 | constructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
16 | };
17 | in
18 | rec {
19 | docker = {
20 | pkg = constructors.docker {};
21 | };
22 |
23 | docker-secondary = rec {
24 | pkg = constructors.docker {
25 | instanceSuffix = "-secondary";
26 | extraArgs = [ "--iptables=false" ]; # Avoids conflicting NAT settings with the primary instances
27 | };
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/image-steps/sysvinit-dynamic.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | sysvinitTools = (import ../../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).sysvinit;
8 |
9 | generateCompoundProxy = import ../../util/generate-compound-proxy.nix {
10 | inherit (pkgs) stdenv lib writeTextFile;
11 | };
12 |
13 | runlevel = "3";
14 |
15 | script = generateCompoundProxy {
16 | startCommand = "${sysvinitTools}/bin/nixproc-sysvinit-runactivity --runlevel ${runlevel} start /";
17 | stopCommand = "${sysvinitTools}/bin/nixproc-sysvinit-runactivity --runlevel ${runlevel} -r stop /";
18 | };
19 | in
20 | result // {
21 | runAsRoot = result.runAsRoot or "" + ''
22 | # Make symlink to processes profile
23 | ln -s /nix/var/nix/profiles/processes/etc/rc.d /etc/rc.d
24 | '';
25 | config = result.config or {} // {
26 | Cmd = [ script ];
27 | };
28 | contents = result.contents or [] ++ [ sysvinitTools ];
29 | }
30 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/supervisord/extendable.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, writeTextFile, supervisor, runtimeDir, logDir, libDir}:
2 |
3 | { instanceSuffix ? ""
4 | , instanceName ? "supervisord${instanceSuffix}"
5 | , inetHTTPServerPort ? 9001
6 | , postInstall ? ""
7 | }:
8 |
9 | let
10 | includeDir = "${libDir}/${instanceName}/conf.d";
11 | in
12 | import ./default.nix {
13 | inherit createManagedProcess supervisor logDir runtimeDir;
14 | } {
15 | inherit instanceName postInstall;
16 |
17 | initialize = ''
18 | mkdir -p ${includeDir}
19 | '';
20 | configFile = writeTextFile {
21 | name = "supervisord.conf";
22 | text = ''
23 | [supervisord]
24 |
25 | [include]
26 | files=${includeDir}/*
27 |
28 | [inet_http_server]
29 | port = 127.0.0.1:${toString inetHTTPServerPort}
30 |
31 | [rpcinterface:supervisor]
32 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
33 | '';
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/nixproc/backends/systemd/test-module/xserver-autologin-module.nix:
--------------------------------------------------------------------------------
1 | {lib, ...}:
2 |
3 | {
4 | # Xserver + PAM only needed for unprivileged systemd deployments
5 | services.xserver = {
6 | enable = true;
7 |
8 | displayManager.autoLogin = {
9 | enable = true;
10 | user = "unprivileged";
11 | };
12 |
13 | # Use IceWM as the window manager.
14 | # Don't use a desktop manager.
15 | displayManager.defaultSession = lib.mkDefault "none+icewm";
16 | windowManager.icewm.enable = true;
17 | };
18 |
19 | # lightdm by default doesn't allow auto login for root, which is
20 | # required by some nixos tests. Override it here.
21 | security.pam.services.lightdm-autologin.text = lib.mkForce ''
22 | auth requisite pam_nologin.so
23 | auth required pam_succeed_if.so quiet
24 | auth required pam_permit.so
25 |
26 | account include lightdm
27 |
28 | password include lightdm
29 |
30 | session include lightdm
31 | '';
32 | }
33 |
--------------------------------------------------------------------------------
/tests/services/s6-svscan/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | }:
12 |
13 | let
14 | constructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
16 | };
17 | in
18 | rec {
19 | s6-svscan-primary = rec {
20 | instanceSuffix = "-primary";
21 | pkg = constructors.s6-svscan {
22 | inherit instanceSuffix;
23 | };
24 | };
25 |
26 | s6-svscan-secondary = rec {
27 | instanceSuffix = "-secondary";
28 | pkg = constructors.s6-svscan {
29 | inherit instanceSuffix;
30 | };
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/constructors/webapp/default.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, tmpDir}:
2 | {port, instanceSuffix ? "", instanceName ? "webapp${instanceSuffix}"}:
3 |
4 | let
5 | webapp = import ../../../../webapp;
6 | in
7 | createManagedProcess {
8 | description = "Simple web application";
9 | inherit instanceName;
10 |
11 | # This expression can both run in foreground or daemon mode.
12 | # The process manager can pick which mode it prefers.
13 | process = "${webapp}/bin/webapp";
14 | daemonArgs = [ "-D" ];
15 |
16 | environment = {
17 | PORT = port;
18 | PID_FILE = "${tmpDir}/${instanceName}.pid";
19 | };
20 | user = instanceName;
21 | credentials = {
22 | groups = {
23 | "${instanceName}" = {};
24 | };
25 | users = {
26 | "${instanceName}" = {
27 | group = instanceName;
28 | description = "Webapp";
29 | };
30 | };
31 | };
32 |
33 | overrides = {
34 | sysvinit = {
35 | runlevels = [ 3 4 5 ];
36 | };
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/su-pam.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // {
4 | runAsRoot = result.runAsRoot or "" + ''
5 | mkdir -p /etc/pam.d
6 | cat > /etc/pam.d/su < /etc/nsswitch.conf < $out/bin/nixproc-bsdrc-switch
12 | chmod +x $out/bin/nixproc-bsdrc-switch
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@sed@|$(type -p sed)|" \
17 | -e "s|@commonchecks@|${../commonchecks}|" \
18 | ${./nixproc-bsdrc-deploy.in} > $out/bin/nixproc-bsdrc-deploy
19 | chmod +x $out/bin/nixproc-bsdrc-deploy
20 |
21 | sed -e "s|/bin/bash|$SHELL|" \
22 | -e "s|@getopt@|${getopt}/bin/getopt|" \
23 | -e "s|@commonchecks@|${../commonchecks}|" \
24 | ${./nixproc-bsdrc-runactivity.in} > $out/bin/nixproc-bsdrc-runactivity
25 | chmod +x $out/bin/nixproc-bsdrc-runactivity
26 | '';
27 | }
28 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/create-service-bundle.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib}:
2 |
3 | { name
4 | # When a service is flagged as essential it will not stop with the command: s6-rc -d change foo, but only: s6-rc -D change foo
5 | , flagEssential ? false
6 | # List of s6-rc services that are in the bundle
7 | , contents ? []
8 | # Arbitrary commands executed after generating the configuration files
9 | , postInstall ? ""
10 | }:
11 |
12 | let
13 | util = import ./util.nix {
14 | inherit lib;
15 | };
16 | in
17 | stdenv.mkDerivation {
18 | inherit name;
19 | buildCommand = ''
20 | mkdir -p $out/etc/s6/sv/${name}
21 | cd $out/etc/s6/sv/${name}
22 | ''
23 | + util.generateStringProperty { value = "bundle"; filename = "type"; }
24 | + util.generateBooleanProperty { value = flagEssential; filename = "flag-essential"; }
25 | + (if contents == [] then util.generateBooleanProperty { value = true; filename = "contents"; }
26 | else util.generateServiceNameList { services = contents; filename = "contents"; }
27 | )
28 | + postInstall;
29 | }
30 |
--------------------------------------------------------------------------------
/examples/services-agnostic/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | }:
12 |
13 | let
14 | ids = if builtins.pathExists ./ids.nix then (import ./ids.nix).ids else {};
15 |
16 | constructors = import ./constructors/constructors.nix {
17 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager ids;
18 | };
19 | in
20 | rec {
21 | supervisord = rec {
22 | inetHTTPServerPort = ids.inetHTTPPorts.supervisord or 0;
23 |
24 | pkg = constructors.extendableSupervisord {
25 | inherit inetHTTPServerPort;
26 | };
27 |
28 | requiresUniqueIdsFor = [ "inetHTTPPorts" ];
29 | };
30 |
31 | docker = {
32 | pkg = constructors.docker {};
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/image-steps/disnix-static.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | generateCompoundProxy = import ../../util/generate-compound-proxy.nix {
5 | inherit (pkgs) stdenv lib writeTextFile;
6 | };
7 |
8 | disnixDataDir = "${pkgs.disnix}/share/disnix";
9 |
10 | profile = import ../build-disnix-env.nix {
11 | inherit pkgs disnixDataDir;
12 | inherit (common) system;
13 | inherit (input) exprFile stateDir runtimeDir forceDisableUserChange extraParams;
14 | };
15 |
16 | emptyProfile = import ../build-disnix-env.nix {
17 | inherit pkgs disnixDataDir;
18 | inherit (common) system;
19 | inherit (input) stateDir runtimeDir forceDisableUserChange extraParams;
20 | exprFile = null;
21 | };
22 |
23 | script = generateCompoundProxy {
24 | path = [ pkgs.dysnomia pkgs.disnix ];
25 | startCommand = "disnix-activate ${profile}";
26 | stopCommand = "disnix-activate -o ${profile} ${emptyProfile}";
27 | };
28 | in
29 | result // {
30 | config = result.config or {} // {
31 | Cmd = [ script ];
32 | };
33 | }
34 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/constructors/nginx/default.nix:
--------------------------------------------------------------------------------
1 | {createSystemVInitScript, lib, nginx, stateDir, runtimeDir, cacheDir, forceDisableUserChange}:
2 | {configFile, dependencies ? [], instanceSuffix ? "", instanceName ? "nginx${instanceSuffix}"}:
3 |
4 | let
5 | user = instanceName;
6 | group = instanceName;
7 | nginxLogDir = "${stateDir}/logs";
8 | nginxCacheDir = "${cacheDir}/${instanceName}";
9 | in
10 | createSystemVInitScript {
11 | description = "Nginx";
12 |
13 | initialize = ''
14 | mkdir -p ${nginxLogDir}
15 | mkdir -p ${nginxCacheDir}
16 |
17 | ${lib.optionalString (!forceDisableUserChange) ''
18 | chown ${user}:${group} ${nginxLogDir}
19 | ''}
20 | '';
21 | process = "${nginx}/bin/nginx";
22 | args = [ "-c" configFile "-p" stateDir ];
23 | runlevels = [ 3 4 5 ];
24 |
25 | inherit dependencies instanceName;
26 |
27 | credentials = {
28 | groups = {
29 | "${group}" = {};
30 | };
31 | users = {
32 | "${user}" = {
33 | inherit group;
34 | description = "Nginx user";
35 | };
36 | };
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/tools/s6-rc/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-s6-rc-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | ${./nixproc-s6-rc-switch.in} > $out/bin/nixproc-s6-rc-switch
12 | chmod +x $out/bin/nixproc-s6-rc-switch
13 |
14 | sed -e "s|/bin/bash|$SHELL|" \
15 | -e "s|@getopt@|${getopt}/bin/getopt|" \
16 | -e "s|@readlink@|$(type -p readlink)|g" \
17 | -e "s|@commonchecks@|${../commonchecks}|" \
18 | -e "s|@s6rcchecks@|${./s6-rc-checks}|" \
19 | ${./nixproc-s6-rc-deploy.in} > $out/bin/nixproc-s6-rc-deploy
20 | chmod +x $out/bin/nixproc-s6-rc-deploy
21 |
22 | sed -e "s|/bin/bash|$SHELL|" \
23 | -e "s|@getopt@|${getopt}/bin/getopt|" \
24 | -e "s|@commonchecks@|${../commonchecks}|" \
25 | -e "s|@s6rcchecks@|${./s6-rc-checks}|" \
26 | ${./nixproc-s6-svscan.in} > $out/bin/nixproc-s6-svscan
27 | chmod +x $out/bin/nixproc-s6-svscan
28 | '';
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020-2021 Sander van der Burg
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/bootstrap-init.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | cmd = pkgs.lib.escapeShellArgs result.config.Cmd;
5 |
6 | channelURL = input.channelURL or "https://nixos.org/channels/nixpkgs-unstable";
7 | in
8 | result // pkgs.lib.optionalAttrs (!(input ? bootstrap) || input.bootstrap) {
9 | runAsRoot = result.runAsRoot or "" + ''
10 | cat > /bin/bootstrap < /bin/bootstrap < ${filename}
12 | '';
13 |
14 | generateIntProperty = {value, filename}:
15 | lib.optionalString (value != null) ''
16 | echo "${toString value}" > ${filename}
17 | '';
18 |
19 | copyFile = {path, filename}:
20 | lib.optionalString (path != null) ''
21 | cp ${path} ${filename}
22 | '';
23 |
24 | copyDir = {path, filename}:
25 | lib.optionalString (path != null) ''
26 | cp -rLv ${path} ${filename}
27 | '';
28 |
29 | generateServiceName = {service, filename}:
30 | lib.optionalString (service != null) ''
31 | echo "${service.name}" > ${filename}
32 | '';
33 |
34 | generateServiceNameList = {services, filename}:
35 | lib.optionalString (services != [])
36 | (lib.concatMapStrings (service: ''
37 | echo "${service.name}" >> ${filename}
38 | '') services);
39 | }
40 |
--------------------------------------------------------------------------------
/nixproc/backends/bsdrc/build-bsdrc-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${cacheDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , exprFile ? null
15 | , extraParams ? {}
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "bsdrc";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "rc.d";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | }
38 |
--------------------------------------------------------------------------------
/nixproc/backends/docker/build-docker-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "docker";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "docker";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | }
38 |
--------------------------------------------------------------------------------
/examples/service-containers-agnostic/extendable.nix:
--------------------------------------------------------------------------------
1 | {supervisordConstructorFun, stdenv, dysnomia, libDir}:
2 |
3 | { instanceSuffix ? "", instanceName ? "supervisord${instanceSuffix}"
4 | , containerName ? "supervisord-program${instanceSuffix}"
5 | , inetHTTPServerPort ? 9001
6 | , postInstall ? ""
7 | , type
8 | , properties ? {}
9 | }:
10 |
11 | let
12 | supervisordTargetDir = "${libDir}/${instanceName}/conf.d";
13 |
14 | pkg = supervisordConstructorFun {
15 | inherit instanceName inetHTTPServerPort;
16 | postInstall = ''
17 | # Add Dysnomia container configuration file for Supervisord
18 | mkdir -p $out/etc/dysnomia/containers
19 | cat > $out/etc/dysnomia/containers/${containerName} < { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${cacheDir}/cache"
7 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
8 | , spoolDir ? "${stateDir}/spool"
9 | , lockDir ? "${stateDir}/lock"
10 | , libDir ? "${stateDir}/lib"
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "launchd";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "launchd";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | }
38 |
--------------------------------------------------------------------------------
/nixproc/backends/systemd/build-systemd-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "systemd";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "systemd";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | }
38 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/build-sysvinit-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "sysvinit";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "rc.d";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | }
38 |
--------------------------------------------------------------------------------
/nixproc/backends/cygrunsrv/build-cygrunsrv-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${cacheDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "cygrunsrv";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "cygrunsrv-env";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | }
38 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
8 | , forceDisableUserChange ? false
9 | }:
10 |
11 | let
12 | ids = if builtins.pathExists ./ids.nix then (import ./ids.nix).ids else {};
13 |
14 | constructors = import ./constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir cacheDir tmpDir forceDisableUserChange ids;
16 | };
17 | in
18 | rec {
19 | webapp = rec {
20 | port = ids.webappPorts.webapp or 0;
21 | dnsName = "webapp.local";
22 |
23 | pkg = constructors.webapp {
24 | inherit port;
25 | };
26 |
27 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
28 | };
29 |
30 | nginx = rec {
31 | port = ids.nginxPorts.nginx or 0;
32 |
33 | pkg = constructors.nginxReverseProxy {
34 | webapps = [ webapp ];
35 | inherit port;
36 | } {};
37 |
38 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/tools/sysvinit/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-sysvinit-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@commonchecks@|${../commonchecks}|" \
11 | -e "s|@sysvinitchecks@|${./sysvinitchecks}|" \
12 | ${./nixproc-sysvinit-deploy.in} > $out/bin/nixproc-sysvinit-deploy
13 | chmod +x $out/bin/nixproc-sysvinit-deploy
14 |
15 | sed -e "s|/bin/bash|$SHELL|" \
16 | -e "s|@getopt@|${getopt}/bin/getopt|" \
17 | -e "s|@commonchecks@|${../commonchecks}|" \
18 | -e "s|@sysvinitchecks@|${./sysvinitchecks}|" \
19 | ${./nixproc-sysvinit-switch.in} > $out/bin/nixproc-sysvinit-switch
20 | chmod +x $out/bin/nixproc-sysvinit-switch
21 |
22 | sed -e "s|/bin/bash|$SHELL|" \
23 | -e "s|@getopt@|${getopt}/bin/getopt|" \
24 | -e "s|@commonchecks@|${../commonchecks}|" \
25 | -e "s|@sysvinitchecks@|${./sysvinitchecks}|" \
26 | ${./nixproc-sysvinit-runactivity.in} > $out/bin/nixproc-sysvinit-runactivity
27 | chmod +x $out/bin/nixproc-sysvinit-runactivity
28 | '';
29 | }
30 |
--------------------------------------------------------------------------------
/nixproc/backends/bsdrc/generate-bsdrc-script.nix:
--------------------------------------------------------------------------------
1 | { createBSDRCScript, lib }:
2 |
3 | { name
4 | , description
5 | , initialize
6 | , daemon
7 | , daemonArgs
8 | , instanceName
9 | , pidFile
10 | , foregroundProcess
11 | , foregroundProcessArgs
12 | , path
13 | , environment
14 | , directory
15 | , umask
16 | , nice
17 | , user
18 | , dependencies
19 | , credentials
20 | , overrides
21 | , postInstall
22 | }:
23 |
24 | let
25 | generatedTargetSpecificArgs = {
26 | inherit name environment path directory nice umask dependencies;
27 | inherit user instanceName credentials postInstall;
28 |
29 | command = if daemon != null then daemon else foregroundProcess;
30 | commandIsDaemon = daemon != null;
31 | commandArgs = if daemon != null then daemonArgs else foregroundProcessArgs;
32 | } // lib.optionalAttrs (pidFile != null) {
33 | inherit pidFile;
34 | } // lib.optionalAttrs (initialize != "") {
35 | commands.start.pre = initialize;
36 | };
37 |
38 | targetSpecificArgs =
39 | if builtins.isFunction overrides then overrides generatedTargetSpecificArgs
40 | else lib.recursiveUpdate generatedTargetSpecificArgs overrides;
41 | in
42 | createBSDRCScript targetSpecificArgs
43 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/constructors/constructors.nix:
--------------------------------------------------------------------------------
1 | { pkgs
2 | , stateDir
3 | , cacheDir
4 | , logDir
5 | , runtimeDir
6 | , tmpDir
7 | , forceDisableUserChange
8 | , ids ? {}
9 | }:
10 |
11 | let
12 | createSystemVInitScript = import ../../../nixproc/backends/sysvinit/create-sysvinit-script.nix {
13 | inherit (pkgs) stdenv writeTextFile lib daemon;
14 | inherit runtimeDir logDir tmpDir forceDisableUserChange;
15 |
16 | createCredentials = import ../../../nixproc/create-credentials {
17 | inherit (pkgs) stdenv lib;
18 | inherit ids forceDisableUserChange;
19 | };
20 |
21 | initFunctions = import ../../../nixproc/backends/sysvinit/init-functions.nix {
22 | basePackages = [ pkgs.coreutils pkgs.gnused pkgs.inetutils pkgs.gnugrep pkgs.sysvinit ];
23 | inherit (pkgs) stdenv fetchurl;
24 | inherit runtimeDir;
25 | };
26 | };
27 | in
28 | {
29 | webapp = import ./webapp {
30 | inherit createSystemVInitScript tmpDir;
31 | };
32 |
33 | nginxReverseProxy = import ./nginx/nginx-reverse-proxy.nix {
34 | inherit createSystemVInitScript stateDir logDir cacheDir runtimeDir forceDisableUserChange;
35 | inherit (pkgs) stdenv lib writeTextFile nginx;
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/services.nix:
--------------------------------------------------------------------------------
1 | { pkgs, distribution, invDistribution, system
2 | , stateDir ? "/var"
3 | , runtimeDir ? "${stateDir}/run"
4 | , logDir ? "${stateDir}/log"
5 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
6 | , forceDisableUserChange ? true
7 | }:
8 |
9 | let
10 | ids = if builtins.pathExists ./ids.nix then (import ./ids.nix).ids else {};
11 |
12 | constructors = import ./constructors.nix {
13 | inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange;
14 | };
15 | in
16 | rec {
17 | webapp = rec {
18 | name = "webapp";
19 | port = ids.webappPorts.webapp or 0;
20 | dnsName = "webapp.local";
21 | pkg = constructors.webapp {
22 | inherit port;
23 | };
24 | type = "sysvinit-script";
25 |
26 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
27 | };
28 |
29 | nginxReverseProxy = rec {
30 | name = "nginxReverseProxy";
31 | port = ids.nginxPorts.nginx or 0;
32 | pkg = constructors.nginxReverseProxy {
33 | inherit port;
34 | };
35 | dependsOn = {
36 | inherit webapp;
37 | };
38 | type = "sysvinit-script";
39 |
40 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/build-supervisord-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | }@args:
17 |
18 | let
19 | processesFun = import exprFile;
20 |
21 | processesFormalArgs = builtins.functionArgs processesFun;
22 |
23 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
24 | processManager = "supervisord";
25 | } // extraParams);
26 |
27 | processes = if exprFile == null then {} else processesFun processesArgs;
28 | in
29 | pkgs.buildEnv {
30 | name = "supervisord.d";
31 | paths = map (processName:
32 | let
33 | process = builtins.getAttr processName processes;
34 | in
35 | process.pkg
36 | ) (builtins.attrNames processes);
37 | postBuild = ''
38 | cp ${./supervisord.conf} $out/supervisord.conf
39 | '';
40 | }
41 |
--------------------------------------------------------------------------------
/nixproc/backends/sysvinit/image-steps/sysvinit-static.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | sysvinitTools = (import ../../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).sysvinit;
8 |
9 | generateCompoundProxy = import ../../util/generate-compound-proxy.nix {
10 | inherit (pkgs) stdenv lib writeTextFile;
11 | };
12 |
13 | runlevel = "3";
14 |
15 | script = generateCompoundProxy {
16 | startCommand = "${sysvinitTools}/bin/nixproc-sysvinit-runactivity start ${profile}";
17 | stopCommand = "${sysvinitTools}/bin/nixproc-sysvinit-runactivity -r stop ${profile}";
18 | };
19 |
20 | profile = import ../build-sysvinit-env.nix {
21 | inherit (input) exprFile stateDir runtimeDir forceDisableUserChange extraParams;
22 | };
23 | in
24 | result // {
25 | runAsRoot = result.runAsRoot or "" + ''
26 | ln -s ${profile}/etc/rc.d /etc/rc.d
27 |
28 | ${pkgs.lib.optionalString (!input.forceDisableUserChange) ''
29 | export PATH=$PATH:${pkgs.findutils}/bin:${pkgs.glibc.bin}/bin
30 | ${pkgs.dysnomia}/bin/dysnomia-addgroups ${profile}
31 | ${pkgs.dysnomia}/bin/dysnomia-addusers ${profile}
32 | ''}
33 | '';
34 | config = result.config or {} // {
35 | Cmd = [ script ];
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/tests/services/docker/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, testService, processManagers, profiles }:
2 |
3 | testService {
4 | name = "docker";
5 | exprFile = ./processes.nix;
6 | systemPackages = [ pkgs.docker ];
7 |
8 | readiness = {instanceName, instance, runtimeDir, ...}:
9 | ''
10 | machine.wait_for_file("${runtimeDir}/${instanceName}.sock")
11 | '';
12 |
13 | tests = {instanceName, instance, stateDir, runtimeDir, forceDisableUserChange, ...}:
14 | # The primary instance should be connectible with the default parameters
15 | if instanceName == "docker" && !forceDisableUserChange then ''
16 | machine.succeed("docker info | grep 'Docker Root Dir: ${stateDir}/lib/${instanceName}'")
17 | '' else ''
18 | machine.succeed(
19 | "docker --host=unix://${runtimeDir}/${instanceName}.sock info | grep 'Docker Root Dir: ${stateDir}/lib/${instanceName}'"
20 | )
21 | '';
22 |
23 | # It is useless to run Docker in Docker
24 | processManagers = builtins.filter (processManager: processManager != "docker") processManagers;
25 |
26 | # There's an experimental rootless feature for Docker, but a hassle to setup. As a result, we disable unprivileged mode
27 | profiles = builtins.filter (profile: profile == "privileged") profiles;
28 | }
29 |
--------------------------------------------------------------------------------
/tests/services/supervisord/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | }:
12 |
13 | let
14 | constructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir tmpDir cacheDir libDir forceDisableUserChange processManager;
16 | };
17 | in
18 | rec {
19 | supervisord-primary = rec {
20 | # Special situation: we can only bootstrap supervisord with supervisord if we don't conflict with the managing supervisord's port
21 | port = if processManager == "supervisord" then 9003 else 9001;
22 |
23 | pkg = constructors.extendableSupervisord {
24 | inetHTTPServerPort = port;
25 | instanceSuffix = "-primary";
26 | };
27 | };
28 |
29 | supervisord-secondary = rec {
30 | port = 9002;
31 |
32 | pkg = constructors.extendableSupervisord {
33 | inetHTTPServerPort = port;
34 | instanceSuffix = "-secondary";
35 | };
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/create-log-service-for-longrun-service.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib, execline, logDir, logDirUser, logDirGroup, forceDisableUserChange}:
2 | {name}:
3 |
4 | let
5 | serviceName = "${name}-log";
6 |
7 | util = import ./util.nix {
8 | inherit lib;
9 | };
10 |
11 | serviceLogDir = "${logDir}/s6-log/${name}";
12 |
13 | notificationFd = 3;
14 | in
15 | stdenv.mkDerivation {
16 | name = serviceName;
17 | buildCommand = ''
18 | mkdir -p $out/etc/s6/sv/${serviceName}
19 | cd $out/etc/s6/sv/${serviceName}
20 | ''
21 | + util.generateStringProperty { value = "longrun"; filename = "type"; }
22 | + ''
23 | cat > run <
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | if(argc < 3)
10 | {
11 | printf("Usage: %s username command [args]\n", argv[0]);
12 | return 1;
13 | }
14 | else
15 | {
16 | char *username = argv[1];
17 |
18 | /* Query password entry for the user */
19 | struct passwd *pwentry = getpwnam(username);
20 |
21 | if(pwentry == NULL)
22 | {
23 | fprintf(stderr, "Cannot find password entry for user: %s\n", username);
24 | return 1;
25 | }
26 |
27 | /* Change user permissions to the requested user */
28 | if(setgid(pwentry->pw_gid) == 0 && setuid(pwentry->pw_uid) == 0)
29 | {
30 | /* Exec into the requested process */
31 | char **cmd_argv = argv + 2;
32 | execvp(cmd_argv[0], cmd_argv);
33 | fprintf(stderr, "Cannot execute command: %s\n", cmd_argv[0]);
34 | return 1;
35 | }
36 | else
37 | {
38 | fprintf(stderr, "Cannot change into user: %s with corresponding group!\n", username);
39 | return 1;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tools/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | }:
4 |
5 | rec {
6 | chainload-user = import ./chainload-user {
7 | inherit (pkgs) stdenv;
8 | };
9 |
10 | common = import ./common {
11 | inherit (pkgs) stdenv getopt;
12 | };
13 |
14 | generate-config = import ./generate-config {
15 | inherit (pkgs) stdenv getopt;
16 | };
17 |
18 | bsdrc = import ./bsdrc {
19 | inherit (pkgs) stdenv getopt;
20 | };
21 |
22 | cygrunsrv = import ./cygrunsrv {
23 | inherit (pkgs) stdenv getopt;
24 | };
25 |
26 | disnix = import ./disnix {
27 | inherit (pkgs) stdenv getopt;
28 | };
29 |
30 | docker = import ./docker {
31 | inherit (pkgs) stdenv getopt;
32 | };
33 |
34 | idassign = import ./idassign {
35 | inherit (pkgs) stdenv getopt;
36 | };
37 |
38 | launchd = import ./launchd {
39 | inherit (pkgs) stdenv getopt;
40 | };
41 |
42 | s6-rc = import ./s6-rc {
43 | inherit (pkgs) stdenv getopt;
44 | };
45 |
46 | supervisord = import ./supervisord {
47 | inherit (pkgs) stdenv getopt;
48 | };
49 |
50 | systemd = import ./systemd {
51 | inherit (pkgs) stdenv getopt;
52 | };
53 |
54 | sysvinit = import ./sysvinit {
55 | inherit (pkgs) stdenv getopt;
56 | };
57 | }
58 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/image-steps/disnix-dynamic.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | disnixTools = (import ../../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).disnix;
8 |
9 | generateCompoundProxy = import ../../util/generate-compound-proxy.nix {
10 | inherit (pkgs) stdenv lib writeTextFile;
11 | };
12 |
13 | disnixDataDir = "${pkgs.disnix}/share/disnix";
14 |
15 | emptyProfile = import ../build-disnix-env.nix {
16 | inherit pkgs disnixDataDir;
17 | inherit (common) system;
18 | inherit (input) stateDir runtimeDir forceDisableUserChange extraParams;
19 | exprFile = null;
20 | };
21 |
22 | profilePath = "/nix/var/nix/profiles/per-user/root/disnix-coordinator/default";
23 |
24 | script = generateCompoundProxy {
25 | path = [ pkgs.dysnomia pkgs.disnix ];
26 | startCommand = "disnix-activate -o ${emptyProfile} ${profilePath}";
27 | stopCommand = "disnix-activate -o ${profilePath} ${emptyProfile}";
28 | };
29 | in
30 | result // {
31 | runAsRoot = result.runAsRoot or "" + ''
32 | mkdir -p "$(dirname ${profilePath})"
33 | ln -s ${emptyProfile} ${profilePath}
34 | '';
35 |
36 | contents = result.contents or [] ++ [ disnixTools ];
37 | config = result.config or {} // {
38 | Cmd = [ script ];
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/docker/default.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, docker, kmod, runtimeDir, libDir}:
2 | {instanceSuffix ? "", instanceName ? "docker${instanceSuffix}", extraArgs ? []}:
3 |
4 | let
5 | user = instanceName;
6 | group = instanceName;
7 | in
8 | createManagedProcess {
9 | inherit instanceName;
10 | foregroundProcess = "${docker}/bin/dockerd";
11 | args = [
12 | "--group=${group}"
13 | "--host=unix://${runtimeDir}/${instanceName}.sock"
14 | # Add -alt suffix. We only need PID files for the backends that requires processes to daemonize on their own.
15 | # The `daemon` command will create PID files for them. Without the -alt suffix they will conflict causing the Docker daemon to refuse to start.
16 | "--pidfile=${runtimeDir}/${instanceName}-alt.pid"
17 | "--data-root=${libDir}/${instanceName}"
18 | "--exec-root=${runtimeDir}/${instanceName}"
19 | "--log-driver=json-file"
20 | ] ++ extraArgs;
21 | path = [ kmod ];
22 |
23 | credentials = {
24 | groups = {
25 | "${group}" = {};
26 | };
27 | users = {
28 | "${user}" = {
29 | inherit group;
30 | description = "Docker user";
31 | };
32 | };
33 | };
34 |
35 | overrides = {
36 | sysvinit = {
37 | runlevels = [ 3 4 5 ];
38 | };
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/nginx/default.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, lib, nginx, stateDir, runtimeDir, cacheDir, forceDisableUserChange}:
2 | {configFile, dependencies ? [], instanceSuffix ? "", instanceName ? "nginx${instanceSuffix}"}:
3 |
4 | let
5 | user = instanceName;
6 | group = instanceName;
7 |
8 | nginxStateDir = "${stateDir}/${instanceName}";
9 | nginxLogDir = "${nginxStateDir}/logs";
10 | nginxCacheDir = "${cacheDir}/${instanceName}";
11 | in
12 | createManagedProcess {
13 | description = "Nginx";
14 | initialize = ''
15 | mkdir -p ${nginxLogDir}
16 | mkdir -p ${nginxCacheDir}
17 | ${lib.optionalString (!forceDisableUserChange) ''
18 | chown ${user}:${group} ${nginxLogDir}
19 | chown ${user}:${group} ${nginxCacheDir}
20 | ''}
21 | '';
22 | process = "${nginx}/bin/nginx";
23 | args = [ "-p" "${nginxStateDir}" "-c" configFile ];
24 | foregroundProcessExtraArgs = [ "-g" "daemon off;" ];
25 |
26 | inherit dependencies instanceName;
27 |
28 | credentials = {
29 | groups = {
30 | "${group}" = {};
31 | };
32 | users = {
33 | "${user}" = {
34 | inherit group;
35 | description = "Nginx user";
36 | };
37 | };
38 | };
39 |
40 | overrides = {
41 | sysvinit = {
42 | runlevels = [ 3 4 5 ];
43 | };
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/test-module/default.nix:
--------------------------------------------------------------------------------
1 | {profileSettings, exprFile, extraParams, tools, pkgs, system}:
2 |
3 | let
4 | executeDeploy = import ../../../test-driver/util/execute-deploy.nix {
5 | inherit (pkgs) lib;
6 | };
7 |
8 | processesEnvProcessManager = import ../../sysvinit/build-sysvinit-env.nix ({
9 | inherit pkgs system;
10 | exprFile = ./processes-s6-svscan.nix;
11 | } // profileSettings.params);
12 |
13 | processesEnvSystem = import ../build-s6-rc-env.nix ({
14 | inherit pkgs system exprFile extraParams;
15 | } // profileSettings.params);
16 | in
17 | {
18 | inherit (profileSettings) params;
19 |
20 | nixosModules = [];
21 |
22 | systemPackages = [
23 | tools.sysvinit
24 | tools.s6-rc
25 | pkgs.s6-rc
26 | ];
27 |
28 | additionalPaths = [ processesEnvProcessManager processesEnvSystem ];
29 |
30 | deployProcessManager = ''
31 | machine.succeed(
32 | "${executeDeploy { inherit profileSettings; processManager = "sysvinit"; processesEnv = processesEnvProcessManager; }}"
33 | )
34 | machine.wait_for_file("${profileSettings.params.runtimeDir}/service/.s6-svscan")
35 | '';
36 |
37 | deploySystem = ''
38 | machine.succeed(
39 | "${executeDeploy { inherit profileSettings; processManager = "s6-rc"; processesEnv = processesEnvSystem; }}"
40 | )
41 | '';
42 | }
43 |
--------------------------------------------------------------------------------
/webapp/service.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Sander van der Burg
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to
6 | * deal in the Software without restriction, including without limitation the
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 | * sell copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef __SERVICE_H
24 | #define __SERVICE_H
25 | #include "daemonize.h"
26 |
27 | int run_foreground_process(int port);
28 |
29 | DaemonStatus run_daemon(int port, const char *pid_file);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/tools/supervisord/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, getopt}:
2 |
3 | stdenv.mkDerivation {
4 | name = "nixproc-supervisord-tools";
5 | buildCommand = ''
6 | mkdir -p $out/bin
7 |
8 | sed -e "s|/bin/bash|$SHELL|" \
9 | -e "s|@getopt@|${getopt}/bin/getopt|" \
10 | -e "s|@readlink@|$(type -p readlink)|" \
11 | -e "s|@commonchecks@|${../commonchecks}|" \
12 | -e "s|@supervisordchecks@|${./supervisordchecks}|" \
13 | ${./nixproc-supervisord-switch.in} > $out/bin/nixproc-supervisord-switch
14 | chmod +x $out/bin/nixproc-supervisord-switch
15 |
16 | sed -e "s|/bin/bash|$SHELL|" \
17 | -e "s|@getopt@|${getopt}/bin/getopt|" \
18 | -e "s|@readlink@|$(type -p readlink)|" \
19 | -e "s|@commonchecks@|${../commonchecks}|" \
20 | -e "s|@supervisordchecks@|${./supervisordchecks}|" \
21 | ${./nixproc-supervisord-deploy.in} > $out/bin/nixproc-supervisord-deploy
22 | chmod +x $out/bin/nixproc-supervisord-deploy
23 |
24 | sed -e "s|/bin/bash|$SHELL|" \
25 | -e "s|@getopt@|${getopt}/bin/getopt|" \
26 | -e "s|@readlink@|$(type -p readlink)|" \
27 | -e "s|@commonchecks@|${../commonchecks}|" \
28 | -e "s|@supervisordchecks@|${./supervisordchecks}|" \
29 | ${./nixproc-supervisord-deploy-stateless.in} > $out/bin/nixproc-supervisord-deploy-stateless
30 | chmod +x $out/bin/nixproc-supervisord-deploy-stateless
31 | '';
32 | }
33 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/test-module/default.nix:
--------------------------------------------------------------------------------
1 | {profileSettings, exprFile, extraParams, tools, pkgs, system}:
2 |
3 | let
4 | executeDeploy = import ../../../test-driver/util/execute-deploy.nix {
5 | inherit (pkgs) lib;
6 | };
7 |
8 | processesEnvProcessManager = import ../../sysvinit/build-sysvinit-env.nix ({
9 | inherit pkgs system;
10 | exprFile = ./processes-supervisord.nix;
11 | } // profileSettings.params);
12 |
13 | processesEnvSystem = import ../build-supervisord-env.nix ({
14 | inherit pkgs system exprFile extraParams;
15 | } // profileSettings.params);
16 | in
17 | {
18 | inherit (profileSettings) params;
19 |
20 | nixosModules = [];
21 |
22 | systemPackages = [
23 | tools.sysvinit
24 | tools.supervisord
25 | pkgs.python3Packages.supervisor
26 | ];
27 |
28 | additionalPaths = [ processesEnvProcessManager processesEnvSystem ];
29 |
30 | deployProcessManager = ''
31 | machine.succeed(
32 | "${executeDeploy { inherit profileSettings; processManager = "sysvinit"; processesEnv = processesEnvProcessManager; }}"
33 | )
34 | machine.wait_for_open_port(9001)
35 | '';
36 |
37 | deploySystem = ''
38 | machine.succeed(
39 | "${executeDeploy { inherit profileSettings; processManager = "supervisord"; envVars = [ "SUPERVISORD_CONF_DIR=${profileSettings.params.stateDir}/lib/supervisord" ]; processesEnv = processesEnvSystem; }}"
40 | )
41 | '';
42 | }
43 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/network-logical.nix:
--------------------------------------------------------------------------------
1 | let
2 | nixproc-generate-config = (import ../../tools {}).generate-config;
3 | in
4 | {
5 | test1 = {pkgs, ...}:
6 |
7 | {
8 | dysnomia = {
9 | extraContainerProperties = {
10 | managed-process = {
11 | processManager = "systemd";
12 | NIX_PATH = "/root/.nix-defexpr/channels:nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels";
13 | };
14 | };
15 | };
16 |
17 | services.disnix.enable = true;
18 | services.openssh.enable = true;
19 | networking.firewall.enable = false;
20 | environment.systemPackages = [ pkgs.python3Packages.supervisor nixproc-generate-config ];
21 | };
22 |
23 | test2 = {pkgs, ...}:
24 |
25 | {
26 | dysnomia = {
27 | extraContainerProperties = {
28 | managed-process = {
29 | processManager = "sysvinit";
30 | NIX_PATH = "/root/.nix-defexpr/channels:nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels";
31 | };
32 | };
33 |
34 | };
35 |
36 | services.disnix.enable = true;
37 | services.openssh.enable = true;
38 | networking.firewall.enable = false;
39 | environment.systemPackages = [ pkgs.python3Packages.supervisor nixproc-generate-config ];
40 | };
41 | }
42 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/interactive.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | result // pkgs.lib.optionalAttrs (!(input ? interactive) || input.interactive) {
4 | contents = result.contents or [] ++ (with pkgs; [
5 | # An interactive bash shell
6 | bashInteractive
7 | # Basic shell utilities for file management, text manipulation, user management, process management
8 | coreutils diffutils findutils gnugrep gnused glibc.bin less utillinux procps shadow
9 | ]);
10 |
11 | runAsRoot = result.runAsRoot or "" + ''
12 | mkdir -p /root
13 | cat > /root/.bashrc << "EOF"
14 | alias ls='ls --color=auto'
15 |
16 | if [ -n "$PS1" ]
17 | then
18 | if [ "$TERM" != "dumb" -o -n "$INSIDE_EMACS" ]
19 | then
20 | PROMPT_COLOR="1;31m"
21 | let $UID && PROMPT_COLOR="1;32m"
22 | if [ -n "$INSIDE_EMACS" -o "$TERM" == "eterm" -o "$TERM" == "eterm-color" ]
23 | then
24 | # Emacs term mode doesn't support xterm title escape sequence (\e]0;)
25 | PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
26 | else
27 | PS1="\n\[\033[$PROMPT_COLOR\][\[\e]0;\u@\h: \w\a\]\u@\h:\w]\\$\[\033[0m\] "
28 | fi
29 | if test "$TERM" = "xterm"
30 | then
31 | PS1="\[\033]2;\h:\u:\w\007\]$PS1"
32 | fi
33 | fi
34 | fi
35 | EOF
36 | '';
37 | }
38 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/build-s6-rc-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , extraParams ? {}
15 | , exprFile ? null
16 | , defaultBundleName ? "default"
17 | }@args:
18 |
19 | let
20 | processesFun = import exprFile;
21 |
22 | processesFormalArgs = builtins.functionArgs processesFun;
23 |
24 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
25 | processManager = "s6-rc";
26 | } // extraParams);
27 |
28 | processes = if exprFile == null then {} else processesFun processesArgs;
29 |
30 | createServiceBundle = import ./create-service-bundle.nix {
31 | inherit (pkgs) stdenv lib;
32 | };
33 |
34 | processesList = map (processName:
35 | let
36 | process = builtins.getAttr processName processes;
37 | in
38 | process.pkg
39 | ) (builtins.attrNames processes);
40 |
41 | defaultBundle = createServiceBundle {
42 | name = defaultBundleName;
43 | contents = processesList;
44 | };
45 | in
46 | pkgs.buildEnv {
47 | name = "s6-rc";
48 | paths = [ defaultBundle ] ++ processesList;
49 | }
50 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | , webappMode ? null
12 | }:
13 |
14 | let
15 | ids = if builtins.pathExists ./ids.nix then (import ./ids.nix).ids else {};
16 |
17 | sharedConstructors = import ../services-agnostic/constructors/constructors.nix {
18 | inherit pkgs stateDir runtimeDir logDir cacheDir libDir tmpDir forceDisableUserChange processManager ids;
19 | };
20 |
21 | constructors = import ./constructors/constructors.nix {
22 | inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager webappMode ids;
23 | };
24 | in
25 | rec {
26 | webapp = rec {
27 | port = ids.webappPorts.webapp or 0;
28 | dnsName = "webapp.local";
29 |
30 | pkg = constructors.webapp {
31 | inherit port;
32 | };
33 |
34 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
35 | };
36 |
37 | nginx = rec {
38 | port = ids.nginxPorts.nginx or 0;
39 |
40 | pkg = sharedConstructors.nginxReverseProxyHostBased {
41 | webapps = [ webapp ];
42 | inherit port;
43 | } {};
44 |
45 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/nixproc/backends/s6-rc/image-steps/s6-rc.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | skelDir = pkgs.stdenv.mkDerivation {
5 | name = "s6-skel-dir";
6 | buildCommand = ''
7 | mkdir -p $out
8 | cd $out
9 |
10 | cat > rc.init < rc.shutdown < rc.shutdown.final <&2
13 | sleep 1
14 | done
15 | '';
16 | executable = true;
17 | };
18 |
19 | generateTestConf = instanceName:
20 | pkgs.writeTextFile {
21 | name = "test-${instanceName}.conf";
22 | text = ''
23 | [program:test-${instanceName}]
24 | command=${generateTestExecutable instanceName}
25 | '';
26 | };
27 | in
28 | testService {
29 | name = "supervisord";
30 | exprFile = ./processes.nix;
31 | systemPackages = [ pkgs.python3Packages.supervisor ];
32 |
33 | readiness = {instanceName, instance, ...}:
34 | ''
35 | machine.wait_for_open_port(${toString instance.port})
36 | '';
37 |
38 | tests = {instanceName, instance, stateDir, ...}:
39 | ''
40 | machine.succeed(
41 | "cp ${generateTestConf instanceName} ${stateDir}/lib/${instanceName}/conf.d"
42 | )
43 | machine.succeed("supervisorctl --serverurl http://localhost:${toString instance.port} reread")
44 | machine.succeed("supervisorctl --serverurl http://localhost:${toString instance.port} update")
45 | machine.succeed("sleep 1")
46 | machine.succeed(
47 | "pgrep -f '${generateTestExecutable instanceName}'"
48 | )
49 | '';
50 |
51 | inherit processManagers profiles;
52 | }
53 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/services.nix:
--------------------------------------------------------------------------------
1 | { pkgs, distribution, invDistribution, system
2 | , stateDir ? "/var"
3 | , runtimeDir ? "${stateDir}/run"
4 | , logDir ? "${stateDir}/log"
5 | , cacheDir ? "${stateDir}/cache"
6 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
7 | , forceDisableUserChange ? false
8 | , processManager ? "sysvinit"
9 | }:
10 |
11 | let
12 | ids = if builtins.pathExists ./ids.nix then (import ./ids.nix).ids else {};
13 |
14 | sharedConstructors = import ../services-agnostic/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir cacheDir tmpDir forceDisableUserChange processManager ids;
16 | };
17 |
18 | constructors = import ./constructors.nix {
19 | inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager ids;
20 | webappMode = null;
21 | };
22 |
23 | processType = import ../../nixproc/derive-dysnomia-process-type.nix {
24 | inherit processManager;
25 | };
26 | in
27 | rec {
28 | webapp = rec {
29 | name = "webapp";
30 | port = ids.webappPorts.webapp or 0;
31 | dnsName = "webapp.local";
32 | pkg = constructors.webapp {
33 | inherit port;
34 | };
35 | type = processType;
36 |
37 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
38 | };
39 |
40 | nginx = rec {
41 | name = "nginx";
42 | port = ids.nginxPorts.nginx or 0;
43 | pkg = sharedConstructors.nginxReverseProxyHostBased {
44 | inherit port;
45 | };
46 | dependsOn = {
47 | inherit webapp;
48 | };
49 | type = processType;
50 |
51 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
52 | };
53 | }
54 |
--------------------------------------------------------------------------------
/nixproc/backends/systemd/test-module/default.nix:
--------------------------------------------------------------------------------
1 | {profileSettings, exprFile, extraParams, tools, pkgs, system}:
2 |
3 | let
4 | executeDeploy = import ../../../test-driver/util/execute-deploy.nix {
5 | inherit (pkgs) lib;
6 | };
7 |
8 | processesEnvSystem = import ../build-systemd-env.nix ({
9 | inherit pkgs system exprFile extraParams;
10 | } // profileSettings.params);
11 |
12 | deployEnv = if profileSettings.params.forceDisableUserChange
13 | then "XDG_RUNTIME_DIR=/run/user/1000"
14 | else "SYSTEMD_TARGET_DIR=/etc/systemd-mutable/system";
15 | in
16 | {
17 | inherit (profileSettings) params;
18 |
19 | nixosModules = pkgs.lib.optional profileSettings.params.forceDisableUserChange ./xserver-autologin-module.nix
20 | ++ pkgs.lib.optional (!profileSettings.params.forceDisableUserChange) ./systemd-path.nix;
21 |
22 | systemPackages = [
23 | tools.systemd
24 | ];
25 |
26 | additionalPaths = [ processesEnvSystem ];
27 |
28 | deployProcessManager = ''
29 | machine.succeed("mkdir -p /etc/systemd-mutable/system")
30 | '' + pkgs.lib.optionalString profileSettings.params.forceDisableUserChange ''
31 | machine.wait_for_unit("display-manager.service")
32 | machine.wait_until_succeeds("pgrep -f 'systemd --user'")
33 | machine.wait_for_file("/run/user/1000/systemd")
34 | '';
35 |
36 | deploySystem = ''
37 | machine.succeed(
38 | "${executeDeploy { inherit profileSettings; processManager = "systemd"; envVars = [ deployEnv ]; extraDeployArgs = pkgs.lib.optionalString profileSettings.params.forceDisableUserChange [ "--user" ]; processesEnv = processesEnvSystem; }}"
39 | )
40 | '';
41 | }
42 |
--------------------------------------------------------------------------------
/tools/s6-rc/nixproc-s6-svscan.in:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | shopt -s nullglob
4 |
5 | showUsage()
6 | {
7 | me="$(basename "$0")"
8 |
9 | cat < { inherit system; };
7 |
8 | processesFun = import (builtins.getEnv "PROCESSES_EXPR");
9 |
10 | processesFormalArgs = builtins.functionArgs processesFun;
11 |
12 | args = pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_STATE_DIR" != "") {
13 | stateDir = builtins.getEnv "NIXPROC_STATE_DIR";
14 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_RUNTIME_DIR" != "") {
15 | runtimeDir = builtins.getEnv "NIXPROC_RUNTIME_DIR";
16 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_LOG_DIR" != "") {
17 | logDir = builtins.getEnv "NIXPROC_LOG_DIR";
18 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_TMP_DIR" != "") {
19 | tmpDir = builtins.getEnv "NIXPROC_TMP_DIR";
20 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_CACHE_DIR" != "") {
21 | tmpDir = builtins.getEnv "NIXPROC_CACHE_DIR";
22 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_SPOOL_DIR" != "") {
23 | spoolDir = builtins.getEnv "NIXPROC_SPOOL_DIR";
24 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_LOCK_DIR" != "") {
25 | lockDir = builtins.getEnv "NIXPROC_LOCK_DIR";
26 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_LIB_DIR" != "") {
27 | libDir = builtins.getEnv "NIXPROC_LIB_DIR";
28 | } // pkgs.lib.optionalAttrs (builtins.getEnv "NIXPROC_FORCE_DISABLE_USER_CHANGE" != "") {
29 | forceDisableUserChange = true;
30 | };
31 |
32 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
33 | processManager = "disnix";
34 | inherit pkgs system;
35 | });
36 | in
37 | {distribution, invDistribution, pkgs, system}:
38 |
39 | let
40 | processes = processesFun processesArgs;
41 | in
42 | pkgs.lib.mapAttrs (name: config:
43 | config // {
44 | inherit name;
45 | type = "process";
46 | }
47 | ) processes
48 |
--------------------------------------------------------------------------------
/tests/webapps-agnostic-supervisord-stateless.nix:
--------------------------------------------------------------------------------
1 | {nixpkgs ? }:
2 |
3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; };
4 |
5 | let
6 | processesEnvAuto = import ../nixproc/backends/supervisord/build-supervisord-env.nix {
7 | exprFile = ../examples/webapps-agnostic/processes.nix;
8 | };
9 |
10 | tools = import ../tools {};
11 |
12 | nix-processmgmt = ./..;
13 |
14 | env = "NIX_PATH=nixpkgs=${nixpkgs}";
15 | in
16 | makeTest {
17 | name = "webapps-agnostic-supervisord-stateless";
18 |
19 | nodes.machine =
20 | {pkgs, ...}:
21 |
22 | {
23 | virtualisation.additionalPaths = [ pkgs.stdenv ] ++ pkgs.coreutils.all ++ [ processesEnvAuto ];
24 | virtualisation.writableStore = true;
25 | virtualisation.memorySize = 1024;
26 |
27 | # We can't download any substitutes in a test environment. To make tests
28 | # faster, we disable substitutes so that Nix does not waste any time by
29 | # attempting to download them.
30 | nix.extraOptions = ''
31 | substitute = false
32 | '';
33 |
34 | environment.systemPackages = [
35 | pkgs.stdenv
36 | pkgs.daemon
37 | pkgs.python3Packages.supervisor
38 | pkgs.dysnomia
39 | tools.common
40 | tools.systemd
41 | tools.supervisord
42 | ];
43 | };
44 |
45 | testScript = ''
46 | def check_nginx_redirection():
47 | machine.succeed(
48 | "curl --fail -H 'Host: webapp.local' http://localhost:8080 | grep 'listening on port: 5000'"
49 | )
50 |
51 |
52 | start_all()
53 |
54 | # Deploy the advanced example with multiple instances and see if it works
55 |
56 | machine.succeed(
57 | "${env} daemon --inherit --unsafe -- nixproc-supervisord-deploy-stateless ${nix-processmgmt}/examples/webapps-agnostic/processes.nix"
58 | )
59 |
60 | machine.wait_for_open_port(9001)
61 | machine.succeed("sleep 30")
62 | check_nginx_redirection()
63 | '';
64 | }
65 |
--------------------------------------------------------------------------------
/tools/bsdrc/nixproc-bsdrc-runactivity.in:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | shopt -s nullglob
4 |
5 | # Shows the usage of this command to the user
6 |
7 | showUsage()
8 | {
9 | me="$(basename "$0")"
10 |
11 | cat <&2
69 | exit 1
70 | fi
71 |
72 | source @commonchecks@
73 |
74 | checkNixStateDir
75 | checkProfile
76 | composeOldProfilePath
77 |
78 | # Execute the activities
79 |
80 | if [ "$2" = "" ]
81 | then
82 | rcpath="$oldProfilePath/etc/rc.d"
83 | else
84 | rcpath="$2/etc/rc.d"
85 | fi
86 |
87 | if [ "$reverse" = "1" ]
88 | then
89 | for i in $(rcorder $rcpath/* | tail -r)
90 | do
91 | $i $activity
92 | done
93 | else
94 | for i in $(rcorder $rcpath/*)
95 | do
96 | $i $activity
97 | done
98 | fi
99 |
--------------------------------------------------------------------------------
/nixproc/create-managed-process/agnostic/create-managed-process-from-config.nix:
--------------------------------------------------------------------------------
1 | { configFile
2 | , processManager
3 | , createManagedProcessExpr
4 | , system ? builtins.currentSystem
5 | , pkgs ? import { inherit system; }
6 | , stateDir ? "/var"
7 | , runtimeDir ? "${stateDir}/run"
8 | , logDir ? "${stateDir}/log"
9 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
10 | , forceDisableUserChange ? false
11 | }:
12 |
13 | let
14 | createManagedProcessFromConfig = configFile:
15 | let
16 | createManagedProcess = import createManagedProcessExpr {
17 | inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager;
18 | };
19 |
20 | configFileString = builtins.readFile configFile;
21 |
22 | properties = builtins.fromJSON (builtins.unsafeDiscardStringContext configFileString);
23 |
24 | # This attribute is a hack. It readds the dependencies of the JSON file as context to a frequently used string property so that the generated configuration artifact retains the runtime dependencies of the original JSON file.
25 | # This hack is needed because builtins.fromJSON can't work with strings that have context.
26 |
27 | propertiesWithContext = properties // pkgs.lib.optionalAttrs (properties ? process) {
28 | process = pkgs.lib.addContextFrom configFileString properties.process;
29 | } // pkgs.lib.optionalAttrs (properties ? foregroundProcess) {
30 | foregroundProcess = pkgs.lib.addContextFrom configFileString properties.foregroundProcess;
31 | } // pkgs.lib.optionalAttrs (properties ? daemon) {
32 | daemon = pkgs.lib.addContextFrom configFileString properties.daemon;
33 | };
34 |
35 | normalizedProperties = propertiesWithContext // pkgs.lib.optionalAttrs (properties ? dependencies) {
36 | dependencies = map (dependency: createManagedProcessFromConfig "${dependency}/${builtins.substring 33 (builtins.stringLength dependency) (baseNameOf dependency)}.json") properties.dependencies;
37 | };
38 | in
39 | createManagedProcess normalizedProperties;
40 | in
41 | createManagedProcessFromConfig configFile
42 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/build-disnix-env.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${cacheDir}/cache"
7 | , spoolDir ? "${stateDir}/spool"
8 | , lockDir ? "${stateDir}/lock"
9 | , libDir ? "${stateDir}/lib"
10 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
11 | , forceDisableUserChange ? false
12 | , callingUser ? null
13 | , callingGroup ? null
14 | , clientInterface ? (if builtins.getEnv "DISNIX_CLIENT_INTERFACE" == "" then "disnix-run-activity" else builtins.getEnv "DISNIX_CLIENT_INTERFACE")
15 | , disnixDataDir ? (if builtins.getEnv "DISNIX_DATA_DIR" == "" then throw "Set DISNIX_DATA_DIR to the data directory of Disnix" else builtins.getEnv "DISNIX_DATA_DIR")
16 | , extraParams ? {}
17 | , exprFile ? null
18 | }@args:
19 |
20 | let
21 | processesFun = import exprFile;
22 |
23 | processesFormalArgs = builtins.functionArgs processesFun;
24 |
25 | processesArgs = builtins.intersectAttrs processesFormalArgs (args // {
26 | processManager = "disnix";
27 | } // extraParams);
28 |
29 | processes = if exprFile == null then {} else processesFun processesArgs;
30 |
31 | localhostTarget = {
32 | properties.hostname = "localhost";
33 | inherit system;
34 | };
35 |
36 | services = pkgs.lib.mapAttrs (processName: process: {
37 | name = processName;
38 | inherit (process) pkg;
39 |
40 | activatesAfter = builtins.listToAttrs (map (dependency: {
41 | inherit (dependency) name;
42 | value = builtins.getAttr dependency.name services;
43 | }) process.pkg.dependencies);
44 |
45 | type = "process";
46 | targets = [ localhostTarget ];
47 | }) processes;
48 |
49 | architectureFun = {system, pkgs}:
50 | {
51 | infrastructure.localhost = localhostTarget;
52 | inherit services;
53 | };
54 |
55 | manifest = import "${disnixDataDir}/manifest.nix";
56 | in
57 | manifest.generateManifestFromArchitectureFun {
58 | inherit pkgs clientInterface architectureFun;
59 | targetProperty = "hostname";
60 | deployState = false;
61 | }
62 |
--------------------------------------------------------------------------------
/nixproc/backends/docker/test-module/default.nix:
--------------------------------------------------------------------------------
1 | {profileSettings, exprFile, extraParams, tools, pkgs, system}:
2 |
3 | let
4 | executeDeploy = import ../../../test-driver/util/execute-deploy.nix {
5 | inherit (pkgs) lib;
6 | };
7 |
8 | # We cannot deploy Docker as unprivileged user. Use a privileged installation instead
9 | profileSettingsProcessManager = import ../../../test-driver/profiles/privileged.nix;
10 |
11 | # For privileged deployments, use a different directory than /var, because it does not have the right SELinux context to work with containers
12 | profileSettingsSystem = if profileSettings.params.stateDir == "/var" then profileSettings // {
13 | params = profileSettings.params // rec {
14 | stateDir = "/dockervar";
15 | runtimeDir = "${stateDir}/run";
16 | };
17 | } else profileSettings;
18 |
19 | processesEnvProcessManager = import ../../sysvinit/build-sysvinit-env.nix ({
20 | inherit pkgs system;
21 | exprFile = ./processes-docker.nix;
22 | } // profileSettingsProcessManager.params);
23 |
24 | processesEnvSystem = import ../build-docker-env.nix ({
25 | inherit pkgs system exprFile extraParams;
26 | } // profileSettingsSystem.params);
27 | in
28 | {
29 | inherit (profileSettingsSystem) params;
30 |
31 | nixosModules = [];
32 |
33 | systemPackages = [
34 | tools.sysvinit
35 | tools.docker
36 | pkgs.docker
37 | ];
38 |
39 | additionalPaths = [ processesEnvProcessManager processesEnvSystem ];
40 |
41 | deployProcessManager = ''
42 | machine.succeed(
43 | "${executeDeploy { profileSettings = profileSettingsProcessManager; processManager = "sysvinit"; processesEnv = processesEnvProcessManager; }}"
44 | )
45 | machine.wait_for_file("${profileSettingsProcessManager.params.stateDir}/run/docker.sock")
46 | '' + pkgs.lib.optionalString profileSettings.params.forceDisableUserChange ''
47 | machine.succeed("usermod -a -G docker unprivileged")
48 | '';
49 |
50 | deploySystem = ''
51 | machine.succeed(
52 | "${executeDeploy { profileSettings = profileSettingsSystem; processManager = "docker"; processesEnv = processesEnvSystem; }}"
53 | )
54 | '';
55 | }
56 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/nix-support.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | mkDbExtraCommand = contents: let
5 | contentsList = if builtins.isList contents then pkgs.lib.unique contents else [ contents ]; in
6 | ''
7 | echo "Generating the nix database..."
8 | echo "Warning: only the database of the deepest Nix layer is loaded."
9 | echo " If you want to use nix commands in the container, it would"
10 | echo " be better to only have one layer that contains a nix store."
11 |
12 | export NIX_REMOTE=local?root=$PWD
13 | # A user is required by nix
14 | # https://github.com/NixOS/nix/blob/9348f9291e5d9e4ba3c4347ea1b235640f54fd79/src/libutil/util.cc#L478
15 | export USER=nobody
16 | ${pkgs.nix}/bin/nix-store --load-db < ${pkgs.closureInfo {rootPaths = contentsList;}}/registration
17 |
18 | mkdir -p nix/var/nix/gcroots/docker/
19 | for i in ${pkgs.lib.concatStringsSep " " contentsList}
20 | do
21 | ln -s $i nix/var/nix/gcroots/docker/$(basename $i)
22 | done;
23 | '';
24 | in
25 | result // rec {
26 | contents = result.contents or [] ++ (with pkgs; [
27 | # Nix
28 | nix.out
29 | # Needed for SSL authentication
30 | cacert
31 | # Needed for fetchgit
32 | git
33 | # Needed for downloading compressed tarballs
34 | gnutar gzip bzip2 xz
35 | ]);
36 |
37 | extraCommands = result.extraCommands or ""
38 | + mkDbExtraCommand contents;
39 |
40 | runAsRoot = result.runAsRoot or "" + ''
41 | # Initialize groups for Nix
42 | groupadd -g 30000 nixbld
43 | for i in $(seq 1 30)
44 | do
45 | groupadd -g $((30000 + i)) nixbld$i
46 | useradd -d /var/empty -c "Nix build user $i" -u $((30000 + i)) -g nixbld$i -G nixbld nixbld$i
47 | done
48 | '';
49 |
50 | config = result.config or {} // {
51 | Env = result.config.Env or [] ++ [
52 | "NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"
53 | "GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt"
54 | "NIX_PATH=/nix/var/nix/profiles/per-user/root/channels"
55 | "USER=root"
56 | "PATH=/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin"
57 | ];
58 | };
59 | }
60 |
--------------------------------------------------------------------------------
/release.nix:
--------------------------------------------------------------------------------
1 | { nixpkgs ?
2 | , system ? builtins.currentSystem
3 | , nix-processmgmt ? { outPath = ./.; rev = 1234; }
4 | }:
5 |
6 | let
7 | pkgs = import nixpkgs {};
8 | in
9 | rec {
10 | tools = import ./tools {
11 | pkgs = import nixpkgs { inherit system; };
12 | inherit system;
13 | };
14 |
15 | tests = {
16 | builds = import ./tests/builds.nix {
17 | inherit pkgs nix-processmgmt;
18 | };
19 |
20 | services = import ./tests/services {
21 | inherit nixpkgs system;
22 | };
23 |
24 | multi-process-images = import ./tests/multi-process-images.nix {
25 | inherit nixpkgs;
26 | };
27 |
28 | webapps-agnostic = {
29 | config = import ./tests/webapps-agnostic-config.nix {
30 | inherit nixpkgs;
31 | };
32 |
33 | disnix = import ./tests/webapps-agnostic-disnix.nix {
34 | inherit nixpkgs;
35 | };
36 |
37 | docker = import ./tests/webapps-agnostic-docker.nix {
38 | inherit nixpkgs;
39 | };
40 |
41 | s6-rc = import ./tests/webapps-agnostic-s6-rc.nix {
42 | inherit nixpkgs;
43 | };
44 |
45 | supervisord = import ./tests/webapps-agnostic-supervisord.nix {
46 | inherit nixpkgs;
47 | };
48 |
49 | supervisord-stateless = import ./tests/webapps-agnostic-supervisord-stateless.nix {
50 | inherit nixpkgs;
51 | };
52 |
53 | systemd = import ./tests/webapps-agnostic-systemd.nix {
54 | inherit nixpkgs;
55 | };
56 |
57 | systemd-user = import ./tests/webapps-agnostic-systemd-user.nix {
58 | inherit nixpkgs;
59 | };
60 |
61 | sysvinit = import ./tests/webapps-agnostic-sysvinit.nix {
62 | inherit nixpkgs;
63 | };
64 | };
65 |
66 | webapps-sysvinit = import ./tests/webapps-sysvinit.nix {
67 | inherit nixpkgs;
68 | };
69 | };
70 |
71 | release = pkgs.releaseTools.aggregate {
72 | name = "nix-processmgmt";
73 | constituents = builtins.attrValues tools
74 | ++ builtins.attrValues tests.builds
75 | ++ builtins.attrValues tests.webapps-agnostic
76 | ++ [
77 | tests.webapps-sysvinit
78 | tests.multi-process-images
79 | ];
80 | meta.description = "Release-critical builds";
81 | };
82 | }
83 |
--------------------------------------------------------------------------------
/tests/webapps-agnostic-config.nix:
--------------------------------------------------------------------------------
1 | {nixpkgs ? }:
2 |
3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; };
4 |
5 | let
6 | webappUnprivilegedAutoModeConfig = (import ../examples/webapps-agnostic/processes.nix {
7 | forceDisableUserChange = true;
8 | processManager = null;
9 | webappMode = null;
10 | }).webapp.pkg;
11 |
12 | webappUnprivilegedAutoModeSysvinit = (import ../examples/webapps-agnostic/processes.nix {
13 | forceDisableUserChange = true;
14 | processManager = "sysvinit";
15 | webappMode = null;
16 | }).webapp.pkg;
17 |
18 | tools = import ../tools {};
19 |
20 | nix-processmgmt = ./..;
21 |
22 | env = "NIX_PATH=nixpkgs=${nixpkgs}";
23 | in
24 | makeTest {
25 | name = "webapps-agnostic-config";
26 |
27 | nodes.machine =
28 | {pkgs, ...}:
29 |
30 | {
31 | virtualisation.additionalPaths = [ pkgs.stdenv pkgs.stdenvNoCC ] ++ pkgs.coreutils.all ++ [
32 | webappUnprivilegedAutoModeConfig
33 | webappUnprivilegedAutoModeSysvinit
34 | ];
35 |
36 | virtualisation.writableStore = true;
37 |
38 | # We can't download any substitutes in a test environment. To make tests
39 | # faster, we disable substitutes so that Nix does not waste any time by
40 | # attempting to download them.
41 | nix.extraOptions = ''
42 | substitute = false
43 | '';
44 |
45 | environment.systemPackages = [
46 | pkgs.stdenv
47 | pkgs.dysnomia
48 | tools.common
49 | tools.generate-config
50 | ];
51 | };
52 |
53 | testScript = ''
54 | start_all()
55 |
56 | # Make sure the unprivileged user can deploy
57 | machine.succeed("mkdir -p var/run var/tmp")
58 |
59 | result = machine.succeed(
60 | "cat ${webappUnprivilegedAutoModeConfig}/webapp.json >&2"
61 | )
62 |
63 | result = machine.succeed(
64 | "${env} nixproc-generate-config --process-manager sysvinit --force-disable-user-change ${webappUnprivilegedAutoModeConfig}/webapp.json"
65 | )
66 |
67 | machine.succeed("{}/etc/rc.d/init.d/webapp start".format(result[:-1]))
68 | machine.succeed("pgrep -f '/bin/webapp -D$'")
69 | machine.succeed("curl --fail http://localhost:5000 | grep 'Simple test webapp'")
70 | '';
71 | }
72 |
--------------------------------------------------------------------------------
/webapp/daemonize.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Sander van der Burg
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to
6 | * deal in the Software without restriction, including without limitation the
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 | * sell copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef __DAEMONIZE_H
24 | #define __DAEMONIZE_H
25 | #include
26 |
27 | typedef enum
28 | {
29 | STATUS_INIT_SUCCESS = 0x0,
30 | STATUS_CANNOT_ATTACH_STD_FDS_TO_NULL = 0x1,
31 | STATUS_CANNOT_CHDIR = 0x2,
32 | STATUS_CANNOT_CREATE_PID_FILE = 0x3,
33 | STATUS_CANNOT_INIT_DAEMON = 0x4,
34 | STATUS_CANNOT_UNLINK_PID_FILE = 0x5,
35 | STATUS_CANNOT_CLOSE_NON_STD_FDS = 0x6,
36 | STATUS_CANNOT_RESET_SIGNAL_HANDLERS = 0x7,
37 | STATUS_CANNOT_CLEAR_SIGNAL_MASK = 0x8,
38 | STATUS_CANNOT_CREATE_PIPE = 0x9,
39 | STATUS_CANNOT_FORK_HELPER_PROCESS = 0xa,
40 | STATUS_CANNOT_READ_FROM_PIPE = 0xb,
41 | STATUS_CANNOT_SET_SID = 0xc,
42 | STATUS_CANNOT_FORK_DAEMON_PROCESS = 0xd,
43 | STATUS_UNKNOWN_DAEMON_ERROR = 0xe
44 | }
45 | DaemonStatus;
46 |
47 | DaemonStatus daemonize(const char *pid_file, void *data, int (*initialize_daemon) (void *data), int (*run_main_loop) (void *data));
48 |
49 | void print_daemon_status(DaemonStatus status, FILE *file);
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/generate-supervisord-program.nix:
--------------------------------------------------------------------------------
1 | { createSupervisordProgram, stdenv, lib, writeTextFile, runtimeDir, forceDisableUserChange }:
2 |
3 | { name
4 | , description
5 | , initialize
6 | , daemon
7 | , daemonArgs
8 | , instanceName
9 | , pidFile
10 | , foregroundProcess
11 | , foregroundProcessArgs
12 | , path
13 | , environment
14 | , directory
15 | , umask
16 | , nice
17 | , user
18 | , dependencies
19 | , credentials
20 | , overrides
21 | , postInstall
22 | }:
23 |
24 | let
25 | generateForegroundProxy = import ../util/generate-foreground-proxy.nix {
26 | inherit stdenv lib writeTextFile;
27 | };
28 |
29 | chainLoadUser = if initialize == "" || forceDisableUserChange then null
30 | else user;
31 |
32 | command = if foregroundProcess != null then
33 | (if initialize == ""
34 | then foregroundProcess
35 | else generateForegroundProxy ({
36 | user = chainLoadUser;
37 | wrapDaemon = false;
38 | executable = foregroundProcess;
39 | inherit name initialize runtimeDir stdenv;
40 | } // lib.optionalAttrs (instanceName != null) {
41 | inherit instanceName;
42 | } // lib.optionalAttrs (pidFile != null) {
43 | inherit pidFile;
44 | })) + " ${lib.escapeShellArgs foregroundProcessArgs}"
45 | else (generateForegroundProxy ({
46 | wrapDaemon = true;
47 | user = chainLoadUser;
48 | executable = daemon;
49 | inherit name initialize runtimeDir stdenv;
50 | } // lib.optionalAttrs (instanceName != null) {
51 | inherit instanceName;
52 | } // lib.optionalAttrs (pidFile != null) {
53 | inherit pidFile;
54 | })) + " ${lib.escapeShellArgs daemonArgs}";
55 |
56 | generatedTargetSpecificArgs = {
57 | inherit name command path environment dependencies credentials postInstall;
58 | } // lib.optionalAttrs (umask != null) {
59 | inherit umask;
60 | } // lib.optionalAttrs (nice != null) {
61 | inherit nice;
62 | } // lib.optionalAttrs (pidFile != null) {
63 | inherit pidFile;
64 | } // lib.optionalAttrs (user != null && chainLoadUser == null) {
65 | inherit user;
66 | };
67 |
68 | targetSpecificArgs =
69 | if builtins.isFunction overrides then overrides generatedTargetSpecificArgs
70 | else lib.recursiveUpdate generatedTargetSpecificArgs overrides;
71 | in
72 | createSupervisordProgram targetSpecificArgs
73 |
--------------------------------------------------------------------------------
/webapp/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Sander van der Burg
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to
6 | * deal in the Software without restriction, including without limitation the
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 | * sell copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #include
24 | #include
25 | #include
26 | #include "service.h"
27 |
28 | #define TRUE 1
29 | #define FALSE 0
30 |
31 | int main(int argc, char *argv[])
32 | {
33 | unsigned int i;
34 | int run_as_daemon = FALSE;
35 | int port;
36 | char *port_value = getenv("PORT");
37 |
38 | if(port_value == NULL)
39 | {
40 | fprintf(stderr, "We need a PORT environment variable that specifies to which port the HTTP service should bind to!\n");
41 | return 1;
42 | }
43 |
44 | port = atoi(port_value);
45 |
46 | for(i = 1; i < argc; i++)
47 | {
48 | if(strcmp(argv[i], "-D") == 0)
49 | run_as_daemon = TRUE;
50 | }
51 |
52 | if(run_as_daemon)
53 | {
54 | char *pid_file = getenv("PID_FILE");
55 |
56 | if(pid_file == NULL)
57 | {
58 | fprintf(stderr, "We need the PID_FILE environment variable that specifies the path to a file storing the PID of the daemon process!\n");
59 | return 1;
60 | }
61 |
62 | return run_daemon(port, pid_file);
63 | }
64 | else
65 | return run_foreground_process(port);
66 | }
67 |
--------------------------------------------------------------------------------
/nixproc/create-credentials/default.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib, ids ? {}, forceDisableUserChange}:
2 | {groups ? {}, users ? {}}:
3 |
4 | stdenv.mkDerivation {
5 | name = "credentials";
6 | buildCommand = ''
7 | ${lib.optionalString (!forceDisableUserChange && groups != {}) ''
8 | mkdir -p $out/dysnomia-support/groups
9 |
10 | ${lib.concatMapStrings (groupname:
11 | let
12 | group = builtins.getAttr groupname groups;
13 | in
14 | ''
15 | ${lib.optionalString (!(group ? gid) && ids ? gids && builtins.hasAttr groupname ids.gids) ''echo "gid=${toString ids.gids."${groupname}"}" > $out/dysnomia-support/groups/${groupname}''}
16 |
17 | cat >> $out/dysnomia-support/groups/${groupname} < $out/dysnomia-support/users/${username} < $out/dysnomia-support/users/${username}''}
46 |
47 | cat >> $out/dysnomia-support/users/${username} < b) (map (dependency: dependency.priority) dependencies)) + 1;
30 |
31 | sequenceNumberToString = number:
32 | if number < 10 then "0${toString number}"
33 | else toString number;
34 | in
35 | stdenv.mkDerivation {
36 | inherit name priority;
37 | buildCommand = ''
38 | mkdir -p $out
39 |
40 | cat > $out/${name}-docker-settings < $out/${name}-docker-createparams < 1 then "--" else "-"}${nameValuePair.name}"
48 | + (if nameValuePair ? value then "\n${toString nameValuePair.value}" else "")
49 | ) _dockerCreateParameters}
50 | EOF
51 |
52 | touch $out/${sequenceNumberToString priority}-${name}-docker-priority
53 |
54 | ${lib.optionalString useHostNixStore ''
55 | # Add configuration files with Nix store paths used from the host system so that they will not be garbage collected
56 | ${lib.optionalString (cmd != "") ''
57 | cat > $out/${name}-docker-cmd < $out/${name}-storepaths <&2
74 | exit 1
75 | fi
76 |
77 | source @commonchecks@
78 |
79 | checkNixStateDir
80 | checkProfile
81 | composeOldProfilePath
82 |
83 | source @sysvinitchecks@
84 |
85 | checkRunlevel
86 |
87 | if [ "$2" = "" ]
88 | then
89 | rcpath="$oldProfilePath/etc/rc.d/rc${runlevel}.d"
90 | else
91 | rcpath="$2/etc/rc.d/rc${runlevel}.d"
92 | fi
93 |
94 | # Execute the activities
95 |
96 | if [ "$reverse" = "1" ]
97 | then
98 | if [ -n "$(ls -A $rcpath 2> /dev/null)" ]
99 | then
100 | for i in $(ls $rcpath/S* | sort -r)
101 | do
102 | $i $activity
103 | done
104 | fi
105 | else
106 | if [ -n "$(ls -A $rcpath 2> /dev/null)" ]
107 | then
108 | for i in $(ls $rcpath/S*)
109 | do
110 | $i $activity
111 | done
112 | fi
113 | fi
114 |
--------------------------------------------------------------------------------
/tests/services/nginx-reverse-proxy-hostbased/processes.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | }:
12 |
13 | let
14 | sharedConstructors = import ../../../examples/services-agnostic/constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir cacheDir libDir tmpDir forceDisableUserChange processManager;
16 | };
17 |
18 | constructors = import ../../../examples/webapps-agnostic/constructors/constructors.nix {
19 | inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager;
20 | webappMode = null;
21 | };
22 | in
23 | rec {
24 | webapp1 = rec {
25 | port = 5000;
26 | dnsName = "webapp1.local";
27 |
28 | pkg = constructors.webapp {
29 | inherit port;
30 | instanceSuffix = "1";
31 | };
32 | };
33 |
34 | webapp2 = rec {
35 | port = 5001;
36 | dnsName = "webapp2.local";
37 |
38 | pkg = constructors.webapp {
39 | inherit port;
40 | instanceSuffix = "2";
41 | };
42 | };
43 |
44 | webapp3 = rec {
45 | port = 5002;
46 | dnsName = "webapp3.local";
47 |
48 | pkg = constructors.webapp {
49 | inherit port;
50 | instanceSuffix = "3";
51 | };
52 | };
53 |
54 | webapp4 = rec {
55 | port = 5003;
56 | dnsName = "webapp4.local";
57 |
58 | pkg = constructors.webapp {
59 | inherit port;
60 | instanceSuffix = "4";
61 | };
62 | };
63 |
64 | nginx = rec {
65 | port = if forceDisableUserChange then 8080 else 80;
66 | webapps = [ webapp1 webapp2 webapp3 webapp4 ];
67 |
68 | pkg = sharedConstructors.nginxReverseProxyHostBased {
69 | inherit port webapps;
70 | } {};
71 | };
72 |
73 | webapp5 = rec {
74 | port = 5004;
75 | dnsName = "webapp5.local";
76 |
77 | pkg = constructors.webapp {
78 | inherit port;
79 | instanceSuffix = "5";
80 | };
81 | };
82 |
83 | webapp6 = rec {
84 | port = 5005;
85 | dnsName = "webapp6.local";
86 |
87 | pkg = constructors.webapp {
88 | inherit port;
89 | instanceSuffix = "6";
90 | };
91 | };
92 |
93 | nginx2 = rec {
94 | port = if forceDisableUserChange then 8081 else 81;
95 | webapps = [ webapp5 webapp6 ];
96 |
97 | pkg = sharedConstructors.nginxReverseProxyHostBased {
98 | inherit port webapps;
99 | instanceSuffix = "2";
100 | } {};
101 | };
102 | }
103 |
--------------------------------------------------------------------------------
/nixproc/create-image-from-steps/steps/nix-processmgmt-dynamic.nix:
--------------------------------------------------------------------------------
1 | {pkgs, common, input, result}:
2 |
3 | let
4 | commonTools = (import ../../../tools {
5 | inherit pkgs;
6 | inherit (common) system;
7 | }).common;
8 |
9 | # If no processes.nix parameter was provided, generate a template
10 | templateFile = pkgs.writeTextFile {
11 | name = "processes.nix";
12 | text = ''
13 | { pkgs ? import { inherit system; }
14 | , system ? builtins.currentSystem
15 | , stateDir ? "/var"
16 | , runtimeDir ? "''${stateDir}/run"
17 | , logDir ? "''${stateDir}/log"
18 | , cacheDir ? "''${stateDir}/cache"
19 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "''${stateDir}/tmp")
20 | , forceDisableUserChange ? false
21 | , processManager
22 | }:
23 |
24 | let
25 | nix-processmgmt-services = builtins.fetchGit {
26 | url = https://github.com/svanderburg/nix-processmgmt-services.git;
27 | ref = "master";
28 | };
29 |
30 | sharedConstructors = import "''${nix-processmgmt-services}/examples/services-agnostic/constructors.nix" {
31 | inherit pkgs stateDir runtimeDir logDir cacheDir tmpDir forceDisableUserChange processManager;
32 | };
33 | in
34 | rec {
35 | /*nginx = rec {
36 | port = 8080;
37 |
38 | pkg = sharedConstructors.nginxReverseProxyHostBased {
39 | webapps = [];
40 | inherit port;
41 | } {};
42 | };*/
43 | }
44 | '';
45 | };
46 | in
47 | result // {
48 | contents = result.contents or []
49 | ++ [ pkgs.dysnomia commonTools ];
50 |
51 | runAsRoot = result.runAsRoot or "" + ''
52 | nixproc-init-state --state-dir ${input.stateDir} --runtime-dir ${input.runtimeDir}
53 |
54 | # Provide a processes.nix expression
55 | mkdir -p /etc/nixproc
56 | '' + (if input ? exprFile then ''
57 | cp ${input.exprFile} /etc/nixproc/processes.nix
58 | '' else ''
59 | cp ${templateFile} /etc/nixproc/processes.nix
60 | '')
61 | + ''
62 | chmod 644 /etc/nixproc/processes.nix
63 | '' + pkgs.lib.optionalString (input ? idResourcesFile) ''
64 | idResourcesFileName=$(basename ${input.idResourcesFile})
65 | idResourcesTarget=/etc/nixproc/''${idResourcesFileName:33}
66 |
67 | cp ${input.idResourcesFile} $idResourcesTarget
68 | chmod 644 $idResourcesTarget
69 | '' + pkgs.lib.optionalString (input ? idsFile) ''
70 | idsFileName=$(basename ${input.idsFile})
71 | idsFileTarget=/etc/nixproc/''${idsFileName:33}
72 |
73 | cp ${input.idsFile} $idsFileTarget
74 | chmod 644 $idsFileTarget
75 | '';
76 |
77 | config = result.config or {} // {
78 | Env = result.config.Env or [] ++ [
79 | "NIXPROC_PROCESSES=/etc/nixproc/processes.nix"
80 | ];
81 | };
82 | }
83 |
--------------------------------------------------------------------------------
/tests/multi-process-images.nix:
--------------------------------------------------------------------------------
1 | {nixpkgs ? }:
2 |
3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; };
4 |
5 | let
6 | pkgs = import nixpkgs {};
7 |
8 | dockerProcessEnv = import ../nixproc/backends/systemd/build-systemd-env.nix {
9 | exprFile = ../nixproc/backends/docker/test-module/processes-docker.nix;
10 | };
11 |
12 | processManagers = [ "supervisord" "sysvinit" "disnix" "s6-rc" ];
13 | userManagementPolicies = [ "privileged" "unprivileged" ];
14 |
15 | images = pkgs.lib.genAttrs processManagers (processManager:
16 | pkgs.lib.genAttrs userManagementPolicies (userManagementPolicy:
17 | import ../examples/multi-process-image {
18 | inherit processManager;
19 | forceDisableUserChange = userManagementPolicy == "unprivileged";
20 | }
21 | )
22 | );
23 |
24 | nix-processmgmt = ./..;
25 |
26 | tools = import ../tools {};
27 |
28 | env = "NIX_PATH=nixpkgs=${nixpkgs} SYSTEMD_TARGET_DIR=/etc/systemd-mutable/system";
29 | in
30 | makeTest {
31 | name = "multi-process-images";
32 |
33 | nodes.machine =
34 | {pkgs, ...}:
35 |
36 | {
37 | virtualisation.additionalPaths = [ pkgs.stdenv ] ++ pkgs.coreutils.all ++ [ dockerProcessEnv ];
38 | virtualisation.writableStore = true;
39 | virtualisation.diskSize = 8192;
40 | virtualisation.memorySize = 8192;
41 |
42 | dysnomia = {
43 | enable = true;
44 | enableLegacyModules = false;
45 | };
46 |
47 | environment.systemPackages = [
48 | tools.common
49 | tools.systemd
50 | pkgs.docker
51 | ];
52 | };
53 |
54 | testScript = ''
55 | start_all()
56 |
57 | machine.succeed("mkdir -p /etc/systemd-mutable/system")
58 |
59 | # Deploy Docker as a systemd unit
60 |
61 | machine.succeed(
62 | "${env} nixproc-systemd-switch ${nix-processmgmt}/nixproc/backends/docker/test-module/processes-docker.nix"
63 | )
64 |
65 | machine.wait_for_unit("nix-process-docker")
66 | machine.succeed("sleep 10")
67 |
68 | ${pkgs.lib.concatMapStrings (processManager:
69 | pkgs.lib.concatMapStrings (userManagementPolicy:
70 | let
71 | image = images."${processManager}"."${userManagementPolicy}";
72 | in
73 | ''
74 | machine.succeed(
75 | "docker load -i ${image}"
76 | )
77 | machine.succeed(
78 | "docker run --name multiprocess --detach --rm --network host multiprocess:test"
79 | )
80 | machine.succeed("sleep 30")
81 | machine.succeed("curl --fail -H 'Host: webapp.local' http://localhost:8080")
82 | machine.succeed("docker stop multiprocess")
83 | machine.succeed("docker rmi multiprocess:test")
84 | '') userManagementPolicies
85 | ) processManagers}'';
86 | }
87 |
--------------------------------------------------------------------------------
/nixproc/backends/supervisord/create-supervisord-program.nix:
--------------------------------------------------------------------------------
1 | {writeTextFile, stdenv, lib, createCredentials, supervisor, basePackages, forceDisableUserChange ? false, runtimeDir}:
2 |
3 | {
4 | # A name that identifies the process instance
5 | name
6 | # Indicates whether we want to use the pidproxy
7 | , useProxy ? false
8 | # Command line instruction to execute
9 | , command ? null
10 | # Name of the PID file that contains the PID of the running process
11 | , pidFile ? "${name}.pid"
12 | # Specifies which packages need to be in the PATH
13 | , path ? []
14 | # An attribute set specifying arbitrary environment variables
15 | , environment ? {}
16 | # List of supervisord programs that this configuration depends on. This is used to derive the activation order.
17 | , dependencies ? []
18 | # Specifies which groups and users that need to be created.
19 | , credentials ? {}
20 | # Arbitrary commands executed after generating the configuration files
21 | , postInstall ? ""
22 | # The remainder of the parameters directly translate to the properties described in: http://supervisord.org/configuration.html
23 | , ...
24 | }@params:
25 |
26 | let
27 | util = import ../util {
28 | inherit lib;
29 | };
30 |
31 | properties = removeAttrs params ([ "name" "command" "useProxy" "pidFile" "path" "environment" "dependencies" "credentials" "postInstall" ] ++ lib.optional forceDisableUserChange "user");
32 |
33 | priority = if dependencies == [] then 1
34 | else builtins.head (builtins.sort (a: b: a > b) (map (dependency: dependency.priority) dependencies)) + 1;
35 |
36 | _command = (lib.optionalString useProxy "${supervisor}/bin/pidproxy ${runtimeDir}/${pidFile} ") + command;
37 |
38 | _environment = util.appendPathToEnvironment {
39 | inherit environment;
40 | path = basePackages ++ path;
41 | };
42 |
43 | confFile = writeTextFile {
44 | name = "${name}.conf";
45 | text = ''
46 | [program:${name}]
47 | command=${_command}
48 | priority=${toString priority}
49 | ''
50 | + (if _environment == {} then "" else "environment=" + lib.concatMapStringsSep "," (name:
51 | let
52 | value = builtins.getAttr name _environment;
53 | in
54 | "${name}=\"${lib.escape [ "\"" ] (toString value)}\""
55 | ) (builtins.attrNames _environment)) +
56 | "\n"
57 | + lib.concatMapStrings (name:
58 | let
59 | value = builtins.getAttr name properties;
60 | in
61 | ''${name}=${toString value}
62 | ''
63 | ) (builtins.attrNames properties);
64 | };
65 |
66 | credentialsSpec = createCredentials credentials;
67 | in
68 | stdenv.mkDerivation {
69 | inherit name priority;
70 | buildCommand = ''
71 | mkdir -p $out/conf.d
72 | ln -s ${confFile} $out/conf.d/${name}.conf
73 | ln -s ${credentialsSpec}/dysnomia-support $out/dysnomia-support
74 |
75 | ${postInstall}
76 | '';
77 | }
78 |
--------------------------------------------------------------------------------
/nixproc/backends/launchd/generate-launchd-daemon.nix:
--------------------------------------------------------------------------------
1 | { createLaunchdDaemon
2 | , stdenv
3 | , lib
4 | , writeTextFile
5 | , runtimeDir ? "/var/run"
6 | , forceDisableUserChange
7 | }:
8 |
9 | { name
10 | , description
11 | , initialize
12 | , daemon
13 | , daemonArgs
14 | , instanceName
15 | , pidFile
16 | , foregroundProcess
17 | , foregroundProcessArgs
18 | , path
19 | , environment
20 | , directory
21 | , umask
22 | , nice
23 | , user
24 | , dependencies
25 | , credentials
26 | , overrides
27 | , postInstall
28 | }:
29 |
30 | let
31 | generateForegroundProxy = import ../util/generate-foreground-proxy.nix {
32 | inherit stdenv lib writeTextFile;
33 | };
34 |
35 | chainLoadUser = if initialize == "" || forceDisableUserChange then null
36 | else user;
37 |
38 | Program = if foregroundProcess != null then
39 | if initialize == "" then foregroundProcess
40 | else generateForegroundProxy ({
41 | wrapDaemon = false;
42 | user = chainLoadUser;
43 | executable = foregroundProcess;
44 | inherit name initialize runtimeDir stdenv;
45 | } // lib.optionalAttrs (instanceName != null) {
46 | inherit instanceName;
47 | } // lib.optionalAttrs (pidFile != null) {
48 | inherit pidFile;
49 | })
50 | else generateForegroundProxy ({
51 | wrapDaemon = true;
52 | user = chainLoadUser;
53 | executable = daemon;
54 | inherit name initialize runtimeDir stdenv;
55 | } // lib.optionalAttrs (instanceName != null) {
56 | inherit instanceName;
57 | } // lib.optionalAttrs (pidFile != null) {
58 | inherit pidFile;
59 | });
60 | ProgramArguments = [ Program ] ++ (if foregroundProcess != null then foregroundProcessArgs else daemonArgs);
61 |
62 | generatedTargetSpecificArgs = {
63 | inherit name credentials postInstall Program;
64 | } // lib.optionalAttrs (ProgramArguments != [ Program ]) {
65 | inherit ProgramArguments;
66 | } // lib.optionalAttrs (environment != {}) {
67 | EnvironmentVariables = environment;
68 | } // lib.optionalAttrs (path != []) {
69 | inherit path;
70 | } // lib.optionalAttrs (directory != null) {
71 | WorkingDirectory = directory;
72 | } // lib.optionalAttrs (umask != null) {
73 | Umask = umask;
74 | } // lib.optionalAttrs (nice != null) {
75 | Nice = nice;
76 | } // lib.optionalAttrs (user != null && chainLoadUser == null) {
77 | UserName = user;
78 | };
79 |
80 | targetSpecificArgs =
81 | if builtins.isFunction overrides then overrides generatedTargetSpecificArgs
82 | else lib.recursiveUpdate generatedTargetSpecificArgs overrides;
83 |
84 | daemonConfig = createLaunchdDaemon targetSpecificArgs;
85 | in
86 | if dependencies == [] then daemonConfig else
87 | builtins.trace "WARNING: dependencies have been specified for process: ${name}, but launchd has no notion of process dependencies. Proper activation ordering cannot be guaranteed!" daemonConfig
88 |
--------------------------------------------------------------------------------
/tests/services/s6-svscan/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, testService, processManagers, profiles }:
2 |
3 | let
4 | generateTestExecutable = instanceName:
5 | pkgs.writeTextFile {
6 | name = "test-${instanceName}";
7 | text = ''
8 | #! ${pkgs.stdenv.shell} -e
9 |
10 | while true
11 | do
12 | echo "Hello ${instanceName}!" >&2
13 | sleep 1
14 | done
15 | '';
16 | executable = true;
17 | };
18 |
19 | generateTestConfigDir = instanceName:
20 | pkgs.stdenv.mkDerivation {
21 | name = "sv";
22 | buildCommand = ''
23 | mkdir -p $out/test-${instanceName}
24 | cd $out/test-${instanceName}
25 |
26 | # Generate longrun service for test process
27 | echo "longrun" > type
28 | cat > run < type
37 | cat > contents < { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , cacheDir ? "${stateDir}/cache"
6 | , logDir ? "${stateDir}/log"
7 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
8 | , forceDisableUserChange ? false
9 | }:
10 |
11 | let
12 | ids = if builtins.pathExists ./ids-advanced.nix then (import ./ids-advanced.nix).ids else {};
13 |
14 | constructors = import ./constructors/constructors.nix {
15 | inherit pkgs stateDir runtimeDir logDir cacheDir tmpDir forceDisableUserChange ids;
16 | };
17 | in
18 | rec {
19 | webapp1 = rec {
20 | port = ids.webappPorts.webapp1 or 0;
21 | dnsName = "webapp1.local";
22 |
23 | pkg = constructors.webapp {
24 | inherit port;
25 | instanceSuffix = "1";
26 | };
27 |
28 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
29 | };
30 |
31 | webapp2 = rec {
32 | port = ids.webappPorts.webapp2 or 0;
33 | dnsName = "webapp2.local";
34 |
35 | pkg = constructors.webapp {
36 | inherit port;
37 | instanceSuffix = "2";
38 | };
39 |
40 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
41 | };
42 |
43 | webapp3 = rec {
44 | port = ids.webappPorts.webapp3 or 0;
45 | dnsName = "webapp3.local";
46 |
47 | pkg = constructors.webapp {
48 | inherit port;
49 | instanceSuffix = "3";
50 | };
51 |
52 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
53 | };
54 |
55 | webapp4 = rec {
56 | port = ids.webappPorts.webapp4 or 0;
57 | dnsName = "webapp4.local";
58 |
59 | pkg = constructors.webapp {
60 | inherit port;
61 | instanceSuffix = "4";
62 | };
63 |
64 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
65 | };
66 |
67 | nginx = rec {
68 | port = ids.nginxPorts.nginx or 0;
69 |
70 | pkg = constructors.nginxReverseProxy {
71 | webapps = [ webapp1 webapp2 webapp3 webapp4 ];
72 | inherit port;
73 | } {};
74 |
75 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
76 | };
77 |
78 | webapp5 = rec {
79 | port = ids.webappPorts.webapp5 or 0;
80 | dnsName = "webapp5.local";
81 |
82 | pkg = constructors.webapp {
83 | inherit port;
84 | instanceSuffix = "5";
85 | };
86 |
87 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
88 | };
89 |
90 | webapp6 = rec {
91 | port = ids.webappPorts.webapp6 or 0;
92 | dnsName = "webapp6.local";
93 |
94 | pkg = constructors.webapp {
95 | inherit port;
96 | instanceSuffix = "6";
97 | };
98 |
99 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
100 | };
101 |
102 | nginx2 = rec {
103 | port = ids.nginxPorts.nginx2 or 0;
104 |
105 | pkg = constructors.nginxReverseProxy {
106 | webapps = [ webapp5 webapp6 ];
107 | inherit port;
108 | instanceSuffix = "2";
109 | } {};
110 |
111 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
112 | };
113 | }
114 |
--------------------------------------------------------------------------------
/nixproc/backends/util/generate-foreground-proxy.nix:
--------------------------------------------------------------------------------
1 | {stdenv, lib, writeTextFile}:
2 |
3 | { name
4 | , wrapDaemon
5 | , initialize
6 | , executable
7 | , stdenv
8 | , runtimeDir
9 | , instanceName ? null
10 | , pidFile ? (if instanceName == null then null else "${runtimeDir}/${instanceName}.pid")
11 | , user ? null
12 | , nice ? null
13 | , directory ? null
14 | , umask ? null
15 | }:
16 |
17 | let
18 | chainload-user = (import ../../../tools {}).chainload-user;
19 |
20 | _pidFile = if pidFile == null then "${runtimeDir}/$(basename ${executable}).pid" else pidFile;
21 | in
22 | writeTextFile {
23 | name = "${name}-foregroundproxy.sh";
24 | text = ''
25 | #! ${stdenv.shell} -e
26 |
27 | ${initialize}
28 |
29 | ${if wrapDaemon then ''
30 | export _TOP_PID=$$
31 |
32 | # Handle to SIGTERM and SIGINT signals and forward them to the daemon process
33 | _term()
34 | {
35 | trap "exit 0" TERM
36 | kill -TERM "$pid"
37 | kill $_TOP_PID
38 | }
39 |
40 | _interrupt()
41 | {
42 | kill -INT "$pid"
43 | }
44 |
45 | trap _term SIGTERM
46 | trap _interrupt SIGINT
47 |
48 | ${lib.optionalString (directory != null) ''
49 | cd ${directory}
50 | ''}
51 | ${lib.optionalString (umask != null) ''
52 | umask ${umask}
53 | ''}
54 |
55 | # Start process in the background as a daemon
56 | ${lib.optionalString (user != null) "${chainload-user}/bin/nixproc-chainload-user ${user} "}${lib.optionalString (nice != null) "nice -n ${nice} "}${executable} "$@"
57 |
58 | # Wait for the PID file to become available. Useful to work with daemons that don't behave well enough.
59 | count=1 # Start with 1, because 0 returns a non-zero exit status when incrementing it
60 |
61 | while [ ! -f "${_pidFile}" ]
62 | do
63 | if [ $count -eq 10 ]
64 | then
65 | echo "It does not seem that there isn't any pid file! Giving up!"
66 | exit 1
67 | fi
68 |
69 | echo "Waiting for ${_pidFile} to become available..."
70 | sleep 1
71 |
72 | ((count++))
73 | done
74 |
75 | # Determine the daemon's PID by using the PID file
76 | pid=$(cat ${_pidFile})
77 |
78 | # Wait in the background for the PID to terminate
79 | ${if stdenv.isDarwin then ''
80 | lsof -p $pid +r 3 &>/dev/null &
81 | '' else if stdenv.isLinux || stdenv.isCygwin then ''
82 | tail --pid=$pid -f /dev/null &
83 | '' else if stdenv.isBSD || stdenv.isSunOS then ''
84 | pwait $pid &
85 | '' else throw "Don't know how to wait for process completion on system: ${stdenv.system}"}
86 |
87 | # Wait for the blocker process to complete. We use wait, so that bash can still
88 | # handle the SIGTERM and SIGINT signals that may be sent to it by a process
89 | # manager
90 | blocker_pid=$!
91 | wait $blocker_pid
92 | '' else ''
93 | exec ${lib.optionalString (user != null) "${chainload-user}/bin/nixproc-chainload-user ${user} "}${lib.optionalString (nice != null) "nice -n ${nice} "}"${executable}" "$@"
94 | ''}
95 | '';
96 | executable = true;
97 | }
98 |
--------------------------------------------------------------------------------
/nixproc/backends/disnix/generate-process-script.nix:
--------------------------------------------------------------------------------
1 | { createProcessScript, writeTextFile, stdenv, lib, daemon, basePackages
2 | , runtimeDir, logDir, tmpDir, forceDisableUserChange
3 | }:
4 |
5 | let
6 | daemonPkg = daemon; # Circumvent name conflict with the parameter in the next function header
7 | in
8 |
9 | { name
10 | , description
11 | , initialize
12 | , daemon
13 | , daemonArgs
14 | , instanceName
15 | , pidFile
16 | , foregroundProcess
17 | , foregroundProcessArgs
18 | , path
19 | , environment
20 | , directory
21 | , umask
22 | , nice
23 | , user
24 | , dependencies
25 | , credentials
26 | , overrides
27 | , postInstall
28 | }:
29 |
30 | let
31 | util = import ../util {
32 | inherit lib;
33 | };
34 |
35 | _environment = util.appendPathToEnvironment {
36 | inherit environment;
37 | path = basePackages ++ [ daemonPkg ] ++ path;
38 | };
39 |
40 | _user = util.determineUser {
41 | inherit user forceDisableUserChange;
42 | };
43 |
44 | pidFilesDir = util.determinePIDFilesDir {
45 | inherit user runtimeDir tmpDir; # We can't use _user because we want to keep the path convention the same
46 | };
47 |
48 | _pidFile = util.autoGeneratePIDFilePath {
49 | inherit pidFile instanceName pidFilesDir;
50 | };
51 |
52 | invocationCommand =
53 | if daemon != null then util.invokeDaemon {
54 | process = daemon;
55 | args = daemonArgs;
56 | su = "su";
57 | user = _user;
58 | }
59 | else if foregroundProcess != null then util.daemonizeForegroundProcess {
60 | daemon = "daemon";
61 | process = foregroundProcess;
62 | args = foregroundProcessArgs;
63 | pidFile = _pidFile;
64 | user = _user;
65 | outputLogFile = util.autoGenerateDaemonLogFilePath {
66 | inherit name instanceName logDir tmpDir;
67 | user = _user;
68 | enableDaemonOutputLogging = true;
69 | };
70 | inherit pidFilesDir;
71 | }
72 | else throw "I don't know how to start this process!";
73 |
74 | generatedTargetSpecificArgs = {
75 | inherit name dependencies credentials postInstall;
76 |
77 | process = writeTextFile {
78 | name = "${name}-process-wrapper";
79 | executable = true;
80 | text = ''
81 | #! ${stdenv.shell} -e
82 | ''
83 | + util.printShellEnvironmentVariables {
84 | environment = _environment;
85 | allowSystemPath = true;
86 | }
87 | + lib.optionalString (umask != null) ''
88 | umask ${umask}
89 | ''
90 | + lib.optionalString (initialize != null) ''
91 | ${initialize}
92 | ''
93 | + lib.optionalString (directory != null) ''
94 | cd ${directory}
95 | ''
96 | + "exec ${lib.optionalString (nice != null) "nice -n ${toString nice}"} ${invocationCommand}";
97 | };
98 | } // lib.optionalAttrs (_pidFile != null) {
99 | pidFile = _pidFile;
100 | };
101 |
102 | targetSpecificArgs =
103 | if builtins.isFunction overrides then overrides generatedTargetSpecificArgs
104 | else lib.recursiveUpdate generatedTargetSpecificArgs overrides;
105 | in
106 | createProcessScript targetSpecificArgs
107 |
--------------------------------------------------------------------------------
/examples/services-agnostic/constructors/nginx/nginx-reverse-proxy-hostbased.nix:
--------------------------------------------------------------------------------
1 | {createManagedProcess, stdenv, lib, writeTextFile, nginx, runtimeDir, stateDir, cacheDir, forceDisableUserChange}:
2 |
3 | { port ? 80
4 | , webapps ? []
5 | , instanceSuffix ? ""
6 | , instanceName ? "nginx${instanceSuffix}"
7 | , workerConnections ? 190000
8 | }:
9 |
10 | interDependencies:
11 |
12 | let
13 | user = instanceName;
14 | group = instanceName;
15 |
16 | nginxStateDir = "${stateDir}/${instanceName}";
17 | nginxLogDir = "${nginxStateDir}/logs";
18 | nginxCacheDir = "${cacheDir}/${instanceName}";
19 | in
20 | import ./default.nix {
21 | inherit createManagedProcess lib nginx stateDir forceDisableUserChange runtimeDir cacheDir;
22 | } {
23 | inherit instanceName;
24 |
25 | dependencies = map (webapp: webapp.pkg) webapps
26 | ++ map (interDependency: interDependency.pkgs."${stdenv.system}") (builtins.attrValues interDependencies);
27 |
28 | configFile = writeTextFile {
29 | name = "nginx.conf";
30 | text = ''
31 | pid ${runtimeDir}/${instanceName}.pid;
32 | error_log ${nginxLogDir}/error.log;
33 |
34 | ${lib.optionalString (!forceDisableUserChange) ''
35 | user ${user} ${group};
36 | ''}
37 |
38 | events {
39 | worker_connections ${toString workerConnections};
40 | }
41 |
42 | http {
43 | access_log ${nginxLogDir}/access.log;
44 | error_log ${nginxLogDir}/error.log;
45 |
46 | proxy_temp_path ${nginxCacheDir}/proxy;
47 | client_body_temp_path ${nginxCacheDir}/client_body;
48 | fastcgi_temp_path ${nginxCacheDir}/fastcgi;
49 | uwsgi_temp_path ${nginxCacheDir}/uwsgi;
50 | scgi_temp_path ${nginxCacheDir}/scgi;
51 |
52 | ${lib.concatMapStrings (dependency: ''
53 | upstream webapp${toString dependency.port} {
54 | server localhost:${toString dependency.port};
55 | }
56 | '') webapps}
57 |
58 | ${lib.concatMapStrings (paramName:
59 | let
60 | dependency = builtins.getAttr paramName interDependencies;
61 | in
62 | ''
63 | upstream webapp${toString dependency.port} {
64 | server ${dependency.target.properties.hostname}:${toString dependency.port};
65 | }
66 | '') (builtins.attrNames interDependencies)}
67 |
68 | # Fallback virtual host displaying an error page. This is what users see
69 | # if they connect to a non-deployed web application.
70 | # Without it, nginx redirects to the first available virtual host, giving
71 | # unpredictable results. This could happen while an upgrade is in progress.
72 |
73 | server {
74 | listen ${toString port};
75 | server_name aaaa;
76 | root ${./errorpage};
77 | }
78 |
79 | ${lib.concatMapStrings (dependency: ''
80 | server {
81 | listen ${toString port};
82 | server_name ${dependency.dnsName};
83 |
84 | location / {
85 | proxy_pass http://webapp${toString dependency.port};
86 | }
87 | }
88 | '') (webapps ++ builtins.attrValues interDependencies)}
89 | }
90 | '';
91 | };
92 | }
93 |
--------------------------------------------------------------------------------
/examples/webapps-sysvinit/constructors/nginx/nginx-reverse-proxy.nix:
--------------------------------------------------------------------------------
1 | {createSystemVInitScript, stdenv, lib, writeTextFile, nginx, runtimeDir, stateDir, cacheDir, logDir, forceDisableUserChange}:
2 |
3 | { port ? 80
4 | , webapps ? []
5 | , instanceSuffix ? ""
6 | , instanceName ? "nginx${instanceSuffix}"
7 | , workerConnections ? 190000
8 | }:
9 |
10 | interDependencies:
11 |
12 | let
13 | user = instanceName;
14 | group = instanceName;
15 |
16 | nginxStateDir = "${stateDir}/${instanceName}";
17 | nginxLogDir = "${nginxStateDir}/logs";
18 | nginxCacheDir = "${cacheDir}/${instanceName}";
19 | in
20 | import ./default.nix {
21 | inherit createSystemVInitScript lib nginx runtimeDir cacheDir forceDisableUserChange;
22 | stateDir = nginxStateDir;
23 | } {
24 | inherit instanceName;
25 |
26 | dependencies = map (webapp: webapp.pkg) webapps
27 | ++ map (interDependency: interDependency.pkgs."${stdenv.system}") (builtins.attrValues interDependencies);
28 |
29 | configFile = writeTextFile {
30 | name = "nginx.conf";
31 | text = ''
32 | pid ${runtimeDir}/${instanceName}.pid;
33 | error_log ${nginxLogDir}/error.log;
34 |
35 | ${lib.optionalString (!forceDisableUserChange) ''
36 | user ${user} ${group};
37 | ''}
38 |
39 | events {
40 | worker_connections ${toString workerConnections};
41 | }
42 |
43 | http {
44 | access_log ${nginxLogDir}/access.log;
45 | error_log ${nginxLogDir}/error.log;
46 |
47 | proxy_temp_path ${nginxCacheDir}/proxy;
48 | client_body_temp_path ${nginxCacheDir}/client_body;
49 | fastcgi_temp_path ${nginxCacheDir}/fastcgi;
50 | uwsgi_temp_path ${nginxCacheDir}/uwsgi;
51 | scgi_temp_path ${nginxCacheDir}/scgi;
52 |
53 | ${lib.concatMapStrings (dependency: ''
54 | upstream webapp${toString dependency.port} {
55 | server localhost:${toString dependency.port};
56 | }
57 | '') webapps}
58 |
59 | ${lib.concatMapStrings (paramName:
60 | let
61 | dependency = builtins.getAttr paramName interDependencies;
62 | in
63 | ''
64 | upstream webapp${toString dependency.port} {
65 | server ${dependency.target.properties.hostname}:${toString dependency.port};
66 | }
67 | '') (builtins.attrNames interDependencies)}
68 |
69 | # Fallback virtual host displaying an error page. This is what users see
70 | # if they connect to a non-deployed web application.
71 | # Without it, nginx redirects to the first available virtual host, giving
72 | # unpredictable results. This could happen while an upgrade is in progress.
73 |
74 | server {
75 | client_body_temp_path ${nginxCacheDir}/client_body;
76 | listen ${toString port};
77 | server_name aaaa;
78 | root ${./errorpage};
79 | }
80 |
81 | ${lib.concatMapStrings (dependency: ''
82 | server {
83 | client_body_temp_path ${nginxCacheDir}/client_body;
84 | listen ${toString port};
85 | server_name ${dependency.dnsName};
86 |
87 | location / {
88 | proxy_pass http://webapp${toString dependency.port};
89 | }
90 | }
91 | '') (webapps ++ builtins.attrValues interDependencies)}
92 | }
93 | '';
94 | };
95 | }
96 |
--------------------------------------------------------------------------------
/nixproc/create-managed-process/agnostic/create-managed-process.nix:
--------------------------------------------------------------------------------
1 | { processManager, generators ? {}, stdenv }:
2 |
3 | {
4 | # A name that identifies the process instance
5 | name ? instanceName
6 | # A more human-readable description of the process
7 | , description ? name
8 | # Shell commands that specify how the state should be initialized. This script runs as root.
9 | , initialize ? ""
10 | # Path to a process to execute (both in foreground and daemon mode)
11 | , process ? null
12 | # Generic command-line parameters propagated to the process
13 | , args ? []
14 | # The executable that needs to run to start the process is daemon mode
15 | , daemon ? process
16 | # Extra arguments appended to args when the process runs in daemon mode
17 | , daemonExtraArgs ? []
18 | # Command-line arguments propagated to the daemon
19 | , daemonArgs ? (args ++ daemonExtraArgs)
20 | # A name that uniquely identifies each process instance. It is used to generate a unique PID file and as a process name when none was specified.
21 | , instanceName ? null
22 | # Path to a PID file that the system should use to manage the process. If null, it will use the default path (typically the global runtime dir or temp dir).
23 | , pidFile ? null
24 | # The executable that needs to run to start the process in foreground mode
25 | , foregroundProcess ? process
26 | # Extra arguments appended to args when the process runs in foreground mode
27 | , foregroundProcessExtraArgs ? []
28 | # Command-line arguments propagated to the foreground process
29 | , foregroundProcessArgs ? (args ++ foregroundProcessExtraArgs)
30 | # Specifies which packages need to be in the PATH
31 | , path ? []
32 | # An attribute set specifying arbitrary environment variables
33 | , environment ? {}
34 | # If not null, the current working directory will be changed before executing any activities
35 | , directory ? null
36 | # If not null, the umask will be changed before executing any activities
37 | , umask ? null
38 | # If not null, the nice level be changed before executing any activities
39 | , nice ? null
40 | # Specifies as which user the process should run. If null, the user privileges will not be changed.
41 | , user ? null
42 | # Dependencies on other processes. Typically, this specification is used to derive the activation order.
43 | , dependencies ? []
44 | # Specifies which groups and users that need to be created.
45 | , credentials ? {}
46 | # Specifies process manager specific properties that augmented to the generated function parameters
47 | , overrides ? {}
48 | # Arbitrary build commands executed after generating the configuration files
49 | , postInstall ? ""
50 | }@properties:
51 |
52 | if name == null then throw "No process name was specified or can be inferred!"
53 | else
54 |
55 | let
56 | createAgnosticConfig = import ./create-agnostic-config.nix {
57 | inherit stdenv;
58 | };
59 |
60 | generateProcessFun = if builtins.hasAttr processManager generators
61 | then builtins.getAttr processManager generators
62 | else throw "Unknown process manager: ${processManager}";
63 | in
64 | if processManager == null then createAgnosticConfig properties
65 | else generateProcessFun {
66 | inherit name description initialize daemon daemonArgs instanceName pidFile foregroundProcess foregroundProcessArgs path environment directory umask nice user dependencies credentials postInstall;
67 | overrides = if builtins.hasAttr processManager overrides then builtins.getAttr processManager overrides else {};
68 | }
69 |
--------------------------------------------------------------------------------
/examples/webapps-agnostic/processes-advanced.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import { inherit system; }
2 | , system ? builtins.currentSystem
3 | , stateDir ? "/var"
4 | , runtimeDir ? "${stateDir}/run"
5 | , logDir ? "${stateDir}/log"
6 | , cacheDir ? "${stateDir}/cache"
7 | , libDir ? "${stateDir}/lib"
8 | , tmpDir ? (if stateDir == "/var" then "/tmp" else "${stateDir}/tmp")
9 | , forceDisableUserChange ? false
10 | , processManager
11 | , webappMode ? null
12 | }:
13 |
14 | let
15 | ids = if builtins.pathExists ./ids-advanced.nix then (import ./ids-advanced.nix).ids else {};
16 |
17 | sharedConstructors = import ../services-agnostic/constructors/constructors.nix {
18 | inherit pkgs stateDir runtimeDir logDir cacheDir libDir tmpDir forceDisableUserChange processManager ids;
19 | };
20 |
21 | constructors = import ./constructors/constructors.nix {
22 | inherit pkgs stateDir runtimeDir logDir tmpDir forceDisableUserChange processManager webappMode ids;
23 | };
24 | in
25 | rec {
26 | webapp1 = rec {
27 | port = ids.webappPorts.webapp1 or 0;
28 | dnsName = "webapp1.local";
29 |
30 | pkg = constructors.webapp {
31 | inherit port;
32 | instanceSuffix = "1";
33 | };
34 |
35 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
36 | };
37 |
38 | webapp2 = rec {
39 | port = ids.webappPorts.webapp2 or 0;
40 | dnsName = "webapp2.local";
41 |
42 | pkg = constructors.webapp {
43 | inherit port;
44 | instanceSuffix = "2";
45 | };
46 |
47 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
48 | };
49 |
50 | webapp3 = rec {
51 | port = ids.webappPorts.webapp3 or 0;
52 | dnsName = "webapp3.local";
53 |
54 | pkg = constructors.webapp {
55 | inherit port;
56 | instanceSuffix = "3";
57 | };
58 |
59 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
60 | };
61 |
62 | webapp4 = rec {
63 | port = ids.webappPorts.webapp4 or 0;
64 | dnsName = "webapp4.local";
65 |
66 | pkg = constructors.webapp {
67 | inherit port;
68 | instanceSuffix = "4";
69 | };
70 |
71 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
72 | };
73 |
74 | nginx = rec {
75 | port = ids.nginxPorts.nginx or 0;
76 |
77 | pkg = sharedConstructors.nginxReverseProxyHostBased {
78 | webapps = [ webapp1 webapp2 webapp3 webapp4 ];
79 | inherit port;
80 | } {};
81 |
82 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
83 | };
84 |
85 | webapp5 = rec {
86 | port = ids.webappPorts.webapp5 or 0;
87 | dnsName = "webapp5.local";
88 |
89 | pkg = constructors.webapp {
90 | inherit port;
91 | instanceSuffix = "5";
92 | };
93 |
94 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
95 | };
96 |
97 | webapp6 = rec {
98 | port = ids.webappPorts.webapp6 or 0;
99 | dnsName = "webapp6.local";
100 |
101 | pkg = constructors.webapp {
102 | inherit port;
103 | instanceSuffix = "6";
104 | };
105 |
106 | requiresUniqueIdsFor = [ "webappPorts" "uids" "gids" ];
107 | };
108 |
109 | nginx2 = rec {
110 | port = ids.nginxPorts.nginx2 or 0;
111 |
112 | pkg = sharedConstructors.nginxReverseProxyHostBased {
113 | webapps = [ webapp5 webapp6 ];
114 | inherit port;
115 | instanceSuffix = "2";
116 | } {};
117 |
118 | requiresUniqueIdsFor = [ "nginxPorts" "uids" "gids" ];
119 | };
120 | }
121 |
--------------------------------------------------------------------------------
/nixproc/backends/launchd/create-launchd-daemon.nix:
--------------------------------------------------------------------------------
1 | { writeTextFile
2 | , stdenv
3 | , lib
4 | , createCredentials
5 |
6 | # Specifies whether user changing functionality should be disabled or not
7 | , forceDisableUserChange ? false
8 | # Prefix that is in front of all launchd plist files generated by this function
9 | , prefix ? "org.nixos."
10 | }:
11 |
12 | {
13 | # A name that identifies the process instance
14 | name
15 | # Specifies which packages need to be in the PATH
16 | , path ? []
17 | # Specifies which groups and users that need to be created.
18 | , credentials ? {}
19 | # Arbitrary build commands executed after generating the configuration files
20 | , postInstall ? ""
21 | # The remaining parameters are directly translated to plist XML properties.
22 | # Possible configuration options can be found here: https://www.launchd.info
23 | , ...
24 | }@args:
25 |
26 | let
27 | util = import ../util {
28 | inherit lib;
29 | };
30 |
31 | environment = util.appendPathToEnvironment {
32 | environment = lib.mapAttrs (name: value: toString value) args.EnvironmentVariables or {}; # Convert all environment variables to strings
33 | inherit path;
34 | };
35 |
36 | label = if args ? Label then args.Label else "${prefix}${name}";
37 |
38 | properties = {
39 | Label = label;
40 | } // removeAttrs args ([ "name" "path" "credentials" "postInstall" ] ++ lib.optional forceDisableUserChange "UserName") // lib.optionalAttrs (environment != {}) {
41 | EnvironmentVariables = environment;
42 | };
43 |
44 | attrsToPList = attrs:
45 | "\n"
46 | + lib.concatMapStrings (name:
47 | let
48 | value = builtins.getAttr name attrs;
49 | in
50 | ''
51 | ${name}
52 | ${exprToPList value}
53 | ''
54 | ) (builtins.attrNames attrs)
55 | + "\n";
56 |
57 | listToPList = list:
58 | "\n"
59 | + lib.concatMapStrings (value: exprToPList value + "\n") list
60 | + "\n";
61 |
62 | exprToPList = expr:
63 | let
64 | exprType = builtins.typeOf expr;
65 | in
66 | if exprType == "bool" then
67 | if expr then "" else ""
68 | else if exprType == "int" then "${toString expr}"
69 | else if exprType == "float" then "${toString expr}"
70 | else if exprType == "string" then "${expr}"
71 | else if exprType == "set" then
72 | if lib.isDerivation expr
73 | then "${expr}"
74 | else attrsToPList expr
75 | else if exprType == "list" then listToPList expr
76 | else if exprType == "null" then ""
77 | else if exprType == "lambda" then throw "Cannot convert a lambda to a plist property"
78 | else "${expr}";
79 |
80 | launchdDaemonConfig = writeTextFile {
81 | name = "${label}.plist";
82 | text = ''
83 |
84 |
85 |
86 |
87 | ${exprToPList properties}
88 |
89 | '';
90 | };
91 |
92 | credentialsSpec = createCredentials credentials;
93 | in
94 | stdenv.mkDerivation {
95 | inherit name;
96 | buildCommand = ''
97 | mkdir -p $out/Library/LaunchDaemons
98 | ln -s ${launchdDaemonConfig} $out/Library/LaunchDaemons/${label}.plist
99 | ln -s ${credentialsSpec}/dysnomia-support $out/dysnomia-support
100 |
101 | ${postInstall}
102 | '';
103 | }
104 |
--------------------------------------------------------------------------------
/nixproc/backends/util/default.nix:
--------------------------------------------------------------------------------
1 | {lib}:
2 |
3 | rec {
4 | /*
5 | * Composes a PATH environment variable from a collection of packages by
6 | * translating their paths to bin/ sub folders
7 | */
8 | composePathEnvVariable = {path}:
9 | builtins.concatStringsSep ":" (map (package: "${package}/bin") path);
10 |
11 | /*
12 | * Appends the bin/ sub folders in the packages in path as a PATH environment
13 | * variable to the environment.
14 | */
15 | appendPathToEnvironment = {environment, path}:
16 | lib.optionalAttrs (path != []) {
17 | PATH = composePathEnvVariable {
18 | inherit path;
19 | };
20 | } // environment;
21 |
22 | /*
23 | * Prints escaped export statements that configure environment variables
24 | *
25 | * Parameters:
26 | * environment: attribute set in which the keys are the environment variables names and the values to environment variable values
27 | * allowSystemPath: whether to allow access to the original system PATH
28 | */
29 | printShellEnvironmentVariables = {environment, allowSystemPath ? true}:
30 | lib.concatMapStrings (name:
31 | let
32 | value = builtins.getAttr name environment;
33 | in
34 | ''
35 | export ${name}=${lib.escapeShellArg value}${lib.optionalString (allowSystemPath && name == "PATH") ":$PATH"}
36 | ''
37 | ) (builtins.attrNames environment);
38 |
39 | /*
40 | * Determines the actual user name
41 | */
42 | determineUser = {user, forceDisableUserChange}:
43 | if forceDisableUserChange then null else user;
44 |
45 | /*
46 | * Determines the preferred directory in which PID files should be stored.
47 | * For privileged users it is in the runtime dir, unprivileged users use the
48 | * temp dir.
49 | */
50 | determinePIDFilesDir = {user, runtimeDir, tmpDir}:
51 | if user == null then runtimeDir else tmpDir;
52 |
53 | /*
54 | * Auto-generates the path to the preferred PID file if none has been
55 | * specified.
56 | */
57 | autoGeneratePIDFilePath = {pidFile, instanceName, pidFilesDir}:
58 | if pidFile == null then
59 | if instanceName == null then null
60 | else "${pidFilesDir}/${instanceName}.pid"
61 | else pidFile;
62 |
63 | /*
64 | * Auto-generates the path to the log file that captures the
65 | * output of a process invoked with the daemon command
66 | */
67 | autoGenerateDaemonLogFilePath = {name, instanceName, logDir, tmpDir, user, enableDaemonOutputLogging ? true}:
68 | if enableDaemonOutputLogging then
69 | if instanceName == null then
70 | if user == null then "${logDir}/nixproc-${name}.log"
71 | else "${tmpDir}/nixproc-${name}.log"
72 | else
73 | if user == null then "${logDir}/nixproc-${instanceName}.log"
74 | else "${tmpDir}/nixproc-${instanceName}.log"
75 | else null;
76 |
77 | /*
78 | * Creates a shell command invocation that deamonizes a foreground process by
79 | * using libslack's daemon command.
80 | */
81 | daemonizeForegroundProcess = {daemon, process, args, pidFile ? null, pidFilesDir, user ? null, outputLogFile ? null}:
82 | "${daemon} --unsafe --inherit"
83 | + (if outputLogFile == null then "" else " --output ${outputLogFile}")
84 | + (if pidFile == null then " --pidfiles ${pidFilesDir} --name $(basename ${process})" else " --pidfile ${pidFile}")
85 | + lib.optionalString (user != null) " --user ${user}"
86 | + " -- ${process} ${lib.escapeShellArgs args}";
87 |
88 | /*
89 | * Creates a daemon command invocation that escapes parameters and changes the
90 | * user, if needed.
91 | */
92 | invokeDaemon = {process, args, su, user ? null}:
93 | let
94 | invocation = "${process} ${lib.escapeShellArgs args}";
95 | in
96 | if user == null then invocation
97 | else "${su} ${user} -c ${lib.escapeShellArgs [ invocation ]}";
98 | }
99 |
--------------------------------------------------------------------------------
/nixproc/backends/cygrunsrv/create-cygrunsrv-params.nix:
--------------------------------------------------------------------------------
1 | { stdenv
2 | , lib
3 | , writeTextFile
4 |
5 | # Prefix that is in front of all Windows services generated by this function
6 | , prefix ? "nix-process-"
7 | }:
8 |
9 | {
10 | # A name that identifies the process instance
11 | name
12 | # A more human readable name that identifies the process
13 | , displayName ? "${prefix}${name}"
14 | # Path to the executable to run
15 | , path
16 | # Command-line arguments propagated to the executable
17 | , args ? []
18 | # An attribute set specifying arbitrary environment variables
19 | , environment ? {}
20 | # Specifies whether this service needs to be automatically started or not.
21 | # 'manual' indicates manual start, 'auto' indicates automatic start
22 | , type ? "auto"
23 | # Specifies as which user the process should run. If null, the user privileges will not be changed.
24 | , user ? null
25 | # The password of the user so that the user privileges can be changed
26 | , password ? null
27 | # File where the stdin should read from. null indicates that no file should be read
28 | , stdin ? null
29 | # File where the stdout should write to. null discards output
30 | , stdout ? null
31 | # File where the stderr should write to. null discards output
32 | , stderr ? null
33 | # The signal that needs to be sent to the process to terminate it
34 | , terminateSignal ? "TERM"
35 | # Indicates whether the process should be terminated on shutdown
36 | , terminateOnShutdown ? false
37 | # Dependencies on other Windows services. The service manager makes sure that dependencies are activated first.
38 | , dependencies ? []
39 | # Specifies which packages need to be in the PATH
40 | , environmentPath ? []
41 | # Arbitrary commands executed after generating the configuration files
42 | , postInstall ? ""
43 | }:
44 |
45 | let
46 | util = import ../util {
47 | inherit lib;
48 | };
49 |
50 | _environment = util.appendPathToEnvironment {
51 | inherit environment;
52 | path = environmentPath;
53 | };
54 |
55 | cygrunsrvConfig = writeTextFile {
56 | name = "${prefix}${name}-cygrunsrv-params";
57 | text = ''
58 | --path
59 | ${path}
60 | --disp
61 | ${displayName}
62 | ''
63 | + lib.optionalString (type != "auto") ''
64 | --type
65 | ${type}
66 | ''
67 | + lib.optionalString (args != []) ''
68 | --args
69 | ${builtins.concatStringsSep " " (map (arg: lib.escapeShellArg arg) args)}
70 | ''
71 | +
72 | lib.concatMapStrings (variableName:
73 | let
74 | value = builtins.getAttr variableName _environment;
75 | in
76 | ''
77 | --env
78 | '${variableName}=${lib.escape [ "'" ] (toString value)}'
79 | '') (builtins.attrNames _environment)
80 | + lib.optionalString (user != null) ''
81 | --user
82 | ${user}
83 | ''
84 | + lib.optionalString (password != null) ''
85 | --passwd
86 | ${password}
87 | ''
88 | + lib.optionalString (stdin != null) ''
89 | --stdin
90 | ${stdin}
91 | ''
92 | + lib.optionalString (stdout != null) ''
93 | --stdout
94 | ${stdout}
95 | ''
96 | + lib.optionalString (stderr != null) ''
97 | --stderr
98 | ${stderr}
99 | ''
100 | + lib.optionalString (terminateSignal != "TERM") ''
101 | --termsig
102 | ${terminateSignal}
103 | ''
104 | + lib.optionalString terminateOnShutdown ''
105 | --shutdown
106 | ''
107 | + lib.concatMapStrings (dependency: ''
108 | --dep
109 | ${dependency.name}
110 | '') dependencies;
111 | };
112 | in
113 | stdenv.mkDerivation {
114 | name = "${prefix}${name}";
115 |
116 | buildCommand = ''
117 | mkdir -p $out
118 | ln -s ${cygrunsrvConfig} $out/${prefix}${name}-cygrunsrvparams
119 | ${postInstall}
120 | '';
121 | }
122 |
--------------------------------------------------------------------------------
/nixproc/test-driver/agnostic.nix:
--------------------------------------------------------------------------------
1 | { nixpkgs ?
2 | , system ? builtins.currentSystem
3 | , processManagerModules ? {}
4 | , profileSettingModules ? {}
5 | }:
6 |
7 | let
8 | pkgs = import nixpkgs { inherit system; };
9 |
10 | tools = import ../../tools {
11 | inherit pkgs system;
12 | };
13 |
14 | testSystemVariantForProcessManager = {name, processManager, profileSettings, exprFile, extraParams ? {}, nixosConfig ? null, systemPackages ? [], initialTests ? null, readiness ? null, tests ? null, postTests ? null}:
15 | let
16 | processManagerModule = builtins.getAttr processManager processManagerModules;
17 |
18 | processManagerSettings = import processManagerModule {
19 | inherit profileSettings exprFile extraParams pkgs system tools;
20 | };
21 |
22 | processesFun = import exprFile;
23 | processesFormalArgs = builtins.functionArgs processesFun;
24 |
25 | processesArgs = builtins.intersectAttrs processesFormalArgs ({
26 | inherit pkgs system processManager;
27 | } // processManagerSettings.params // extraParams);
28 |
29 | processes = processesFun processesArgs;
30 | in
31 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { inherit system; };
32 |
33 | makeTest {
34 | inherit name;
35 |
36 | nodes.machine =
37 | {pkgs, lib, ...}:
38 |
39 | {
40 | imports =
41 | profileSettings.nixosModules
42 | ++ processManagerSettings.nixosModules
43 | ++ lib.optional (nixosConfig != null) nixosConfig;
44 |
45 | virtualisation.additionalPaths = processManagerSettings.additionalPaths;
46 |
47 | nix.extraOptions = ''
48 | substitute = false
49 | '';
50 |
51 | environment.systemPackages = [
52 | pkgs.dysnomia
53 | tools.common
54 | ]
55 | ++ processManagerSettings.systemPackages
56 | ++ systemPackages;
57 | };
58 |
59 | testScript =
60 | ''
61 | start_all()
62 | ''
63 | + processManagerSettings.deployProcessManager
64 | + processManagerSettings.deploySystem
65 | + pkgs.lib.optionalString (initialTests != null) (initialTests (processManagerSettings.params // { inherit processes; }))
66 |
67 | # Execute readiness check for all process instances
68 | + pkgs.lib.optionalString (readiness != null)
69 | (pkgs.lib.concatMapStrings (instanceName:
70 | let
71 | instance = builtins.getAttr instanceName processes;
72 | in
73 | readiness ({ inherit instanceName instance; } // processManagerSettings.params)
74 | ) (builtins.attrNames processes))
75 |
76 | # Execute tests for all process instances
77 | + pkgs.lib.optionalString (tests != null)
78 | (pkgs.lib.concatMapStrings (instanceName:
79 | let
80 | instance = builtins.getAttr instanceName processes;
81 | in
82 | tests ({ inherit instanceName instance processManager; } // processManagerSettings.params)
83 | ) (builtins.attrNames processes))
84 |
85 | + pkgs.lib.optionalString (postTests != null) (postTests (processManagerSettings.params // { inherit processes; }));
86 | };
87 | in
88 | { name
89 | , processManagers
90 | , profiles
91 | , exprFile
92 | , extraParams ? {}
93 | , nixosConfig ? null
94 | , systemPackages ? []
95 | , initialTests ? null
96 | , readiness ? null
97 | , tests ? null
98 | , postTests ? null
99 | }:
100 |
101 | pkgs.lib.genAttrs profiles (profile:
102 | let
103 | profileSettingsModule = builtins.getAttr profile profileSettingModules;
104 | profileSettings = import profileSettingsModule;
105 | in
106 | pkgs.lib.genAttrs processManagers (processManager:
107 | testSystemVariantForProcessManager {
108 | inherit name processManager profileSettings exprFile extraParams nixosConfig systemPackages initialTests readiness tests postTests;
109 | }
110 | )
111 | )
112 |
--------------------------------------------------------------------------------