summaryrefslogtreecommitdiffstats
path: root/krebs/3modules/on-failure.nix
blob: 54c1eca1076e114295cf77e46ee0327480c6bc87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
{ config, lib, pkgs, ... }: with lib; let
  out = {
    options.krebs.on-failure = api;
    config = lib.mkIf cfg.enable imp;
  };

  cfg = config.krebs.on-failure;

  api = {
    enable = mkEnableOption "krebs.on-failure" // {
      default = cfg.plans != {};
    };
    plans = mkOption {
      default = {};
      type = let
        inherit (config) krebs;
      in types.attrsOf (types.submodule ({ config, ... }: {
        options = {
          enable = mkEnableOption "krebs.on-failure.${config.name}" // {
            default = true;
          };
          journalctl = {
            lines = mkOption {
              type = types.int;
              default = 100;
            };
            output = mkOption {
              type = types.enum [
                "cat"
                "export"
                "json"
                "json-pretty"
                "json-sse"
                "short"
                "short-iso"
                "short-precise"
                "verbose"
              ];
              default = "short-iso";
            };
          };
          mailto = mkOption {
            type = types.str;
            default = krebs.build.user.mail;
            description = "Mail address to send journal extract to.";
          };
          subject = mkOption {
            type = types.str;
            default = "[${krebs.build.host.name}] ${config.name} has failed";
          };
          name = mkOption {
            type = types.str;
            default = config._module.args.name;
            description = "Name of the to-be-monitored service.";
          };
        };
      }));
    };
    sendmail = mkOption {
      type = types.str;
      default = "/run/wrappers/bin/sendmail";
    };
  };

  imp = {
    systemd.services = foldl (a: b: a // b) {} (map to-services enabled-plans);
  };

  enabled-plans = filter (getAttr "enable") (attrValues cfg.plans);

  to-services = plan: {
    "${plan.name}".unitConfig.OnFailure = "on-failure.${plan.name}.service";
    "on-failure.${plan.name}".serviceConfig = rec {
      ExecStart = start plan;
      SyslogIdentifier = ExecStart.name;
      Type = "oneshot";
    };
  };

  start = plan: pkgs.writeDash "on-failure.${plan.name}" ''
    { echo Subject: ${shell.escape plan.subject}
      echo To: ${shell.escape plan.mailto}
      echo
      ${pkgs.systemd}/bin/journalctl \
          --lines=${toString plan.journalctl.lines} \
          --output=${plan.journalctl.output} \
          --since="$(
            ${pkgs.coreutils}/bin/date +'%F %T UTC' -ud "$(
              ${pkgs.systemd}/bin/systemctl show \
                  -p ExecMainStartTimestamp \
                  ${shell.escape plan.name} \
                | ${pkgs.coreutils}/bin/cut -d= -f2-
            )"
          )" \
          --unit=${shell.escape plan.name}.service
    } | ${shell.escape cfg.sendmail} -t
  '';

in out