liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

default.nix (9968B)


      1 {
      2   config,
      3   pkgs,
      4   lib,
      5   lim,
      6   ...
      7 }:
      8 let
      9   inherit (pkgs)
     10     execline
     11     s6
     12     s6-init-bin
     13     s6-linux-init
     14     stdenvNoCC
     15     ;
     16   inherit (lib.lists) unique concatMap;
     17   inherit (lib) concatStrings;
     18   inherit (builtins) map;
     19   inherit (pkgs.pseudofile) dir symlink;
     20   inherit (pkgs.liminix.services) oneshot bundle longrun;
     21   inherit (lib)
     22     mkIf
     23     mkEnableOption
     24     mkOption
     25     types
     26     ;
     27   cfg = config.logging;
     28   # don't put this in /run/log because logtap tries to create it
     29   # before s6-log makes the directory
     30   fifo = "/run/.log-fifo";
     31   fifoBackfill = "/run/.log-fifo-backfill";
     32 
     33   logger =
     34     let
     35       pipecmds = [
     36         "${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1"
     37       ]
     38       ++ (lib.optional (cfg ? persistent && cfg.persistent.enable) "/bin/tee /dev/pmsg0")
     39       ++ (lib.optional cfg.shipping.enable "${pkgs.logtap}/bin/logtap ${fifo} logshipper-socket-event");
     40     in
     41     ''
     42       #!${execline}/bin/execlineb -P
     43       ${execline}/bin/redirfd -w 1 /dev/null
     44       ${execline}/bin/redirfd -rnb 0 fifo
     45       ${concatStrings (map (l: "pipeline { ${l} }\n") pipecmds)}
     46       ${s6}/bin/s6-log -- ${cfg.directory}
     47     '';
     48   s6-rc-db =
     49     let
     50       # In the default bundle we need to have all the services
     51       # in config.services except for controlled services and
     52       # anything that depends on one. But we do need the controllers
     53       # themselves.
     54 
     55       # So, find all required services and their transitive
     56       # dependencies and their controllers. remove all controlled
     57       # services and all services that have a controlled service as
     58       # dependency
     59 
     60       isControlled = s: s ? controller && s.controller != null;
     61       deps = s: s.dependencies ++ lib.optional (isControlled s) s.controller;
     62       flatDeps = s: [ s ] ++ concatMap flatDeps (deps s);
     63       allServices = unique (concatMap flatDeps (builtins.attrValues config.services));
     64       isDependentOnControlled =
     65         let
     66           inherit (lib.lists) any;
     67         in
     68         s:
     69         isControlled s
     70         || (any isDependentOnControlled s.dependencies)
     71         || ((s ? contents) && (any isDependentOnControlled s.contents));
     72 
     73       # all controlled services depend on this oneshot, which
     74       # makes a list of them so we can identify them at runtime
     75       controlled = oneshot {
     76         name = "controlled";
     77         up = ''
     78           mkdir -p /run/services/controlled
     79           for s in $(s6-rc-db -d dependencies controlled); do
     80             touch /run/services/controlled/$s
     81           done
     82         '';
     83         down = "rm -r /run/services/controlled";
     84       };
     85 
     86       defaultStart = builtins.filter (s: !(isDependentOnControlled s)) allServices;
     87       defaultDefaultTarget = bundle {
     88         name = "default";
     89         contents = defaultStart ++ [ controlled ];
     90       };
     91       servicesAttrs = {
     92         default = defaultDefaultTarget;
     93       }
     94       // config.services;
     95     in
     96     pkgs.s6-rc-database.override {
     97       services = builtins.attrValues servicesAttrs;
     98     };
     99   s6-init-scripts = stdenvNoCC.mkDerivation {
    100     name = "s6-scripts";
    101     src = ./scripts;
    102     phases = [
    103       "unpackPhase"
    104       "installPhase"
    105     ];
    106     buildInputs = [ ];
    107     installPhase = ''
    108       mkdir $out
    109       cp -r $src $out/scripts
    110       chmod -R +w $out
    111     '';
    112   };
    113   service = dir {
    114     s6-linux-init-runleveld = dir {
    115       notification-fd = {
    116         file = "3";
    117       };
    118       run = {
    119         file = ''
    120           #!${execline}/bin/execlineb -P
    121           ${execline}/bin/fdmove -c 2 1
    122           ${execline}/bin/fdmove 1 3
    123           ${s6}/bin/s6-ipcserver -1 -a 0700 -c 1 -- s
    124           ${s6}/bin/s6-sudod -dt30000 -- "/etc/s6-linux-init/current"/scripts/runlevel
    125         '';
    126         mode = "0755";
    127       };
    128     };
    129     s6-linux-init-shutdownd = dir {
    130       fifo = {
    131         type = "i";
    132         mode = "0600";
    133       };
    134       run = {
    135         file = ''
    136           #!${execline}/bin/execlineb -P
    137           importas PATH PATH
    138           export PATH ${s6}/bin:''${PATH}
    139           foreground { echo path is  ''${PATH} }
    140           ${s6-linux-init}/bin/s6-linux-init-shutdownd -c  "/etc/s6-linux-init/current" -g 3000
    141         '';
    142         mode = "0755";
    143       };
    144     };
    145     s6-svscan-log = dir {
    146       fifo = {
    147         type = "i";
    148         mode = "0600";
    149       };
    150       notification-fd = {
    151         file = "3";
    152       };
    153       run = {
    154         file = logger;
    155         mode = "0755";
    156       };
    157     };
    158     getty = dir {
    159       run = {
    160         # We can't run a useful shell on /dev/console because
    161         # /dev/console is not allowed to be the controlling
    162         # tty of any process, which means ^C ^Z etc don't work.
    163         # So we work out what the *actual* console device is
    164         # using sysfs and open our shell there instead.
    165         file = ''
    166           #!${execline}/bin/execlineb -P
    167           ${execline}/bin/cd /
    168           redirfd -r 0 /sys/devices/virtual/tty/console/active
    169           withstdinas CONSOLETTY
    170           importas CONSOLETTY CONSOLETTY
    171           redirfd -w 2 /dev/''${CONSOLETTY}
    172           fdmove -c 1 2
    173           redirfd -r 0 /dev/''${CONSOLETTY}
    174           /bin/ash -l
    175         '';
    176         mode = "0755";
    177       };
    178       down-signal = {
    179         file = "HUP\n";
    180       };
    181     };
    182     ".s6-svscan" =
    183       let
    184         openConsole = ''
    185           #!${execline}/bin/execlineb -P
    186           ${execline}/bin/redirfd -w 2 /dev/console
    187           ${execline}/bin/fdmove -c 1 2
    188         '';
    189         quit = message: ''
    190           ${openConsole}
    191           ${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
    192           ${s6-linux-init}/bin/s6-linux-init-hpr -fr
    193         '';
    194         shutdown = action: ''
    195           #!${execline}/bin/execlineb -P
    196           ${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now
    197         '';
    198         empty = "#!${execline}/bin/execlineb -P\n";
    199       in
    200       dir {
    201         crash = {
    202           file = quit "s6-svscan crashed. Rebooting.";
    203           mode = "0755";
    204         };
    205         finish = {
    206           file = ''
    207             ${openConsole}
    208             ifelse { test -x /run/maintenance/exec } { /run/maintenance/exec }
    209             foreground { echo "s6-svscan exited. Rebooting." }
    210             wait { }
    211             ${s6-linux-init}/bin/s6-linux-init-hpr -fr
    212           '';
    213           mode = "0755";
    214         };
    215         SIGINT = {
    216           file = shutdown "-r";
    217           mode = "0755";
    218         };
    219         SIGPWR = {
    220           file = shutdown "-p";
    221           mode = "0755";
    222         };
    223         SIGQUIT = {
    224           file = empty;
    225           mode = "0755";
    226         };
    227         SIGTERM = {
    228           file = empty;
    229           mode = "0755";
    230         };
    231         SIGUSR1 = {
    232           file = shutdown "-p";
    233           mode = "0755";
    234         };
    235         SIGUSR2 = {
    236           file = shutdown "-h";
    237           mode = "0755";
    238         };
    239         SIGWINCH = {
    240           file = empty;
    241           mode = "0755";
    242         };
    243 
    244       };
    245   };
    246 in
    247 {
    248   options = {
    249     logging = {
    250       shipping = {
    251         enable = mkEnableOption "fifo for log shipping";
    252         command = mkOption {
    253           description = "log shipping command, should accept one parameter which is the file name to read";
    254           type = types.pathInStore;
    255           example = lib.literalExpression ''
    256             writeAshScript "shipper" {} \'\'
    257             ''${pkgs.s6-networking}/bin/s6-tcpclient loghost 9428 ''${pkgs.logshippers}/bin/victorialogsend http://loghost:9428/insert/jsonline
    258             \'\'
    259           '';
    260         };
    261         dependencies = mkOption {
    262           description = "services required by the shipping script";
    263           type = types.listOf pkgs.liminix.lib.types.service;
    264           default = [ ];
    265         };
    266       };
    267       script = mkOption {
    268         description = "\"log script\" used by fallback s6-log process";
    269         type = types.str;
    270         default = "p${config.hostname} t";
    271       };
    272       directory = mkOption {
    273         description = "default log directory";
    274         default = "/run/log";
    275         type = types.path;
    276       };
    277     };
    278   };
    279 
    280   config = {
    281     programs.busybox.applets = mkIf config.logging.shipping.enable [ "mkfifo" ];
    282     services.log-shipper =
    283       let
    284         cfg = config.logging.shipping;
    285         dependencies = config.logging.shipping.dependencies;
    286       in
    287       mkIf cfg.enable (
    288         let
    289           live = longrun {
    290             name = "log-shipper-live";
    291             run = "${cfg.command} ${fifo}";
    292             inherit dependencies;
    293           };
    294           source = longrun {
    295             name = "log-shipper-backfill-source";
    296             # if backfill dies we want the service manager to retry
    297             # it (assuming that its dependencies are still healthy).
    298             # But if it reaches the end of logs to backfill, we want
    299             # it to rest quietly not to exit
    300             run = ''
    301               test -p ${fifoBackfill} || mkfifo ${fifoBackfill}
    302               (cat ${config.logging.directory}/*; sleep 86400) | ${pkgs.logtap}/bin/backfill ${fifoBackfill} ${fifoBackfill}.ts
    303             '';
    304             dependencies = dependencies ++ [ live ];
    305           };
    306           sink = longrun {
    307             name = "log-shipper-backfill-sink";
    308             run = "${cfg.command} ${fifoBackfill}";
    309             dependencies = dependencies ++ [ source ];
    310           };
    311         in
    312         bundle {
    313           name = "log-shipper";
    314           contents = [
    315             live
    316             source
    317             sink
    318           ];
    319         }
    320       );
    321 
    322     filesystem = dir {
    323       etc = dir {
    324         s6-rc = dir {
    325           compiled = symlink "${s6-rc-db}/compiled";
    326         };
    327         s6-linux-init = dir {
    328           current = dir {
    329             scripts = symlink "${s6-init-scripts}/scripts";
    330             env = dir { };
    331             run-image = dir {
    332               uncaught-logs = (dir { }) // {
    333                 mode = "2750";
    334               };
    335               inherit service;
    336             };
    337           };
    338         };
    339       };
    340       bin = dir {
    341         init = symlink "${s6-init-bin}/bin/init";
    342       };
    343     };
    344   };
    345 }