summary refs log tree commit diff
path: root/module.nix
diff options
context:
space:
mode:
authorMalte Voos <malte@malvo.org>2022-05-13 13:21:18 +0200
committerMalte Voos <malte@malvo.org>2022-05-13 13:21:18 +0200
commitc93eae7878325927cd11489de40be35c907c84ca (patch)
treedb9cd2aafa76c219b827283178e3211f7b54c319 /module.nix
parent785f9e04b123b8fd3b5a6fd0901f4ac5177fd752 (diff)
downloads6-rc.nix-c93eae7878325927cd11489de40be35c907c84ca.tar.gz
s6-rc.nix-c93eae7878325927cd11489de40be35c907c84ca.zip
nixos module for non-nixos systems (s6-rc config only)
Diffstat (limited to 'module.nix')
-rw-r--r--module.nix308
1 files changed, 115 insertions, 193 deletions
diff --git a/module.nix b/module.nix
index bd607c8..928f9d7 100644
--- a/module.nix
+++ b/module.nix
@@ -1,33 +1,31 @@
-{ config, lib, pkgs, ... }:
-with lib;
+{ config, pkgs, lib, ... }:
+with pkgs.lib;
 let
   writeExeclineScript = name: text: pkgs.writeScript name ''
     #!${pkgs.execline}/bin/execlineb -P
     ${text}
   '';
 
-  cfg = config.s6;
+  cfg = config;
 
-  # -------- configuration for s6-rc -------- #
+  logNames = flatten (mapAttrsToList (_: sv: optional (sv.log != null) sv.log) cfg.longruns);
 
