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