at 24.11-pre 6.7 kB view raw
1{ config, pkgs, lib, ... }: 2 3with lib; 4 5let 6 cfg = config.services.prometheus.alertmanager; 7 mkConfigFile = pkgs.writeText "alertmanager.yml" (builtins.toJSON cfg.configuration); 8 9 checkedConfig = file: 10 if cfg.checkConfig then 11 pkgs.runCommand "checked-config" { nativeBuildInputs = [ cfg.package ]; } '' 12 ln -s ${file} $out 13 amtool check-config $out 14 '' else file; 15 16 alertmanagerYml = let 17 yml = if cfg.configText != null then 18 pkgs.writeText "alertmanager.yml" cfg.configText 19 else mkConfigFile; 20 in checkedConfig yml; 21 22 cmdlineArgs = cfg.extraFlags ++ [ 23 "--config.file /tmp/alert-manager-substituted.yaml" 24 "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" 25 "--log.level ${cfg.logLevel}" 26 "--storage.path /var/lib/alertmanager" 27 (toString (map (peer: "--cluster.peer ${peer}:9094") cfg.clusterPeers)) 28 ] ++ (optional (cfg.webExternalUrl != null) 29 "--web.external-url ${cfg.webExternalUrl}" 30 ) ++ (optional (cfg.logFormat != null) 31 "--log.format ${cfg.logFormat}" 32 ); 33in { 34 imports = [ 35 (mkRemovedOptionModule [ "services" "prometheus" "alertmanager" "user" ] "The alertmanager service is now using systemd's DynamicUser mechanism which obviates a user setting.") 36 (mkRemovedOptionModule [ "services" "prometheus" "alertmanager" "group" ] "The alertmanager service is now using systemd's DynamicUser mechanism which obviates a group setting.") 37 (mkRemovedOptionModule [ "services" "prometheus" "alertmanagerURL" ] '' 38 Due to incompatibility, the alertmanagerURL option has been removed, 39 please use 'services.prometheus.alertmanagers' instead. 40 '') 41 ]; 42 43 options = { 44 services.prometheus.alertmanager = { 45 enable = mkEnableOption "Prometheus Alertmanager"; 46 47 package = mkPackageOption pkgs "prometheus-alertmanager" { }; 48 49 configuration = mkOption { 50 type = types.nullOr types.attrs; 51 default = null; 52 description = '' 53 Alertmanager configuration as nix attribute set. 54 ''; 55 }; 56 57 configText = mkOption { 58 type = types.nullOr types.lines; 59 default = null; 60 description = '' 61 Alertmanager configuration as YAML text. If non-null, this option 62 defines the text that is written to alertmanager.yml. If null, the 63 contents of alertmanager.yml is generated from the structured config 64 options. 65 ''; 66 }; 67 68 checkConfig = mkOption { 69 type = types.bool; 70 default = true; 71 description = '' 72 Check configuration with `amtool check-config`. The call to `amtool` is 73 subject to sandboxing by Nix. 74 75 If you use credentials stored in external files 76 (`environmentFile`, etc), 77 they will not be visible to `amtool` 78 and it will report errors, despite a correct configuration. 79 ''; 80 }; 81 82 logFormat = mkOption { 83 type = types.nullOr types.str; 84 default = null; 85 description = '' 86 If set use a syslog logger or JSON logging. 87 ''; 88 }; 89 90 logLevel = mkOption { 91 type = types.enum ["debug" "info" "warn" "error" "fatal"]; 92 default = "warn"; 93 description = '' 94 Only log messages with the given severity or above. 95 ''; 96 }; 97 98 webExternalUrl = mkOption { 99 type = types.nullOr types.str; 100 default = null; 101 description = '' 102 The URL under which Alertmanager is externally reachable (for example, if Alertmanager is served via a reverse proxy). 103 Used for generating relative and absolute links back to Alertmanager itself. 104 If the URL has a path portion, it will be used to prefix all HTTP endoints served by Alertmanager. 105 If omitted, relevant URL components will be derived automatically. 106 ''; 107 }; 108 109 listenAddress = mkOption { 110 type = types.str; 111 default = ""; 112 description = '' 113 Address to listen on for the web interface and API. Empty string will listen on all interfaces. 114 "localhost" will listen on 127.0.0.1 (but not ::1). 115 ''; 116 }; 117 118 port = mkOption { 119 type = types.port; 120 default = 9093; 121 description = '' 122 Port to listen on for the web interface and API. 123 ''; 124 }; 125 126 openFirewall = mkOption { 127 type = types.bool; 128 default = false; 129 description = '' 130 Open port in firewall for incoming connections. 131 ''; 132 }; 133 134 clusterPeers = mkOption { 135 type = types.listOf types.str; 136 default = []; 137 description = '' 138 Initial peers for HA cluster. 139 ''; 140 }; 141 142 extraFlags = mkOption { 143 type = types.listOf types.str; 144 default = []; 145 description = '' 146 Extra commandline options when launching the Alertmanager. 147 ''; 148 }; 149 150 environmentFile = mkOption { 151 type = types.nullOr types.path; 152 default = null; 153 example = "/root/alertmanager.env"; 154 description = '' 155 File to load as environment file. Environment variables 156 from this file will be interpolated into the config file 157 using envsubst with this syntax: 158 `$ENVIRONMENT ''${VARIABLE}` 159 ''; 160 }; 161 }; 162 }; 163 164 config = mkMerge [ 165 (mkIf cfg.enable { 166 assertions = singleton { 167 assertion = cfg.configuration != null || cfg.configText != null; 168 message = "Can not enable alertmanager without a configuration. " 169 + "Set either the `configuration` or `configText` attribute."; 170 }; 171 }) 172 (mkIf cfg.enable { 173 networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; 174 175 systemd.services.alertmanager = { 176 wantedBy = [ "multi-user.target" ]; 177 wants = [ "network-online.target" ]; 178 after = [ "network-online.target" ]; 179 preStart = '' 180 ${lib.getBin pkgs.envsubst}/bin/envsubst -o "/tmp/alert-manager-substituted.yaml" \ 181 -i "${alertmanagerYml}" 182 ''; 183 serviceConfig = { 184 Restart = "always"; 185 StateDirectory = "alertmanager"; 186 DynamicUser = true; # implies PrivateTmp 187 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; 188 WorkingDirectory = "/tmp"; 189 ExecStart = "${cfg.package}/bin/alertmanager" + 190 optionalString (length cmdlineArgs != 0) (" \\\n " + 191 concatStringsSep " \\\n " cmdlineArgs); 192 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 193 }; 194 }; 195 }) 196 ]; 197}