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 }