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