at 15.09-beta 7.0 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3with lib; 4let 5 6 dataDir = "/var/lib/consul"; 7 cfg = config.services.consul; 8 9 configOptions = { data_dir = dataDir; } // 10 (if cfg.webUi then { ui_dir = "${pkgs.consul.ui}"; } else { }) // 11 cfg.extraConfig; 12 13 configFiles = [ "/etc/consul.json" "/etc/consul-addrs.json" ] 14 ++ cfg.extraConfigFiles; 15 16 devices = attrValues (filterAttrs (_: i: i != null) cfg.interface); 17 systemdDevices = flip map devices 18 (i: "sys-subsystem-net-devices-${utils.escapeSystemdPath i}.device"); 19in 20{ 21 options = { 22 23 services.consul = { 24 25 enable = mkOption { 26 type = types.bool; 27 default = false; 28 description = '' 29 Enables the consul daemon. 30 ''; 31 }; 32 33 webUi = mkOption { 34 type = types.bool; 35 default = false; 36 description = '' 37 Enables the web interface on the consul http port. 38 ''; 39 }; 40 41 leaveOnStop = mkOption { 42 type = types.bool; 43 default = false; 44 description = '' 45 If enabled, causes a leave action to be sent when closing consul. 46 This allows a clean termination of the node, but permanently removes 47 it from the cluster. You probably don't want this option unless you 48 are running a node which going offline in a permanent / semi-permanent 49 fashion. 50 ''; 51 }; 52 53 interface = { 54 55 advertise = mkOption { 56 type = types.nullOr types.str; 57 default = null; 58 description = '' 59 The name of the interface to pull the advertise_addr from. 60 ''; 61 }; 62 63 bind = mkOption { 64 type = types.nullOr types.str; 65 default = null; 66 description = '' 67 The name of the interface to pull the bind_addr from. 68 ''; 69 }; 70 71 }; 72 73 forceIpv4 = mkOption { 74 type = types.bool; 75 default = false; 76 description = '' 77 Whether we should force the interfaces to only pull ipv4 addresses. 78 ''; 79 }; 80 81 dropPrivileges = mkOption { 82 type = types.bool; 83 default = true; 84 description = '' 85 Whether the consul agent should be run as a non-root consul user. 86 ''; 87 }; 88 89 extraConfig = mkOption { 90 default = { }; 91 description = '' 92 Extra configuration options which are serialized to json and added 93 to the config.json file. 94 ''; 95 }; 96 97 extraConfigFiles = mkOption { 98 default = [ ]; 99 type = types.listOf types.str; 100 description = '' 101 Additional configuration files to pass to consul 102 NOTE: These will not trigger the service to be restarted when altered. 103 ''; 104 }; 105 106 alerts = { 107 enable = mkEnableOption "consul-alerts"; 108 109 package = mkOption { 110 description = "Package to use for consul-alerts."; 111 default = pkgs.consul-alerts; 112 type = types.package; 113 }; 114 115 listenAddr = mkOption { 116 description = "Api listening address."; 117 default = "localhost:9000"; 118 type = types.str; 119 }; 120 121 consulAddr = mkOption { 122 description = "Consul api listening adddress"; 123 default = "localhost:8500"; 124 type = types.str; 125 }; 126 127 watchChecks = mkOption { 128 description = "Whether to enable check watcher."; 129 default = true; 130 type = types.bool; 131 }; 132 133 watchEvents = mkOption { 134 description = "Whether to enable event watcher."; 135 default = true; 136 type = types.bool; 137 }; 138 }; 139 140 }; 141 142 }; 143 144 config = mkIf cfg.enable ( 145 mkMerge [{ 146 147 users.extraUsers."consul" = { 148 description = "Consul agent daemon user"; 149 uid = config.ids.uids.consul; 150 # The shell is needed for health checks 151 shell = "/run/current-system/sw/bin/bash"; 152 }; 153 154 environment = { 155 etc."consul.json".text = builtins.toJSON configOptions; 156 # We need consul.d to exist for consul to start 157 etc."consul.d/dummy.json".text = "{ }"; 158 systemPackages = with pkgs; [ consul ]; 159 }; 160 161 systemd.services.consul = { 162 wantedBy = [ "multi-user.target" ]; 163 after = [ "network.target" ] ++ systemdDevices; 164 bindsTo = systemdDevices; 165 restartTriggers = [ config.environment.etc."consul.json".source ] 166 ++ mapAttrsToList (_: d: d.source) 167 (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc); 168 169 serviceConfig = { 170 ExecStart = "@${pkgs.consul}/bin/consul consul agent -config-dir /etc/consul.d" 171 + concatMapStrings (n: " -config-file ${n}") configFiles; 172 ExecReload = "${pkgs.consul}/bin/consul reload"; 173 PermissionsStartOnly = true; 174 User = if cfg.dropPrivileges then "consul" else null; 175 TimeoutStartSec = "0"; 176 } // (optionalAttrs (cfg.leaveOnStop) { 177 ExecStop = "${pkgs.consul}/bin/consul leave"; 178 }); 179 180 path = with pkgs; [ iproute gnugrep gawk consul ]; 181 preStart = '' 182 mkdir -m 0700 -p ${dataDir} 183 chown -R consul ${dataDir} 184 185 # Determine interface addresses 186 getAddrOnce () { 187 ip addr show dev "$1" \ 188 | grep 'inet${optionalString (cfg.forceIpv4) " "}.*scope global' \ 189 | awk -F '[ /\t]*' '{print $3}' | head -n 1 190 } 191 getAddr () { 192 ADDR="$(getAddrOnce $1)" 193 LEFT=60 # Die after 1 minute 194 while [ -z "$ADDR" ]; do 195 sleep 1 196 LEFT=$(expr $LEFT - 1) 197 if [ "$LEFT" -eq "0" ]; then 198 echo "Address lookup timed out" 199 exit 1 200 fi 201 ADDR="$(getAddrOnce $1)" 202 done 203 echo "$ADDR" 204 } 205 echo "{" > /etc/consul-addrs.json 206 delim=" " 207 '' 208 + concatStrings (flip mapAttrsToList cfg.interface (name: i: 209 optionalString (i != null) '' 210 echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json 211 delim="," 212 '')) 213 + '' 214 echo "}" >> /etc/consul-addrs.json 215 ''; 216 }; 217 } 218 219 (mkIf (cfg.alerts.enable) { 220 systemd.services.consul-alerts = { 221 wantedBy = [ "multi-user.target" ]; 222 after = [ "consul.service" ]; 223 224 path = [ pkgs.consul ]; 225 226 serviceConfig = { 227 ExecStart = '' 228 ${cfg.alerts.package}/bin/consul-alerts start \ 229 --alert-addr=${cfg.alerts.listenAddr} \ 230 --consul-addr=${cfg.alerts.consulAddr} \ 231 ${optionalString cfg.alerts.watchChecks "--watch-checks"} \ 232 ${optionalString cfg.alerts.watchEvents "--watch-events"} 233 ''; 234 User = if cfg.dropPrivileges then "consul" else null; 235 Restart = "on-failure"; 236 }; 237 }; 238 }) 239 240 ]); 241}