liminix

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

default.nix (8910B)


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