at 24.11-pre 7.3 kB view raw
1{ config, lib, options, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.etcd; 7 opt = options.services.etcd; 8 9in { 10 11 options.services.etcd = { 12 enable = mkOption { 13 description = "Whether to enable etcd."; 14 default = false; 15 type = types.bool; 16 }; 17 18 package = mkPackageOption pkgs "etcd" { }; 19 20 name = mkOption { 21 description = "Etcd unique node name."; 22 default = config.networking.hostName; 23 defaultText = literalExpression "config.networking.hostName"; 24 type = types.str; 25 }; 26 27 advertiseClientUrls = mkOption { 28 description = "Etcd list of this member's client URLs to advertise to the rest of the cluster."; 29 default = cfg.listenClientUrls; 30 defaultText = literalExpression "config.${opt.listenClientUrls}"; 31 type = types.listOf types.str; 32 }; 33 34 listenClientUrls = mkOption { 35 description = "Etcd list of URLs to listen on for client traffic."; 36 default = ["http://127.0.0.1:2379"]; 37 type = types.listOf types.str; 38 }; 39 40 listenPeerUrls = mkOption { 41 description = "Etcd list of URLs to listen on for peer traffic."; 42 default = ["http://127.0.0.1:2380"]; 43 type = types.listOf types.str; 44 }; 45 46 initialAdvertisePeerUrls = mkOption { 47 description = "Etcd list of this member's peer URLs to advertise to rest of the cluster."; 48 default = cfg.listenPeerUrls; 49 defaultText = literalExpression "config.${opt.listenPeerUrls}"; 50 type = types.listOf types.str; 51 }; 52 53 initialCluster = mkOption { 54 description = "Etcd initial cluster configuration for bootstrapping."; 55 default = ["${cfg.name}=http://127.0.0.1:2380"]; 56 defaultText = literalExpression ''["''${config.${opt.name}}=http://127.0.0.1:2380"]''; 57 type = types.listOf types.str; 58 }; 59 60 initialClusterState = mkOption { 61 description = "Etcd initial cluster configuration for bootstrapping."; 62 default = "new"; 63 type = types.enum ["new" "existing"]; 64 }; 65 66 initialClusterToken = mkOption { 67 description = "Etcd initial cluster token for etcd cluster during bootstrap."; 68 default = "etcd-cluster"; 69 type = types.str; 70 }; 71 72 discovery = mkOption { 73 description = "Etcd discovery url"; 74 default = ""; 75 type = types.str; 76 }; 77 78 clientCertAuth = mkOption { 79 description = "Whether to use certs for client authentication"; 80 default = false; 81 type = types.bool; 82 }; 83 84 trustedCaFile = mkOption { 85 description = "Certificate authority file to use for clients"; 86 default = null; 87 type = types.nullOr types.path; 88 }; 89 90 certFile = mkOption { 91 description = "Cert file to use for clients"; 92 default = null; 93 type = types.nullOr types.path; 94 }; 95 96 keyFile = mkOption { 97 description = "Key file to use for clients"; 98 default = null; 99 type = types.nullOr types.path; 100 }; 101 102 openFirewall = mkOption { 103 type = types.bool; 104 default = false; 105 description = '' 106 Open etcd ports in the firewall. 107 Ports opened: 108 - 2379/tcp for client requests 109 - 2380/tcp for peer communication 110 ''; 111 }; 112 113 peerCertFile = mkOption { 114 description = "Cert file to use for peer to peer communication"; 115 default = cfg.certFile; 116 defaultText = literalExpression "config.${opt.certFile}"; 117 type = types.nullOr types.path; 118 }; 119 120 peerKeyFile = mkOption { 121 description = "Key file to use for peer to peer communication"; 122 default = cfg.keyFile; 123 defaultText = literalExpression "config.${opt.keyFile}"; 124 type = types.nullOr types.path; 125 }; 126 127 peerTrustedCaFile = mkOption { 128 description = "Certificate authority file to use for peer to peer communication"; 129 default = cfg.trustedCaFile; 130 defaultText = literalExpression "config.${opt.trustedCaFile}"; 131 type = types.nullOr types.path; 132 }; 133 134 peerClientCertAuth = mkOption { 135 description = "Whether to check all incoming peer requests from the cluster for valid client certificates signed by the supplied CA"; 136 default = false; 137 type = types.bool; 138 }; 139 140 extraConf = mkOption { 141 description = '' 142 Etcd extra configuration. See 143 <https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md#configuration-flags> 144 ''; 145 type = types.attrsOf types.str; 146 default = {}; 147 example = literalExpression '' 148 { 149 "CORS" = "*"; 150 "NAME" = "default-name"; 151 "MAX_RESULT_BUFFER" = "1024"; 152 "MAX_CLUSTER_SIZE" = "9"; 153 "MAX_RETRY_ATTEMPTS" = "3"; 154 } 155 ''; 156 }; 157 158 dataDir = mkOption { 159 type = types.path; 160 default = "/var/lib/etcd"; 161 description = "Etcd data directory."; 162 }; 163 }; 164 165 config = mkIf cfg.enable { 166 systemd.tmpfiles.settings."10-etcd".${cfg.dataDir}.d = { 167 user = "etcd"; 168 mode = "0700"; 169 }; 170 171 systemd.services.etcd = { 172 description = "etcd key-value store"; 173 wantedBy = [ "multi-user.target" ]; 174 after = [ "network-online.target" ] 175 ++ lib.optional config.networking.firewall.enable "firewall.service"; 176 wants = [ "network-online.target" ] 177 ++ lib.optional config.networking.firewall.enable "firewall.service"; 178 179 environment = (filterAttrs (n: v: v != null) { 180 ETCD_NAME = cfg.name; 181 ETCD_DISCOVERY = cfg.discovery; 182 ETCD_DATA_DIR = cfg.dataDir; 183 ETCD_ADVERTISE_CLIENT_URLS = concatStringsSep "," cfg.advertiseClientUrls; 184 ETCD_LISTEN_CLIENT_URLS = concatStringsSep "," cfg.listenClientUrls; 185 ETCD_LISTEN_PEER_URLS = concatStringsSep "," cfg.listenPeerUrls; 186 ETCD_INITIAL_ADVERTISE_PEER_URLS = concatStringsSep "," cfg.initialAdvertisePeerUrls; 187 ETCD_PEER_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth; 188 ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile; 189 ETCD_PEER_CERT_FILE = cfg.peerCertFile; 190 ETCD_PEER_KEY_FILE = cfg.peerKeyFile; 191 ETCD_CLIENT_CERT_AUTH = toString cfg.clientCertAuth; 192 ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile; 193 ETCD_CERT_FILE = cfg.certFile; 194 ETCD_KEY_FILE = cfg.keyFile; 195 }) // (optionalAttrs (cfg.discovery == ""){ 196 ETCD_INITIAL_CLUSTER = concatStringsSep "," cfg.initialCluster; 197 ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState; 198 ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken; 199 }) // (mapAttrs' (n: v: nameValuePair "ETCD_${n}" v) cfg.extraConf); 200 201 unitConfig = { 202 Documentation = "https://github.com/coreos/etcd"; 203 }; 204 205 serviceConfig = { 206 Type = "notify"; 207 Restart = "always"; 208 RestartSec = "30s"; 209 ExecStart = "${cfg.package}/bin/etcd"; 210 User = "etcd"; 211 LimitNOFILE = 40000; 212 }; 213 }; 214 215 environment.systemPackages = [ cfg.package ]; 216 217 networking.firewall = lib.mkIf cfg.openFirewall { 218 allowedTCPPorts = [ 219 2379 # for client requests 220 2380 # for peer communication 221 ]; 222 }; 223 224 users.users.etcd = { 225 isSystemUser = true; 226 group = "etcd"; 227 description = "Etcd daemon user"; 228 home = cfg.dataDir; 229 }; 230 users.groups.etcd = {}; 231 }; 232}