summary refs log tree commit diff
path: root/nixos/modules/system/boot/s6.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/system/boot/s6.nix')
-rw-r--r--nixos/modules/system/boot/s6.nix256
1 files changed, 256 insertions, 0 deletions
diff --git a/nixos/modules/system/boot/s6.nix b/nixos/modules/system/boot/s6.nix
new file mode 100644
index 000000000000..23ccd0f0c8b6
--- /dev/null
+++ b/nixos/modules/system/boot/s6.nix
@@ -0,0 +1,256 @@
+{ pkgs, lib, config, ... }:
+
+let
+  inherit (builtins) typeOf;
+  inherit (pkgs) linkFarm writeScript runCommand;
+  inherit (lib) concatStringsSep mapAttrsToList mkOption mkDefault types filterAttrsRecursive foldr;
+
+  s6EntryTypes = {
+    int = v: s6Entry (toString v);
+    bool = v: s6Entry "";
+    string = writeScript "s6-file";
+    set = v: linkFarm "s6-dir"
+      (mapAttrsToList (name: value: { inherit name; path = s6Entry value; }) v);
+    list = v: s6Entry (concatStringsSep "\n" v);
+  };
+
+  s6Entry = v: s6EntryTypes.${typeOf v} v;
+
+  s6RcCompile = { uids ? null, gids ? null, fdhuser ? null }: source: 
+    runCommand "s6-rc-compile" {} ''
+      ${config.s6.rc.package}/bin/s6-rc-compile \
+          ${if (uids != null) then "-u ${concatStringsSep "," uids}" else ""} \
+          ${if (gids != null) then "-g ${concatStringsSep "," gids}" else ""} \
+          ${if (fdhuser != null) then "-h ${fdhuser}" else ""} \
+          $out \
+          ${lib.traceVal (toString (s6Entry (filterAttrsRecursive (n: v: v != null) source)))}
+    '';
+
+in {
+  options = {
+    s6.rc.package = mkOption {
+      default = pkgs.s6-rc;
+      description = ''
+        The package to look for the s6-rc, s6-rc-compile, and s6-rc-init
+        commands in.
+      '';
+    };
+
+    s6.rc.initTimeout = mkOption {
+      default = null;
+      description = ''
+        Milliseconds to wait for all s6-supervise processes to start up before
+        giving up.
+      '';
+    };
+
+    s6.rc.timeout = mkOption {
+      default = null;
+      description = ''
+        Milliseconds to wait for s6-rc to transition to the up state.
+      '';
+    };
+
+    s6.rc.services = mkOption {
+      description = ''
+        Attribute set of available services. Names correspond to service
+        directory names on disk. Values are attribute sets of service
+        properties, which are then transformed into the directory structure
+        expected by s6-rc-compile.
+      '';
+      example = {
+        foo = { 
+          type = "oneshot"; 
+          up = "echo hello world"; 
+          dependencies = [ "bar" "baz" ]; 
+          env = { a = "b"; };
+        };
+      };
+
+      type = with types; attrsOf
+        (submodule {
+          options = {
+            type = mkOption {
+              description = "type";
+              type = enum [ "bundle" "oneshot" "longrun" ];
+            };
+            contents = mkOption {
+              description = "contents";
+              type = nullOr (listOf str);
+              default = null;
+            };
+            timeout-up = mkOption {
+              description = "timeout-up";
+              type = nullOr ints.unsigned;
+              default = null;
+            };
+            timeout-down = mkOption {
+              description = "timeout-down";
+              type = nullOr ints.unsigned;
+              default = null;
+            };
+            dependencies = mkOption {
+              description = "dependencies";
+              type = nullOr (listOf str);
+              default = null;
+            };
+            up = mkOption {
+              description = "up";
+              type = nullOr str;
+              default = null;
+            };
+            down = mkOption {
+              description = "down";
+              type = nullOr str;
+              default = null;
+            };
+            run = mkOption {
+              description = "run";
+              type = nullOr str;
+              default = null;
+            };
+            finish = mkOption {
+              description = "finish";
+              type = nullOr str;
+              default = null;
+            };
+            notification-fd = mkOption {
+              description = "notification-fd";
+              type = nullOr ints.unsigned;
+              default = null;
+            };
+            timeout-kill = mkOption {
+              description = "timeout-kill";
+              type = nullOr ints.unsigned;
+              default = null;
+            };
+            timeout-finish = mkOption {
+              description = "timeout-finish";
+              type = nullOr ints.unsigned;
+              default = null;
+            };
+            nosetsid = mkOption {
+              description = "nosetsid";
+              type = nullOr bool;
+              default = null;
+            };
+            data = mkOption {
+              description = "data";
+              type = nullOr (attrsOf str);
+              default = null;
+            };
+            env = mkOption {
+              description = "env";
+              type = nullOr (attrsOf str);
+              default = null;
+            };
+            producer-for = mkOption {
+              description = "producer-for";
+              type = nullOr str;
+              default = null;
+            };
+            consumer-for = mkOption { 
+              description = "consumer-for";
+              type = nullOr (listOf str);
+              default = null;
+            };
+            pipeline-name = mkOption { 
+              description = "pipeline-name";
+              type = nullOr str;
+              default = null;
+            };
+          };
+        });
+    };
+
+    s6.rc.live = mkOption {
+      default = "/run/s6-rc";
+      description = ''
+        Where to store the s6-rc live state.
+      '';
+    };
+
+    s6.rc.prefix = mkOption {
+      default = "";
+      description = ''
+        Unique prefix to apply to all service names when they are added to the
+        supervisor, for disambiguation.
+      '';
+    };
+
+    s6.rc.uids = mkOption {
+      default = null;
+      description = ''
+        IDs of users who should be allowed to start and stop services controlled
+        by this instance of s6-rc. Default: only root.
+      '';
+    };
+
+    s6.rc.gids = mkOption {
+      default = null;
+      description = ''
+        IDs of groups who should be allowed to start and stop services controlled
+        by this instance of s6-rc. Default: only root.
+      '';
+    };
+
+    s6.rc.fdhuser = mkOption {
+      default = null;
+      description = ''
+        User for the s6-fileholder-daemon process to run as. Defaults to root,
+        the owner of the supervision tree.
+      '';
+    };
+
+    s6.rc.initBundle = mkOption {
+      default = "ok-all";
+      description = ''
+        Name of the top bundle to be brought up at system startup.
+      '';
+    };
+
+    s6.rc.initCommand = mkOption {
+      description = ''
+        The s6-rc-init command line to be executed by rc.init, prior to running
+        s6-rc.
+      '';
+    };
+
+    s6.rc.command = mkOption {
+      description = ''
+        The s6-rc command line to be executed by rc.init, after running
+        s6-rc-init.
+      '';
+    };
+  };
+
+  config = {
+    s6.rc.services.${config.s6.rc.initBundle} = {
+      type = "bundle";
+      contents = [];
+    };
+
+    s6.rc.initCommand = mkDefault ''
+      ${config.s6.rc.package}/bin/s6-rc-init \
+          -c ${s6RcCompile
+                { inherit (config.s6.rc) uids gids fdhuser; }
+                config.s6.rc.services} \
+          -l ${config.s6.rc.live} \
+          -p "${config.s6.rc.prefix}" \
+          ${if (config.s6.rc.initTimeout != null)
+            then "-t ${toString config.s6.rc.initTimeout}"
+            else ""} \
+          /run/service
+    '';
+
+    s6.rc.command = mkDefault ''
+      ${config.s6.rc.package}/bin/s6-rc \
+          -l ${config.s6.rc.live} \
+          change \
+          ${if (config.s6.rc.timeout != null)
+            then "-t ${toString config.s6.rc.timeout}"
+            else ""} \
+          ${config.s6.rc.initBundle}
+    '';
+  };
+}