1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7let
8 cfg = config.services.kthxbye;
9in
10
11{
12 options.services.kthxbye = {
13 enable = lib.mkEnableOption "kthxbye alert acknowledgement management daemon";
14
15 package = lib.mkPackageOption pkgs "kthxbye" { };
16
17 openFirewall = lib.mkOption {
18 type = lib.types.bool;
19 default = false;
20 description = ''
21 Whether to open ports in the firewall needed for the daemon to function.
22 '';
23 };
24
25 extraOptions = lib.mkOption {
26 type = with lib.types; listOf str;
27 default = [ ];
28 description = ''
29 Extra command line options.
30
31 Documentation can be found [here](https://github.com/prymitive/kthxbye/blob/main/README.md).
32 '';
33 example = lib.literalExpression ''
34 [
35 "-extend-with-prefix 'ACK!'"
36 ];
37 '';
38 };
39
40 alertmanager = {
41 timeout = lib.mkOption {
42 type = lib.types.str;
43 default = "1m0s";
44 description = ''
45 Alertmanager request timeout duration in the [time.Duration](https://pkg.go.dev/time#ParseDuration) format.
46 '';
47 example = "30s";
48 };
49 uri = lib.mkOption {
50 type = lib.types.str;
51 default = "http://localhost:9093";
52 description = ''
53 Alertmanager URI to use.
54 '';
55 example = "https://alertmanager.example.com";
56 };
57 };
58
59 extendBy = lib.mkOption {
60 type = lib.types.str;
61 default = "15m0s";
62 description = ''
63 Extend silences by adding DURATION seconds.
64
65 DURATION should be provided in the [time.Duration](https://pkg.go.dev/time#ParseDuration) format.
66 '';
67 example = "6h0m0s";
68 };
69
70 extendIfExpiringIn = lib.mkOption {
71 type = lib.types.str;
72 default = "5m0s";
73 description = ''
74 Extend silences that are about to expire in the next DURATION seconds.
75
76 DURATION should be provided in the [time.Duration](https://pkg.go.dev/time#ParseDuration) format.
77 '';
78 example = "1m0s";
79 };
80
81 extendWithPrefix = lib.mkOption {
82 type = lib.types.str;
83 default = "ACK!";
84 description = ''
85 Extend silences with comment starting with PREFIX string.
86 '';
87 example = "!perma-silence";
88 };
89
90 interval = lib.mkOption {
91 type = lib.types.str;
92 default = "45s";
93 description = ''
94 Silence check interval duration in the [time.Duration](https://pkg.go.dev/time#ParseDuration) format.
95 '';
96 example = "30s";
97 };
98
99 listenAddress = lib.mkOption {
100 type = lib.types.str;
101 default = "0.0.0.0";
102 description = ''
103 The address to listen on for HTTP requests.
104 '';
105 example = "127.0.0.1";
106 };
107
108 port = lib.mkOption {
109 type = lib.types.port;
110 default = 8080;
111 description = ''
112 The port to listen on for HTTP requests.
113 '';
114 };
115
116 logJSON = lib.mkOption {
117 type = lib.types.bool;
118 default = false;
119 description = ''
120 Format logged messages as JSON.
121 '';
122 };
123
124 maxDuration = lib.mkOption {
125 type = with lib.types; nullOr str;
126 default = null;
127 description = ''
128 Maximum duration of a silence, it won't be extended anymore after reaching it.
129
130 Duration should be provided in the [time.Duration](https://pkg.go.dev/time#ParseDuration) format.
131 '';
132 example = "30d";
133 };
134 };
135
136 config = lib.mkIf cfg.enable {
137 systemd.services.kthxbye = {
138 description = "kthxbye Alertmanager ack management daemon";
139 wantedBy = [ "multi-user.target" ];
140 script = ''
141 ${cfg.package}/bin/kthxbye \
142 -alertmanager.timeout ${cfg.alertmanager.timeout} \
143 -alertmanager.uri ${cfg.alertmanager.uri} \
144 -extend-by ${cfg.extendBy} \
145 -extend-if-expiring-in ${cfg.extendIfExpiringIn} \
146 -extend-with-prefix ${cfg.extendWithPrefix} \
147 -interval ${cfg.interval} \
148 -listen ${cfg.listenAddress}:${toString cfg.port} \
149 ${lib.optionalString cfg.logJSON "-log-json"} \
150 ${lib.optionalString (cfg.maxDuration != null) "-max-duration ${cfg.maxDuration}"} \
151 ${lib.concatStringsSep " " cfg.extraOptions}
152 '';
153 serviceConfig = {
154 Type = "simple";
155 DynamicUser = true;
156 Restart = "on-failure";
157 };
158 };
159
160 networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ];
161 };
162}