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