-  loggerNames = flatten (mapAttrsToList (_: srv: optional (srv.logger != null) srv.logger) cfg.longruns);
-
-  loggingRelations = genAttrs loggerNames
-    (loggerName: filter
-      (serviceName: cfg.longruns.${serviceName}.logger == loggerName)
+  loggingRelations = genAttrs logNames
+    (logName: filter
+      (serviceName: cfg.longruns.${serviceName}.log == logName)
       (attrNames cfg.longruns));
 
-  loggerLongruns = mapAttrs'
-    (loggerName: producers:
-      nameValuePair "${loggerName}-log" {
+  logLongruns = mapAttrs'
+    (logName: producers:
+      nameValuePair "${logName}-log" {
         run = ''
-          s6-setuidgid ${cfg.logUser}
-          exec -c
-          s6-log -d 3 -- ${cfg.loggingScript loggerName}
+          ${pkgs.s6}/bin/s6-setuidgid "${cfg.logUser}"
+          ${pkgs.execline}/bin/exec -c
+          ${pkgs.s6}/bin/s6-log -d 3 -- ${cfg.loggingScript logName}
         '';
         notificationFd = 3;
         consumerFor = producers;
-        pipelineName = "${loggerName}-pipeline";
+        pipelineName = "${logName}-pipeline";
         flagEssential = false;
         timeoutUp = null;
         timeoutDown = null;
@@ -38,92 +36,92 @@ let
         maxDeathTally = null;
         downSignal = null;
         producerFor = null;
-        logger = null;
+        log = null;
       })
     loggingRelations;
 
-  allLongruns = cfg.longruns // loggerLongruns;
+  allLongruns = cfg.longruns // logLongruns;
 
-  makeCommonConfig = srv: ''
+  makeCommonConfig = sv: ''
     mkdir -p $out
-  '' + optionalString srv.flagEssential ''
+  '' + optionalString sv.flagEssential ''
     touch $out/flagEssential
   '';
 
-  makeBundleConfig = srv: makeCommonConfig srv + ''
+  makeBundleConfig = sv: makeCommonConfig sv + ''
     echo bundle > $out/type
     mkdir $out/contents.d
   '' + concatMapStringsSep "\n"
-    (srvName: ''touch "$out/contents.d/${srvName}"'')
-    srv.contents + "\n";
-
-  makeAtomicConfig = srv: makeCommonConfig srv
-    + optionalString (srv.timeoutUp != null) ''
-    echo "${toString srv.timeoutUp}" > $out/timeout-up
-  '' + optionalString (srv.timeoutDown != null) ''
-    echo "${toString srv.timeoutDown}" > $out/timeout-down
-  '' + optionalString (srv.dependencies != null) (
+    (svName: ''touch "$out/contents.d/${svName}"'')
+    sv.contents + "\n";
+
+  makeAtomicConfig = sv: makeCommonConfig sv
+    + optionalString (sv.timeoutUp != null) ''
+    echo "${toString sv.timeoutUp}" > $out/timeout-up
+  '' + optionalString (sv.timeoutDown != null) ''
+    echo "${toString sv.timeoutDown}" > $out/timeout-down
+  '' + optionalString (sv.dependencies != null) (
     ''
       mkdir $out/dependencies.d
     '' + concatMapStringsSep "\n"
-      (srvName: ''touch "$out/dependencies.d/${srvName}"'')
-      srv.dependencies + "\n"
+      (svName: ''touch "$out/dependencies.d/${svName}"'')
+      sv.dependencies + "\n"
   );
 
-  makeOneshotConfig = srv:
+  makeOneshotConfig = sv:
     let
-      upScript = pkgs.writeText "up-script" srv.up;
-      downScript = mapNullable (pkgs.writeText "down-script") srv.down;
+      upScript = pkgs.writeText "up-script" sv.up;
+      downScript = mapNullable (pkgs.writeText "down-script") sv.down;
     in
-    makeAtomicConfig srv + ''
+    makeAtomicConfig sv + ''
       echo oneshot > $out/type
       cp ${upScript} $out/up
     '' + optionalString (downScript != null) ''
       cp ${downScript} $out/down
     '';
 
-  makeLongrunConfig = srv:
+  makeLongrunConfig = sv:
     let
-      runScript = writeExeclineScript "run-script" srv.run;
-      finishScript = mapNullable (writeExeclineScript "finish-script") srv.finish;
+      runScript = writeExeclineScript "run-script" sv.run;
+      finishScript = mapNullable (writeExeclineScript "finish-script") sv.finish;
     in
-    makeAtomicConfig srv + ''
+    makeAtomicConfig sv + ''
       echo longrun > $out/type
       cp ${runScript} $out/run
     '' + optionalString (finishScript != null) ''
       cp ${finishScript} $out/finish
-    '' + optionalString (srv.notificationFd != null) ''
-      echo "${toString srv.notificationFd}" > $out/notification-fd
-    '' + optionalString (srv.timeoutKill != null) ''
-      echo "${toString srv.timeoutKill}" > $out/timeout-kill
-    '' + optionalString (srv.timeoutFinish != null) ''
-      echo "${toString srv.timeoutFinish}" > $out/timeout-finish
-    '' + optionalString (srv.maxDeathTally != null) ''
-      echo "${toString srv.maxDeathTally}" > $out/max-death-tally
-    '' + optionalString (srv.downSignal != null) ''
-      echo "${srv.downSignal}" > $out/down-signal
-    '' + optionalString (srv.producerFor != null) ''
-      echo "${srv.producerFor}" > $out/producer-for
-    '' + optionalString (srv.consumerFor != null) ''
-      echo "${concatStringsSep "\n" srv.consumerFor}" > $out/consumer-for
-    '' + optionalString (srv.pipelineName != null) ''
-      echo "${srv.pipelineName}" > $out/pipeline-name
-    '' + optionalString (srv.logger != null) ''
-      echo "${srv.logger}-log" > $out/producer-for
+    '' + optionalString (sv.notificationFd != null) ''
+      echo "${toString sv.notificationFd}" > $out/notification-fd
+    '' + optionalString (sv.timeoutKill != null) ''
+      echo "${toString sv.timeoutKill}" > $out/timeout-kill
+    '' + optionalString (sv.timeoutFinish != null) ''
+      echo "${toString sv.timeoutFinish}" > $out/timeout-finish
+    '' + optionalString (sv.maxDeathTally != null) ''
+      echo "${toString sv.maxDeathTally}" > $out/max-death-tally
+    '' + optionalString (sv.downSignal != null) ''
+      echo "${sv.downSignal}" > $out/down-signal
+    '' + optionalString (sv.producerFor != null) ''
+      echo "${sv.producerFor}" > $out/producer-for
+    '' + optionalString (sv.consumerFor != null) ''
+      echo "${concatStringsSep "\n" sv.consumerFor}" > $out/consumer-for
+    '' + optionalString (sv.pipelineName != null) ''
+      echo "${sv.pipelineName}" > $out/pipeline-name
+    '' + optionalString (sv.log != null) ''
+      echo "${sv.log}-log" > $out/producer-for
     '';
 
-  makeBundleDefinitionDir = name: srv: pkgs.runCommand
+  makeBundleDefinitionDir = name: sv: pkgs.runCommand
     "s6-rc-bundle-definition-${name}"
     { }
-    (makeBundleConfig srv);
-  makeOneshotDefinitionDir = name: srv: pkgs.runCommand
+    (makeBundleConfig sv);
+  makeOneshotDefinitionDir = name: sv: pkgs.runCommand
     "s6-rc-oneshot-definition-${name}"
     { }
-    (makeOneshotConfig srv);
-  makeLongrunDefinitionDir = name: srv: pkgs.runCommand
+    (makeOneshotConfig sv);
+  makeLongrunDefinitionDir = name: sv: pkgs.runCommand
     "s6-rc-longrun-definition-${name}"
     { }
-    (makeLongrunConfig srv);
+    (makeLongrunConfig sv);
 
   bundleDefinitionDirs = mapAttrs makeBundleDefinitionDir cfg.bundles;
   oneshotDefinitionDirs = mapAttrs makeOneshotDefinitionDir cfg.oneshots;
@@ -133,69 +131,12 @@ let
 
   serviceSourceDir = pkgs.linkFarm "s6-rc-service-source"
     (mapAttrsToList
-      (srvName: definitionDir: { name = srvName; path = definitionDir; })
+      (svName: definitionDir: { name = svName; path = definitionDir; })
       allDefinitionDirs);
 
   compiledDatabase = pkgs.runCommand "s6-rc-compiled-database" { } ''
     ${pkgs.s6-rc}/bin/s6-rc-compile $out ${serviceSourceDir}
   '';
-
-  # -------- init script -------- #
-
-  initialPath = lib.makeBinPath (with pkgs; [
-    coreutils
-    execline
-    s6
-    s6-rc
-  ]);
-
-  catchAllLoggerServiceDir =
-    let
-      runScript = writeExeclineScript "catch-all-logger-run-script" ''
-        s6-setuidgid "${cfg.logUser}"
-        redirfd -w 1 /dev/null
-        redirfd -rnb 0 "${cfg.logFifo}"
-        s6-log -bpd3 -- ${cfg.loggingScript "uncaught"}
-      '';
-    in
-    pkgs.runCommand "catch-all-logger-srvdir" { } ''
-      mkdir -p $out
-      cp ${runScript} $out/run
-      echo 3 > $out/notification-fd
-    '';
-
-  # this runs after NixOS' stage-2-init.sh
-  initScript = writeExeclineScript "init-script" ''
-    ${pkgs.execline}/bin/export PATH "${initialPath}"
-    ${pkgs.execline}/bin/exec
-
-    # stage-2-init.sh prints the line "starting systemd..."
-    foreground { echo "...NOT! starting s6-svscan on ${cfg.scanDir}..." }
-
-    if { mkdir -p "${cfg.scanDir}" }
-    if { cp -r "${catchAllLoggerServiceDir}" "${cfg.scanDir}/catch-all-log" }
-
-    if { mkdir -p "${cfg.logDir}" }
-    if { chown "${cfg.logUser}:${cfg.logGroup}" "${cfg.logDir}" }
-    if { chmod 700 "${cfg.logDir}" }
-
-    if { mkfifo "${cfg.logFifo}" }
-    if { chown "${cfg.logUser}:${cfg.logGroup}" "${cfg.logFifo}" }
-    if { chmod 600 "${cfg.logFifo}" }
-
-    redirfd -r 0 /dev/null             # don't use /dev/console as stdin
-    redirfd -wnb 1 "${cfg.logFifo}"    # redirect stdout to fifo
-    fdmove -c 2 1                      # redirect stderr to fifo
-
-    background {
-      redirfd -w 3 "${cfg.logFifo}"    # this blocks until the catch-all logger is running
-      if { s6-rc-init -c "${compiledDatabase}" "${cfg.scanDir}" }
-      s6-rc -v2 change "${cfg.allBundle}"
-    }
-
-    exec -a s6-svscan                  # name it 's6-svscan' instead of /nix/store/...
-    s6-svscan "${cfg.scanDir}"
-  '';
 in
 {
   options = with types;
@@ -271,101 +212,82 @@ in
           type = str;
         };
         # this is not an actual option in s6-rc; it creates a logger service
-        # with the name "<logger>-log" and adds the necessary "producer-for"
-        # and "consumer-for" files.
-        logger = mkNullableOption {
+        # named "<log>-log" and adds the necessary "producer-for" and
+        # "consumer-for" files.
+        log = mkNullableOption {
           type = str;
         };
       } // atomicOptions;
     in
     {
-      s6 = {
-        enable = mkEnableOption "s6 init system";
-        allBundle = mkOption {
-          type = str;
-        };
-        logUser = mkOption {
-          type = str;
-          default = "log";
-        };
-        logGroup = mkOption {
-          type = str;
-          default = "log";
-        };
-        logDir = mkOption {
-          type = path;
-          default = "/log";
-        };
-        logFifo = mkOption {
-          type = path;
-          default = "/run/log-fifo";
-        };
-        loggingScript = mkOption {
-          type = anything;
-          default = name: "T s1000000 n20 ${cfg.logDir}/${name}";
-        };
-        scanDir = mkOption {
-          type = path;
-          default = "/run/service";
-        };
+      logUser = mkOption {
+        type = str;
+        default = "log";
+      };
 
-        bundles = mkOption {
-          type = with types; attrsOf (submodule {
-            options = bundleOptions;
-          });
-        };
+      logGroup = mkOption {
+        type = str;
+        default = "log";
+      };
 
-        oneshots = mkOption {
-          type = with types; attrsOf (submodule {
-            options = oneshotOptions;
-          });
-          default = { };
-        };
+      logDir = mkOption {
+        type = path;
+        default = "/log";
+      };
 
-        longruns = mkOption {
-          type = with types; attrsOf (submodule {
-            options = longrunOptions;
-          });
-          default = { };
-        };
+      loggingScript = mkOption {
+        type = anything;
+        default = name: "T s1000000 n20 ${cfg.logDir}/${name}";
+      };
+
+      bundles = mkOption {
+        type = with types; attrsOf (submodule {
+          options = bundleOptions;
+        });
+      };
+
+      oneshots = mkOption {
+        type = with types; attrsOf (submodule {
+          options = oneshotOptions;
+        });
+        default = { };
+      };
+
+      longruns = mkOption {
+        type = with types; attrsOf (submodule {
+          options = longrunOptions;
+        });
+        default = { };
+      };
+
+      # ---- output ---- #
+
+      serviceSourceDir = mkOption {
+        type = types.raw;
+      };
+
+      compiledDatabase = mkOption {
+        type = types.raw;
       };
     };
 
   config = lib.mkIf cfg.enable {
     assertions = [
       {
-        assertion = hasAttr cfg.allBundle cfg.bundles;
-        message = "the bundle '${cfg.allBundle}' does not exist!";
-      }
-      {
-        assertion = !(elem "uncaught" loggerNames);
-        message = "the logger name 'uncaught' is reserved";
-      }
-      {
         assertion = length (attrNames allDefinitionDirs)
           == length (attrNames cfg.bundles)
           + length (attrNames cfg.oneshots)
           + length (attrNames cfg.longruns)
-          + length (attrNames loggerLongruns);
+          + length (attrNames logLongruns);
         message = "no two services can have the same name, even if they are of different types";
       }
     ] ++ mapAttrsToList
       (name: def: {
-        assertion = def.producerFor == null || def.logger == null;
-        message = "in s6.longruns.${name}: 'producerFor' and 'logger' are mutually exclusive";
+        assertion = def.producerFor == null || def.log == null;
+        message = "in `longruns.${name}`: `producerFor` and `log` are mutually exclusive";
       })
       cfg.longruns;
 
-    users = {
-      users.${cfg.logUser} = {
-        isSystemUser = true;
-        group = cfg.logGroup;
-        home = cfg.logDir;
-      };
-      groups.${cfg.logGroup} = { };
-    };
-
-    # checkmate!
-    boot.systemdExecutable = "${initScript}";
+    inherit serviceSourceDir compiledDatabase;
   };
 }