10 dataDir = "/var/lib/consul";
11 cfg = config.services.consul;
22 "/etc/consul-addrs.json"
23 ] ++ cfg.extraConfigFiles;
25 devices = lib.attrValues (lib.filterAttrs (_: i: i != null) cfg.interface);
26 systemdDevices = lib.forEach devices (
27 i: "sys-subsystem-net-devices-${utils.escapeSystemdPath i}.device"
35 enable = lib.mkOption {
36 type = lib.types.bool;
39 Enables the consul daemon.
43 package = lib.mkPackageOption pkgs "consul" { };
45 webUi = lib.mkOption {
46 type = lib.types.bool;
49 Enables the web interface on the consul http port.
53 leaveOnStop = lib.mkOption {
54 type = lib.types.bool;
57 If enabled, causes a leave action to be sent when closing consul.
58 This allows a clean termination of the node, but permanently removes
59 it from the cluster. You probably don't want this option unless you
60 are running a node which going offline in a permanent / semi-permanent
67 advertise = lib.mkOption {
68 type = lib.types.nullOr lib.types.str;
71 The name of the interface to pull the advertise_addr from.
76 type = lib.types.nullOr lib.types.str;
79 The name of the interface to pull the bind_addr from.
84 forceAddrFamily = lib.mkOption {
85 type = lib.types.enum [
92 Whether to bind ipv4/ipv6 or both kind of addresses.
96 forceIpv4 = lib.mkOption {
97 type = lib.types.nullOr lib.types.bool;
100 Deprecated: Use consul.forceAddrFamily instead.
101 Whether we should force the interfaces to only pull ipv4 addresses.
105 dropPrivileges = lib.mkOption {
106 type = lib.types.bool;
109 Whether the consul agent should be run as a non-root consul user.
113 extraConfig = lib.mkOption {
115 type = lib.types.attrsOf lib.types.anything;
117 Extra configuration options which are serialized to json and added
118 to the config.json file.
122 extraConfigFiles = lib.mkOption {
124 type = lib.types.listOf lib.types.str;
126 Additional configuration files to pass to consul
127 NOTE: These will not trigger the service to be restarted when altered.
132 enable = lib.mkEnableOption "consul-alerts";
134 package = lib.mkPackageOption pkgs "consul-alerts" { };
136 listenAddr = lib.mkOption {
137 description = "Api listening address.";
138 default = "localhost:9000";
139 type = lib.types.str;
142 consulAddr = lib.mkOption {
143 description = "Consul api listening address";
144 default = "localhost:8500";
145 type = lib.types.str;
148 watchChecks = lib.mkOption {
149 description = "Whether to enable check watcher.";
151 type = lib.types.bool;
154 watchEvents = lib.mkOption {
155 description = "Whether to enable event watcher.";
157 type = lib.types.bool;
165 config = lib.mkIf cfg.enable (
169 users.users.consul = {
170 description = "Consul agent daemon user";
173 # The shell is needed for health checks
174 shell = "/run/current-system/sw/bin/bash";
176 users.groups.consul = { };
179 etc."consul.json".text = builtins.toJSON configOptions;
180 # We need consul.d to exist for consul to start
181 etc."consul.d/dummy.json".text = "{ }";
182 systemPackages = [ cfg.package ];
185 warnings = lib.flatten [
186 (lib.optional (cfg.forceIpv4 != null) ''
187 The option consul.forceIpv4 is deprecated, please use
188 consul.forceAddrFamily instead.
192 systemd.services.consul = {
193 wantedBy = [ "multi-user.target" ];
194 after = [ "network.target" ] ++ systemdDevices;
195 bindsTo = systemdDevices;
197 [ config.environment.etc."consul.json".source ]
198 ++ lib.mapAttrsToList (_: d: d.source) (
199 lib.filterAttrs (n: _: lib.hasPrefix "consul.d/" n) config.environment.etc
205 "@${lib.getExe cfg.package} consul agent -config-dir /etc/consul.d"
206 + lib.concatMapStrings (n: " -config-file ${n}") configFiles;
207 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
208 PermissionsStartOnly = true;
209 User = if cfg.dropPrivileges then "consul" else null;
210 Restart = "on-failure";
211 TimeoutStartSec = "infinity";
213 // (lib.optionalAttrs (cfg.leaveOnStop) {
214 ExecStop = "${lib.getExe cfg.package} leave";
225 if cfg.forceAddrFamily == "ipv6" then
227 else if cfg.forceAddrFamily == "ipv4" then
233 mkdir -m 0700 -p ${dataDir}
234 chown -R consul ${dataDir}
236 # Determine interface addresses
238 ip ${family} addr show dev "$1" scope global \
239 | awk -F '[ /\t]*' '/inet/ {print $3}' | head -n 1
242 ADDR="$(getAddrOnce $1)"
243 LEFT=60 # Die after 1 minute
244 while [ -z "$ADDR" ]; do
246 LEFT=$(expr $LEFT - 1)
247 if [ "$LEFT" -eq "0" ]; then
248 echo "Address lookup timed out"
251 ADDR="$(getAddrOnce $1)"
255 echo "{" > /etc/consul-addrs.json
258 + lib.concatStrings (
259 lib.flip lib.mapAttrsToList cfg.interface (
261 lib.optionalString (i != null) ''
262 echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json
268 echo "}" >> /etc/consul-addrs.json
274 (lib.mkIf (cfg.forceIpv4 != null && cfg.forceIpv4) {
275 services.consul.forceAddrFamily = "ipv4";
278 (lib.mkIf (cfg.alerts.enable) {
279 systemd.services.consul-alerts = {
280 wantedBy = [ "multi-user.target" ];
281 after = [ "consul.service" ];
283 path = [ cfg.package ];
287 ${lib.getExe cfg.alerts.package} start \
288 --alert-addr=${cfg.alerts.listenAddr} \
289 --consul-addr=${cfg.alerts.consulAddr} \
290 ${lib.optionalString cfg.alerts.watchChecks "--watch-checks"} \
291 ${lib.optionalString cfg.alerts.watchEvents "--watch-events"}
293 User = if cfg.dropPrivileges then "consul" else null;
294 Restart = "on-failure";