1{ config, pkgs, lib, ... }: with lib;
2let
3 cfg = config.services.vmalert;
4
5 format = pkgs.formats.yaml {};
6
7 confOpts = concatStringsSep " \\\n" (mapAttrsToList mkLine (filterAttrs (_: v: v != false) cfg.settings));
8 confType = with types;
9 let
10 valueType = oneOf [ bool int path str ];
11 in
12 attrsOf (either valueType (listOf valueType));
13
14 mkLine = key: value:
15 if value == true then "-${key}"
16 else if isList value then concatMapStringsSep " " (v: "-${key}=${escapeShellArg (toString v)}") value
17 else "-${key}=${escapeShellArg (toString value)}"
18 ;
19in
20{
21 # interface
22 options.services.vmalert = {
23 enable = mkEnableOption (mdDoc "vmalert");
24
25 package = mkOption {
26 type = types.package;
27 default = pkgs.victoriametrics;
28 defaultText = "pkgs.victoriametrics";
29 description = mdDoc ''
30 The VictoriaMetrics derivation to use.
31 '';
32 };
33
34 settings = mkOption {
35 type = types.submodule {
36 freeformType = confType;
37 options = {
38
39 "datasource.url" = mkOption {
40 type = types.nonEmptyStr;
41 example = "http://localhost:8428";
42 description = mdDoc ''
43 Datasource compatible with Prometheus HTTP API.
44 '';
45 };
46
47 "notifier.url" = mkOption {
48 type = with types; listOf nonEmptyStr;
49 default = [];
50 example = [ "http://127.0.0.1:9093" ];
51 description = mdDoc ''
52 Prometheus Alertmanager URL. List all Alertmanager URLs if it runs in the cluster mode to ensure high availability.
53 '';
54 };
55
56 "rule" = mkOption {
57 type = with types; listOf path;
58 description = mdDoc ''
59 Path to the files with alerting and/or recording rules.
60
61 ::: {.note}
62 Consider using the {option}`services.vmalert.rules` option as a convenient alternative for declaring rules
63 directly in the `nix` language.
64 :::
65 '';
66 };
67
68 };
69 };
70 default = { };
71 example = {
72 "datasource.url" = "http://localhost:8428";
73 "datasource.disableKeepAlive" = true;
74 "datasource.showURL" = false;
75 "rule" = [
76 "http://<some-server-addr>/path/to/rules"
77 "dir/*.yaml"
78 ];
79 };
80 description = mdDoc ''
81 `vmalert` configuration, passed via command line flags. Refer to
82 <https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/README.md#configuration>
83 for details on supported values.
84 '';
85 };
86
87 rules = mkOption {
88 type = format.type;
89 default = {};
90 example = {
91 group = [
92 { name = "TestGroup";
93 rules = [
94 { alert = "ExampleAlertAlwaysFiring";
95 expr = ''
96 sum by(job)
97 (up == 1)
98 '';
99 }
100 ];
101 }
102 ];
103 };
104 description = mdDoc ''
105 A list of the given alerting or recording rules against configured `"datasource.url"` compatible with
106 Prometheus HTTP API for `vmalert` to execute. Refer to
107 <https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/app/vmalert/README.md#rules>
108 for details on supported values.
109 '';
110 };
111 };
112
113 # implementation
114 config = mkIf cfg.enable {
115
116 environment.etc."vmalert/rules.yml".source = format.generate "rules.yml" cfg.rules;
117
118 services.vmalert.settings.rule = [
119 "/etc/vmalert/rules.yml"
120 ];
121
122 systemd.services.vmalert = {
123 description = "vmalert service";
124 wantedBy = [ "multi-user.target" ];
125 after = [ "network.target" ];
126 reloadTriggers = [ config.environment.etc."vmalert/rules.yml".source ];
127
128 serviceConfig = {
129 DynamicUser = true;
130 Restart = "on-failure";
131 ExecStart = "${cfg.package}/bin/vmalert ${confOpts}";
132 ExecReload = ''${pkgs.coreutils}/bin/kill -SIGHUP "$MAINPID"'';
133 };
134 };
135 };
136}