1{
2 lib,
3 config,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.matrix-alertmanager;
9 rooms = room: lib.concatStringsSep "/" (room.receivers ++ [ room.roomId ]);
10 concatenatedRooms = lib.concatStringsSep "|" (map rooms cfg.matrixRooms);
11in
12{
13 meta.maintainers = [ lib.maintainers.erethon ];
14
15 options.services.matrix-alertmanager = {
16 enable = lib.mkEnableOption "matrix-alertmanager";
17 package = lib.mkPackageOption pkgs "matrix-alertmanager" { };
18 port = lib.mkOption {
19 type = lib.types.port;
20 default = 3000;
21 description = "Port that matrix-alertmanager listens on.";
22 };
23 homeserverUrl = lib.mkOption {
24 type = lib.types.str;
25 description = "URL of the Matrix homeserver to use.";
26 example = "https://matrix.example.com";
27 };
28 matrixUser = lib.mkOption {
29 type = lib.types.str;
30 description = "Matrix user to use for the bot.";
31 example = "@alertmanageruser:example.com";
32 };
33 matrixRooms = lib.mkOption {
34 type = lib.types.listOf (
35 lib.types.submodule {
36 options = {
37 receivers = lib.mkOption {
38 type = lib.types.listOf lib.types.str;
39 description = "List of receivers for this room";
40 };
41 roomId = lib.mkOption {
42 type = lib.types.str;
43 description = "Matrix room ID";
44 apply =
45 x:
46 assert lib.assertMsg (lib.hasPrefix "!" x) "Matrix room ID must start with a '!'. Got: ${x}";
47 x;
48 };
49 };
50 }
51 );
52 description = ''
53 Combination of Alertmanager receiver(s) and rooms for the bot to join.
54 Each Alertmanager receiver can be mapped to post to a matrix room.
55
56 Note, you must use a room ID and not a room alias/name. Room IDs start
57 with a "!".
58 '';
59 example = [
60 {
61 receivers = [
62 "receiver1"
63 "receiver2"
64 ];
65 roomId = "!roomid@example.com";
66 }
67 {
68 receivers = [ "receiver3" ];
69 roomId = "!differentroomid@example.com";
70 }
71 ];
72 };
73 mention = lib.mkOption {
74 type = lib.types.bool;
75 default = false;
76 description = "Makes the bot mention @room when posting an alert";
77 };
78 tokenFile = lib.mkOption {
79 type = lib.types.pathWith {
80 inStore = false;
81 absolute = true;
82 };
83 description = "File that contains a valid Matrix token for the Matrix user.";
84 };
85 secretFile = lib.mkOption {
86 type = lib.types.pathWith {
87 inStore = false;
88 absolute = true;
89 };
90 description = "File that contains a secret for the Alertmanager webhook.";
91 };
92 };
93
94 config = lib.mkIf cfg.enable {
95 systemd.services.matrix-alertmanager = {
96 description = "A bot to receive Alertmanager webhook events and forward them to chosen rooms.";
97 after = [ "network.target" ];
98 wantedBy = [ "multi-user.target" ];
99 serviceConfig = {
100 DynamicUser = true;
101 Restart = "always";
102 RestartSec = "10s";
103 LoadCredential = [
104 "token:${cfg.tokenFile}"
105 "secret:${cfg.secretFile}"
106 ];
107 };
108
109 environment = {
110 APP_PORT = toString cfg.port;
111 MATRIX_HOMESERVER_URL = cfg.homeserverUrl;
112 MATRIX_ROOMS = concatenatedRooms;
113 MATRIX_USER = cfg.matrixUser;
114 MENTION_ROOM = if cfg.mention then "1" else "0";
115 NODE_ENV = "production";
116 };
117
118 script = ''
119 # shellcheck disable=SC2155
120 export APP_ALERTMANAGER_SECRET=$(cat "''${CREDENTIALS_DIRECTORY}/secret")
121 # shellcheck disable=SC2155
122 export MATRIX_TOKEN=$(cat "''${CREDENTIALS_DIRECTORY}/token")
123 exec ${lib.getExe cfg.package}
124 '';
125 };
126 };
127}