From 54d3556e7aaa36f68cbeb9c9ea40edafda42c823 Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Wed, 24 Aug 2016 14:45:08 +0200 Subject: [PATCH 1/6] etcd: 2.3.7 -> 3.0.6 --- pkgs/servers/etcd/default.nix | 6 +- pkgs/servers/etcd/deps.json | 351 ++++++++++++++++++++++++++++++++-- 2 files changed, 336 insertions(+), 21 deletions(-) diff --git a/pkgs/servers/etcd/default.nix b/pkgs/servers/etcd/default.nix index 2c76dfc8e31..57eb877cd79 100644 --- a/pkgs/servers/etcd/default.nix +++ b/pkgs/servers/etcd/default.nix @@ -2,16 +2,16 @@ buildGoPackage rec { name = "etcd-${version}"; - version = "2.3.7"; + version = "3.0.6"; rev = "v${version}"; - + goPackagePath = "github.com/coreos/etcd"; src = fetchFromGitHub { inherit rev; owner = "coreos"; repo = "etcd"; - sha256 = "07rdnhcpnvnkxj5pqacxz669rzn5vw2i1zmf6dd4nv7wpfscdw9f"; + sha256 = "163qji360y21nr1wnl16nbvvgdgqgbny4c3v3igp87q9p78sdf75"; }; goDeps = ./deps.json; diff --git a/pkgs/servers/etcd/deps.json b/pkgs/servers/etcd/deps.json index 310f51963f2..6ba22a78b7c 100644 --- a/pkgs/servers/etcd/deps.json +++ b/pkgs/servers/etcd/deps.json @@ -1,20 +1,335 @@ [ - { - "goPackagePath": "github.com/olekukonko/tablewriter", - "fetch": { - "type": "git", - "url": "https://github.com/olekukonko/tablewriter", - "rev": "cca8bbc0798408af109aaaa239cbd2634846b340", - "sha256": "0f9ph3z7lh6p6gihbl1461j9yq5qiaqxr9mzdkp512n18v89ml48" - } - }, - { - "goPackagePath": "github.com/mattn/go-runewidth", - "fetch": { - "type": "git", - "url": "https://github.com/mattn/go-runewidth", - "rev": "d6bea18f789704b5f83375793155289da36a3c7f", - "sha256": "1hnigpn7rjbwd1ircxkyx9hvi0xmxr32b2jdy2jzw6b3jmcnz1fs" - } + { + "goPackagePath": "github.com/beorn7/perks", + "fetch": { + "type": "git", + "url": "https://github.com/beorn7/perks", + "rev": "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9", + "sha256": "1hrybsql68xw57brzj805xx2mghydpdiysv3gbhr7f5wlxj2514y" } -] + }, + { + "goPackagePath": "github.com/boltdb/bolt", + "fetch": { + "type": "git", + "url": "https://github.com/boltdb/bolt", + "rev": "583e8937c61f1af6513608ccc75c97b6abdf4ff9", + "sha256": "0cp5v9iypg9ysiq40k3h3lg7aisxplnmxshha7nama6b170izyay" + } + }, + { + "goPackagePath": "github.com/cloudfoundry-incubator/candiedyaml", + "fetch": { + "type": "git", + "url": "https://github.com/cloudfoundry-incubator/candiedyaml", + "rev": "99c3df83b51532e3615f851d8c2dbb638f5313bf", + "sha256": "106nibg7423642gbkg88c5x2jxfz6nmxbribhwb8cr1rn9vpjaxs" + } + }, + { + "goPackagePath": "github.com/cockroachdb/cmux", + "fetch": { + "type": "git", + "url": "https://github.com/cockroachdb/cmux", + "rev": "b64f5908f4945f4b11ed4a0a9d3cc1e23350866d", + "sha256": "1by4f3x7j3r3z1sdx1v04r494hn6jaag7lc03prrgx455j8i0jlh" + } + }, + { + "goPackagePath": "github.com/coreos/etcd", + "fetch": { + "type": "git", + "url": "https://github.com/coreos/etcd.git", + "rev": "9efa00d1030d4bf62eb8e5ec130023aeb1b8e2d0", + "sha256": "163qji360y21nr1wnl16nbvvgdgqgbny4c3v3igp87q9p78sdf75" + } + }, + { + "goPackagePath": "github.com/coreos/go-semver", + "fetch": { + "type": "git", + "url": "https://github.com/coreos/go-semver", + "rev": "8ab6407b697782a06568d4b7f1db25550ec2e4c6", + "sha256": "1gghi5bnqj50hfxhqc1cxmynqmh2yk9ii7ab9gsm75y5cp94ymk0" + } + }, + { + "goPackagePath": "github.com/coreos/go-systemd", + "fetch": { + "type": "git", + "url": "https://github.com/coreos/go-systemd", + "rev": "5c49e4850c879a0ddc061e8f4adcf307de8a8bc2", + "sha256": "1w16bnrgfjb5rwha7g8rdjhpgjf8bzmlzhrda5bfvc9ymj3qjibk" + } + }, + { + "goPackagePath": "github.com/coreos/pkg", + "fetch": { + "type": "git", + "url": "https://github.com/coreos/pkg", + "rev": "3ac0863d7acf3bc44daf49afef8919af12f704ef", + "sha256": "0l5ans1ls2gknkrnhymgc0zbgg5nqjbjbqc51r611adcr0m6gg8l" + } + }, + { + "goPackagePath": "github.com/ghodss/yaml", + "fetch": { + "type": "git", + "url": "https://github.com/ghodss/yaml", + "rev": "aa0c862057666179de291b67d9f093d12b5a8473", + "sha256": "0cbc78n8l7h1gdzhrvahplcvr4v7n8v23vkgskfp843rcx5h6isr" + } + }, + { + "goPackagePath": "github.com/gogo/protobuf", + "fetch": { + "type": "git", + "url": "https://github.com/gogo/protobuf", + "rev": "f20a1444730c7d9949b880a0309e737d007def25", + "sha256": "12wa3r2cb2v1m65phbkh692ldlklk459z4x6avpc6im0zkr6r73c" + } + }, + { + "goPackagePath": "github.com/golang/protobuf", + "fetch": { + "type": "git", + "url": "https://github.com/golang/protobuf", + "rev": "f592bd283e9ef86337a432eb50e592278c3d534d", + "sha256": "01gxhzn9m6jz6ihwxfycnx39zf5pmkan61l278cnynsb8mibdpvb" + } + }, + { + "goPackagePath": "github.com/google/btree", + "fetch": { + "type": "git", + "url": "https://github.com/google/btree", + "rev": "7d79101e329e5a3adf994758c578dab82b90c017", + "sha256": "1c1hsy5s2pfawg3l9954jmqmy4yc2zp3f7i87m00km2yqgb8xpd0" + } + }, + { + "goPackagePath": "github.com/grpc-ecosystem/grpc-gateway", + "fetch": { + "type": "git", + "url": "https://github.com/grpc-ecosystem/grpc-gateway", + "rev": "5e0e028ba0a015710eaebf6e47af18812c9f2767", + "sha256": "00s4wxzs6lz5al7y2hxi6r4bxhx5b0ajk5rwxrnb4a4mhlaii8pk" + } + }, + { + "goPackagePath": "github.com/jonboulle/clockwork", + "fetch": { + "type": "git", + "url": "https://github.com/jonboulle/clockwork", + "rev": "e3653ace2d63753697e0e5b07b9393971c0bba9d", + "sha256": "1avzqhks12a8x2yzpvjsf3k0gv9cy7zx2z88hn0scacnxkphisvc" + } + }, + { + "goPackagePath": "github.com/matttproud/golang_protobuf_extensions", + "fetch": { + "type": "git", + "url": "https://github.com/matttproud/golang_protobuf_extensions", + "rev": "c12348ce28de40eed0136aa2b644d0ee0650e56c", + "sha256": "1d0c1isd2lk9pnfq2nk0aih356j30k3h1gi2w0ixsivi5csl7jya" + } + }, + { + "goPackagePath": "github.com/prometheus/client_golang", + "fetch": { + "type": "git", + "url": "https://github.com/prometheus/client_golang", + "rev": "c5b7fccd204277076155f10851dad72b76a49317", + "sha256": "1xqny3147g12n4j03kxm8s9mvdbs3ln6i56c655mybrn9jjy48kd" + } + }, + { + "goPackagePath": "github.com/prometheus/client_model", + "fetch": { + "type": "git", + "url": "https://github.com/prometheus/client_model", + "rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6", + "sha256": "11a7v1fjzhhwsl128znjcf5v7v6129xjgkdpym2lial4lac1dhm9" + } + }, + { + "goPackagePath": "github.com/prometheus/common", + "fetch": { + "type": "git", + "url": "https://github.com/prometheus/common", + "rev": "ebdfc6da46522d58825777cf1f90490a5b1ef1d8", + "sha256": "0js62pj8600773wx6labpd772yyhz5ivim7dnl7b862wblbmc8mq" + } + }, + { + "goPackagePath": "github.com/prometheus/procfs", + "fetch": { + "type": "git", + "url": "https://github.com/prometheus/procfs", + "rev": "abf152e5f3e97f2fafac028d2cc06c1feb87ffa5", + "sha256": "0cp8lznv1b4zhi3wnbjkfxwzhkqd3wbmiy6mwgjanip8l9l3ykws" + } + }, + { + "goPackagePath": "github.com/spf13/cobra", + "fetch": { + "type": "git", + "url": "https://github.com/spf13/cobra", + "rev": "7c674d9e72017ed25f6d2b5e497a1368086b6a6f", + "sha256": "0an935r7lc11a744mvdrsy56rs2w0ah3gdclvr4gzd5iqr9ap3dr" + } + }, + { + "goPackagePath": "github.com/spf13/pflag", + "fetch": { + "type": "git", + "url": "https://github.com/spf13/pflag", + "rev": "6454a84b6da0ea8b628d5d8a26759f62c6c161b4", + "sha256": "06rfi73jhkncn8gxy6klgmba5947k9gpwdswipdpz680yxczcwna" + } + }, + { + "goPackagePath": "github.com/ugorji/go", + "fetch": { + "type": "git", + "url": "https://github.com/ugorji/go", + "rev": "4a1cb5252a6951f715a85d0e4be334c2a2dbf2a2", + "sha256": "0izpijk3piihl4fnqg8ncnp5ivbq41pg3xf7iagg4fbg5id4pxbx" + } + }, + { + "goPackagePath": "github.com/xiang90/probing", + "fetch": { + "type": "git", + "url": "https://github.com/xiang90/probing", + "rev": "07dd2e8dfe18522e9c447ba95f2fe95262f63bb2", + "sha256": "0r8rq27yigz72mk8z7p61yjfan8id021dnp1v421ln9byzpvabn2" + } + }, + { + "goPackagePath": "golang.org/x/crypto", + "fetch": { + "type": "git", + "url": "https://go.googlesource.com/crypto", + "rev": "88d0005bf4c3ec17306ecaca4281a8d8efd73e91", + "sha256": "1d3x0rwfd4cml06ka8gy74wxrw94m2z7qgz6ky0rgmxcr7p5iikz" + } + }, + { + "goPackagePath": "golang.org/x/net", + "fetch": { + "type": "git", + "url": "https://go.googlesource.com/net", + "rev": "7394c112eae4dba7e96bfcfe738e6373d61772b4", + "sha256": "1p8wsxnbsp2lq6hbza2n0zgv4sgpxzzjjlrmcngkhxj47kp3hin7" + } + }, + { + "goPackagePath": "google.golang.org/grpc", + "fetch": { + "type": "git", + "url": "https://github.com/grpc/grpc-go", + "rev": "0032a855ba5c8a3c8e0d71c2deef354b70af1584", + "sha256": "0qkynp65jwk6jk932k7kwxs5v6fzlfsb1fay71a00dwr36f44s67" + } + }, + { + "goPackagePath": "github.com/urfave/cli", + "fetch": { + "type": "git", + "url": "https://github.com/urfave/cli", + "rev": "168c95418e66e019fe17b8f4f5c45aa62ff80e23", + "sha256": "1gdvvim2f1zigcmbpcgypgn7nvpnlr87grbg7lw13fbpy6fnlw2n" + } + }, + { + "goPackagePath": "github.com/mattn/go-runewidth", + "fetch": { + "type": "git", + "url": "https://github.com/mattn/go-runewidth", + "rev": "d6bea18f789704b5f83375793155289da36a3c7f", + "sha256": "1hnigpn7rjbwd1ircxkyx9hvi0xmxr32b2jdy2jzw6b3jmcnz1fs" + } + }, + { + "goPackagePath": "github.com/olekukonko/tablewriter", + "fetch": { + "type": "git", + "url": "https://github.com/olekukonko/tablewriter", + "rev": "daf2955e742cf123959884fdff4685aa79b63135", + "sha256": "1fvl251ms7qmzfbi853kdgghqkrmyy6n1605mfy50nhgvw03z203" + } + }, + { + "goPackagePath": "github.com/dustin/go-humanize", + "fetch": { + "type": "git", + "url": "https://github.com/dustin/go-humanize", + "rev": "2fcb5204cdc65b4bec9fd0a87606bb0d0e3c54e8", + "sha256": "1m2qgn5vh5m66ggmclgikvwc05np2r7sxgpvlj2jip5d61x29j5k" + } + }, + { + "goPackagePath": "github.com/bgentry/speakeasy", + "fetch": { + "type": "git", + "url": "https://github.com/bgentry/speakeasy", + "rev": "a1ccbf2c40dfc8ce514b5c5c6e6d1429ea6880da", + "sha256": "0xqpc1qhdcs5blp1mkrppfb1x0rcv4a445mj0yzdwshbzkw5di01" + } + }, + { + "goPackagePath": "github.com/kr/pty", + "fetch": { + "type": "git", + "url": "https://github.com/kr/pty", + "rev": "ce7fa45920dc37a92de8377972e52bc55ffa8d57", + "sha256": "0mdlr2mmwjznw2id0l4200xjajq9dh1kxn3z7d3ksn0b5fwinzmk" + } + }, + { + "goPackagePath": "github.com/golang/groupcache", + "fetch": { + "type": "git", + "url": "https://github.com/golang/groupcache", + "rev": "a6b377e3400b08991b80d6805d627f347f983866", + "sha256": "125a6zdaxj916yp2rlrkg8xw00vjf5ga9xwdg4clby8wj4fysma2" + } + }, + { + "goPackagePath": "gopkg.in/cheggaaa/pb.v1", + "fetch": { + "type": "git", + "url": "https://gopkg.in/cheggaaa/pb.v1", + "rev": "9453b2db37f4d8bc63751daca63bbe7049eb5e74", + "sha256": "0py7dxvm3ydxcw260x7r7xbjww1vkil3rhyy3f9njmjydyb303rb" + } + }, + { + "goPackagePath": "github.com/golang/glog", + "fetch": { + "type": "git", + "url": "https://github.com/golang/glog", + "rev": "23def4e6c14b4da8ac2ed8007337bc5eb5007998", + "sha256": "0jb2834rw5sykfr937fxi8hxi2zy80sj2bdn9b3jb4b26ksqng30" + } + }, + { + "goPackagePath": "github.com/spacejam/loghisto", + "fetch": { + "type": "git", + "url": "https://github.com/spacejam/loghisto", + "rev": "9d1d8c1fd2a4ac852bf2e312f2379f553345fda7", + "sha256": "0r31y4ci35pp11wqdyarimdq5a703byk3cf6d67adsa4nw0ysfm1" + } + }, + { + "goPackagePath": "github.com/akrennmair/gopcap", + "fetch": { + "type": "git", + "url": "https://github.com/akrennmair/gopcap", + "rev": "00e11033259acb75598ba416495bb708d864a010", + "sha256": "0xfw7x5a36w0g76imjvgk055360xg0nva42qhmflfvll7ldxq96a" + } + } +] \ No newline at end of file From 8256c07fc03625ea37ff2ebb29217c50e2ed6163 Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Wed, 24 Aug 2016 20:11:39 +0200 Subject: [PATCH 2/6] etcd module: add support for ssl, better defaults, fix tests --- nixos/modules/services/misc/etcd.nix | 65 ++++++++- nixos/tests/etcd.nix | 199 +++++++++++++++------------ 2 files changed, 168 insertions(+), 96 deletions(-) diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix index 0d6ed8eb904..8a12e183aa3 100644 --- a/nixos/modules/services/misc/etcd.nix +++ b/nixos/modules/services/misc/etcd.nix @@ -28,13 +28,13 @@ in { listenClientUrls = mkOption { description = "Etcd list of URLs to listen on for client traffic."; - default = ["http://localhost:4001"]; + default = ["http://localhost:2379"]; type = types.listOf types.str; }; listenPeerUrls = mkOption { description = "Etcd list of URLs to listen on for peer traffic."; - default = ["http://localhost:7001"]; + default = ["http://localhost:2380"]; type = types.listOf types.str; }; @@ -46,7 +46,7 @@ in { initialCluster = mkOption { description = "Etcd initial cluster configuration for bootstrapping."; - default = ["${cfg.name}=http://localhost:7001"]; + default = ["${cfg.name}=http://127.0.0.1:2380"]; type = types.listOf types.str; }; @@ -68,6 +68,54 @@ in { type = types.str; }; + clientCertAuth = mkOption { + description = "Whether to use certs for client authentication"; + default = false; + type = types.bool; + }; + + trustedCaFile = mkOption { + description = "Certificate authority file to use for clients"; + default = null; + type = types.nullOr types.path; + }; + + certFile = mkOption { + description = "Cert file to use for clients"; + default = null; + type = types.nullOr types.path; + }; + + keyFile = mkOption { + description = "Key file to use for clients"; + default = null; + type = types.nullOr types.path; + }; + + peerCertFile = mkOption { + description = "Cert file to use for peer to peer communication"; + default = cfg.certFile; + type = types.nullOr types.path; + }; + + peerKeyFile = mkOption { + description = "Key file to use for peer to peer communication"; + default = cfg.keyFile; + type = types.nullOr types.path; + }; + + peerTrustedCaFile = mkOption { + description = "Certificate authority file to use for peer to peer communication"; + default = cfg.trustedCaFile; + type = types.nullOr types.path; + }; + + peerClientCertAuth = mkOption { + description = "Whether to check all incoming peer requests from the cluster for valid client certificates signed by the supplied CA"; + default = false; + type = types.bool; + }; + extraConf = mkOption { description = '' Etcd extra configuration. See @@ -99,7 +147,7 @@ in { wantedBy = [ "multi-user.target" ]; after = [ "network-interfaces.target" ]; - environment = { + environment = (filterAttrs (n: v: v != null) { ETCD_NAME = cfg.name; ETCD_DISCOVERY = cfg.discovery; ETCD_DATA_DIR = cfg.dataDir; @@ -107,7 +155,14 @@ in { ETCD_LISTEN_CLIENT_URLS = concatStringsSep "," cfg.listenClientUrls; ETCD_LISTEN_PEER_URLS = concatStringsSep "," cfg.listenPeerUrls; ETCD_INITIAL_ADVERTISE_PEER_URLS = concatStringsSep "," cfg.initialAdvertisePeerUrls; - } // (optionalAttrs (cfg.discovery == ""){ + ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile; + ETCD_PEER_CERT_FILE = cfg.peerCertFile; + ETCD_PEER_KEY_FILE = cfg.peerKeyFile; + ETCD_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth; + ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile; + ETCD_CERT_FILE = cfg.certFile; + ETCD_KEY_FILE = cfg.keyFile; + }) // (optionalAttrs (cfg.discovery == ""){ ETCD_INITIAL_CLUSTER = concatStringsSep "," cfg.initialCluster; ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState; ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken; diff --git a/nixos/tests/etcd.nix b/nixos/tests/etcd.nix index bac4ec6a918..4eca6558dde 100644 --- a/nixos/tests/etcd.nix +++ b/nixos/tests/etcd.nix @@ -1,111 +1,128 @@ -# This test runs etcd as single node, multy node and using discovery +# This test runs simple etcd cluster -import ./make-test.nix ({ pkgs, ... } : { +import ./make-test.nix ({ pkgs, ... } : let + certs = pkgs.runCommand "certs" { + buildInputs = [pkgs.openssl]; + } '' + mkdir -p $out + openssl genrsa -out $out/ca-key.pem 2048 + openssl req -x509 -new -nodes -key $out/ca-key.pem -days 10000 -out $out/ca.pem -subj "/CN=etcd-ca" + + cat << EOF > openssl.cnf + ions = v3_req + distinguished_name = req_distinguished_name + [req_distinguished_name] + [ v3_req ] + basicConstraints = CA:FALSE + keyUsage = digitalSignature, keyEncipherment + extendedKeyUsage = serverAuth + subjectAltName = @alt_names + [alt_names] + DNS.1 = node1 + DNS.2 = node2 + DNS.3 = node3 + IP.1 = 127.0.0.1 + EOF + + openssl genrsa -out $out/etcd-key.pem 2048 + openssl req -new -key $out/etcd-key.pem -out etcd.csr -subj "/CN=etcd" -config openssl.cnf + openssl x509 -req -in etcd.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd.pem -days 365 -extensions v3_req -extfile openssl.cnf + + cat << EOF > client-openssl.cnf + ions = v3_req + distinguished_name = req_distinguished_name + [req_distinguished_name] + [ v3_req ] + basicConstraints = CA:FALSE + keyUsage = digitalSignature, keyEncipherment + extendedKeyUsage = clientAuth + EOF + + openssl genrsa -out $out/etcd-client-key.pem 2048 + openssl req -new -key $out/etcd-client-key.pem -out etcd-client.csr -subj "/CN=etcd-client" -config client-openssl.cnf + openssl x509 -req -in etcd-client.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd-client.pem -days 365 -extensions v3_req -extfile client-openssl.cnf + ''; + + nodeConfig = { + services = { + etcd = { + enable = true; + keyFile = "${certs}/etcd-key.pem"; + certFile = "${certs}/etcd.pem"; + trustedCaFile = "${certs}/ca.pem"; + peerClientCertAuth = true; + listenClientUrls = ["https://127.0.0.1:2379"]; + listenPeerUrls = ["https://0.0.0.0:2380"]; + }; + }; + + environment.variables = { + ETCDCTL_CERT_FILE = "${certs}/etcd-client.pem"; + ETCDCTL_KEY_FILE = "${certs}/etcd-client-key.pem"; + ETCDCTL_CA_FILE = "${certs}/ca.pem"; + ETCDCTL_PEERS = "https://127.0.0.1:2379"; + }; + + networking.firewall.allowedTCPPorts = [ 2380 ]; + }; +in { name = "etcd"; + meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ offline ]; }; nodes = { - simple = - { config, pkgs, nodes, ... }: - { - services.etcd.enable = true; - services.etcd.listenClientUrls = ["http://0.0.0.0:4001"]; - environment.systemPackages = [ pkgs.curl ]; - networking.firewall.allowedTCPPorts = [ 4001 ]; - }; - - - node1 = - { config, pkgs, nodes, ... }: - { - services = { - etcd = { - enable = true; - listenPeerUrls = ["http://0.0.0.0:7001"]; - initialAdvertisePeerUrls = ["http://node1:7001"]; - initialCluster = ["node1=http://node1:7001" "node2=http://node2:7001"]; - }; - }; - - networking.firewall.allowedTCPPorts = [ 7001 ]; - }; - - node2 = - { config, pkgs, ... }: - { - services = { - etcd = { - enable = true; - listenPeerUrls = ["http://0.0.0.0:7001"]; - initialAdvertisePeerUrls = ["http://node2:7001"]; - initialCluster = ["node1=http://node1:7001" "node2=http://node2:7001"]; - }; - }; - - networking.firewall.allowedTCPPorts = [ 7001 ]; - }; - - discovery1 = - { config, pkgs, nodes, ... }: - { - services = { - etcd = { - enable = true; - listenPeerUrls = ["http://0.0.0.0:7001"]; - initialAdvertisePeerUrls = ["http://discovery1:7001"]; - discovery = "http://simple:4001/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/"; - }; - }; - - networking.firewall.allowedTCPPorts = [ 7001 ]; - }; - - discovery2 = - { config, pkgs, ... }: - { - services = { - etcd = { - enable = true; - listenPeerUrls = ["http://0.0.0.0:7001"]; - initialAdvertisePeerUrls = ["http://discovery2:7001"]; - discovery = "http://simple:4001/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/"; - }; - }; - - networking.firewall.allowedTCPPorts = [ 7001 ]; - }; + node1 = { config, pkgs, nodes, ... }: { + require = [nodeConfig]; + services.etcd = { + initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380"]; + initialAdvertisePeerUrls = ["https://node1:2380"]; + }; }; + node2 = { config, pkgs, ... }: { + require = [nodeConfig]; + services.etcd = { + initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380"]; + initialAdvertisePeerUrls = ["https://node2:2380"]; + }; + }; + + node3 = { config, pkgs, ... }: { + require = [nodeConfig]; + services.etcd = { + initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380" "node3=https://node3:2380"]; + initialAdvertisePeerUrls = ["https://node3:2380"]; + initialClusterState = "existing"; + }; + }; + }; + testScript = '' - subtest "single node", sub { - $simple->start(); - $simple->waitForUnit("etcd.service"); - $simple->waitUntilSucceeds("etcdctl set /foo/bar 'Hello world'"); - $simple->waitUntilSucceeds("etcdctl get /foo/bar | grep 'Hello world'"); - }; - - subtest "multy node", sub { + subtest "should start etcd cluster", sub { $node1->start(); $node2->start(); $node1->waitForUnit("etcd.service"); $node2->waitForUnit("etcd.service"); - $node1->waitUntilSucceeds("etcdctl set /foo/bar 'Hello world'"); - $node2->waitUntilSucceeds("etcdctl get /foo/bar | grep 'Hello world'"); - $node1->shutdown(); - $node2->shutdown(); + $node2->waitUntilSucceeds("etcdctl cluster-health"); + $node1->succeed("etcdctl set /foo/bar 'Hello world'"); + $node2->succeed("etcdctl get /foo/bar | grep 'Hello world'"); }; - subtest "discovery", sub { - $simple->succeed("curl -X PUT http://localhost:4001/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=2"); + subtest "should add another member", sub { + $node1->succeed("etcdctl member add node3 https://node3:2380"); + $node3->start(); + $node3->waitForUnit("etcd.service"); + $node3->waitUntilSucceeds("etcdctl member list | grep 'node3'"); + $node3->succeed("etcdctl cluster-health"); + }; - $discovery1->start(); - $discovery2->start(); - $discovery1->waitForUnit("etcd.service"); - $discovery2->waitForUnit("etcd.service"); - $discovery1->waitUntilSucceeds("etcdctl set /foo/bar 'Hello world'"); - $discovery2->waitUntilSucceeds("etcdctl get /foo/bar | grep 'Hello world'"); + subtest "should survive member crash", sub { + $node3->crash; + $node1->succeed("etcdctl cluster-health"); + $node1->succeed("etcdctl set /foo/bar 'Hello degraded world'"); + $node1->succeed("etcdctl get /foo/bar | grep 'Hello degraded world'"); }; ''; }) From 0630233afa6440473f0c04825f252c508e8c534b Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Thu, 25 Aug 2016 14:41:47 +0200 Subject: [PATCH 3/6] etcd module: add test for simple one node etcd service --- nixos/modules/services/misc/etcd.nix | 4 +- nixos/tests/etcd-cluster.nix | 128 +++++++++++++++++++++++++++ nixos/tests/etcd.nix | 123 +++---------------------- 3 files changed, 141 insertions(+), 114 deletions(-) create mode 100644 nixos/tests/etcd-cluster.nix diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix index 8a12e183aa3..d30cc5fd7e8 100644 --- a/nixos/modules/services/misc/etcd.nix +++ b/nixos/modules/services/misc/etcd.nix @@ -28,13 +28,13 @@ in { listenClientUrls = mkOption { description = "Etcd list of URLs to listen on for client traffic."; - default = ["http://localhost:2379"]; + default = ["http://127.0.0.1:2379"]; type = types.listOf types.str; }; listenPeerUrls = mkOption { description = "Etcd list of URLs to listen on for peer traffic."; - default = ["http://localhost:2380"]; + default = ["http://127.0.0.1:2380"]; type = types.listOf types.str; }; diff --git a/nixos/tests/etcd-cluster.nix b/nixos/tests/etcd-cluster.nix new file mode 100644 index 00000000000..4eca6558dde --- /dev/null +++ b/nixos/tests/etcd-cluster.nix @@ -0,0 +1,128 @@ +# This test runs simple etcd cluster + +import ./make-test.nix ({ pkgs, ... } : let + certs = pkgs.runCommand "certs" { + buildInputs = [pkgs.openssl]; + } '' + mkdir -p $out + openssl genrsa -out $out/ca-key.pem 2048 + openssl req -x509 -new -nodes -key $out/ca-key.pem -days 10000 -out $out/ca.pem -subj "/CN=etcd-ca" + + cat << EOF > openssl.cnf + ions = v3_req + distinguished_name = req_distinguished_name + [req_distinguished_name] + [ v3_req ] + basicConstraints = CA:FALSE + keyUsage = digitalSignature, keyEncipherment + extendedKeyUsage = serverAuth + subjectAltName = @alt_names + [alt_names] + DNS.1 = node1 + DNS.2 = node2 + DNS.3 = node3 + IP.1 = 127.0.0.1 + EOF + + openssl genrsa -out $out/etcd-key.pem 2048 + openssl req -new -key $out/etcd-key.pem -out etcd.csr -subj "/CN=etcd" -config openssl.cnf + openssl x509 -req -in etcd.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd.pem -days 365 -extensions v3_req -extfile openssl.cnf + + cat << EOF > client-openssl.cnf + ions = v3_req + distinguished_name = req_distinguished_name + [req_distinguished_name] + [ v3_req ] + basicConstraints = CA:FALSE + keyUsage = digitalSignature, keyEncipherment + extendedKeyUsage = clientAuth + EOF + + openssl genrsa -out $out/etcd-client-key.pem 2048 + openssl req -new -key $out/etcd-client-key.pem -out etcd-client.csr -subj "/CN=etcd-client" -config client-openssl.cnf + openssl x509 -req -in etcd-client.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd-client.pem -days 365 -extensions v3_req -extfile client-openssl.cnf + ''; + + nodeConfig = { + services = { + etcd = { + enable = true; + keyFile = "${certs}/etcd-key.pem"; + certFile = "${certs}/etcd.pem"; + trustedCaFile = "${certs}/ca.pem"; + peerClientCertAuth = true; + listenClientUrls = ["https://127.0.0.1:2379"]; + listenPeerUrls = ["https://0.0.0.0:2380"]; + }; + }; + + environment.variables = { + ETCDCTL_CERT_FILE = "${certs}/etcd-client.pem"; + ETCDCTL_KEY_FILE = "${certs}/etcd-client-key.pem"; + ETCDCTL_CA_FILE = "${certs}/ca.pem"; + ETCDCTL_PEERS = "https://127.0.0.1:2379"; + }; + + networking.firewall.allowedTCPPorts = [ 2380 ]; + }; +in { + name = "etcd"; + + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ offline ]; + }; + + nodes = { + node1 = { config, pkgs, nodes, ... }: { + require = [nodeConfig]; + services.etcd = { + initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380"]; + initialAdvertisePeerUrls = ["https://node1:2380"]; + }; + }; + + node2 = { config, pkgs, ... }: { + require = [nodeConfig]; + services.etcd = { + initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380"]; + initialAdvertisePeerUrls = ["https://node2:2380"]; + }; + }; + + node3 = { config, pkgs, ... }: { + require = [nodeConfig]; + services.etcd = { + initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380" "node3=https://node3:2380"]; + initialAdvertisePeerUrls = ["https://node3:2380"]; + initialClusterState = "existing"; + }; + }; + }; + + testScript = '' + subtest "should start etcd cluster", sub { + $node1->start(); + $node2->start(); + $node1->waitForUnit("etcd.service"); + $node2->waitForUnit("etcd.service"); + $node2->waitUntilSucceeds("etcdctl cluster-health"); + $node1->succeed("etcdctl set /foo/bar 'Hello world'"); + $node2->succeed("etcdctl get /foo/bar | grep 'Hello world'"); + }; + + subtest "should add another member", sub { + $node1->succeed("etcdctl member add node3 https://node3:2380"); + $node3->start(); + $node3->waitForUnit("etcd.service"); + $node3->waitUntilSucceeds("etcdctl member list | grep 'node3'"); + $node3->succeed("etcdctl cluster-health"); + }; + + subtest "should survive member crash", sub { + $node3->crash; + $node1->succeed("etcdctl cluster-health"); + $node1->succeed("etcdctl set /foo/bar 'Hello degraded world'"); + $node1->succeed("etcdctl get /foo/bar | grep 'Hello degraded world'"); + }; + ''; +}) diff --git a/nixos/tests/etcd.nix b/nixos/tests/etcd.nix index 4eca6558dde..f8a6791a834 100644 --- a/nixos/tests/etcd.nix +++ b/nixos/tests/etcd.nix @@ -1,71 +1,6 @@ -# This test runs simple etcd cluster +# This test runs simple etcd node -import ./make-test.nix ({ pkgs, ... } : let - certs = pkgs.runCommand "certs" { - buildInputs = [pkgs.openssl]; - } '' - mkdir -p $out - openssl genrsa -out $out/ca-key.pem 2048 - openssl req -x509 -new -nodes -key $out/ca-key.pem -days 10000 -out $out/ca.pem -subj "/CN=etcd-ca" - - cat << EOF > openssl.cnf - ions = v3_req - distinguished_name = req_distinguished_name - [req_distinguished_name] - [ v3_req ] - basicConstraints = CA:FALSE - keyUsage = digitalSignature, keyEncipherment - extendedKeyUsage = serverAuth - subjectAltName = @alt_names - [alt_names] - DNS.1 = node1 - DNS.2 = node2 - DNS.3 = node3 - IP.1 = 127.0.0.1 - EOF - - openssl genrsa -out $out/etcd-key.pem 2048 - openssl req -new -key $out/etcd-key.pem -out etcd.csr -subj "/CN=etcd" -config openssl.cnf - openssl x509 -req -in etcd.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd.pem -days 365 -extensions v3_req -extfile openssl.cnf - - cat << EOF > client-openssl.cnf - ions = v3_req - distinguished_name = req_distinguished_name - [req_distinguished_name] - [ v3_req ] - basicConstraints = CA:FALSE - keyUsage = digitalSignature, keyEncipherment - extendedKeyUsage = clientAuth - EOF - - openssl genrsa -out $out/etcd-client-key.pem 2048 - openssl req -new -key $out/etcd-client-key.pem -out etcd-client.csr -subj "/CN=etcd-client" -config client-openssl.cnf - openssl x509 -req -in etcd-client.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd-client.pem -days 365 -extensions v3_req -extfile client-openssl.cnf - ''; - - nodeConfig = { - services = { - etcd = { - enable = true; - keyFile = "${certs}/etcd-key.pem"; - certFile = "${certs}/etcd.pem"; - trustedCaFile = "${certs}/ca.pem"; - peerClientCertAuth = true; - listenClientUrls = ["https://127.0.0.1:2379"]; - listenPeerUrls = ["https://0.0.0.0:2380"]; - }; - }; - - environment.variables = { - ETCDCTL_CERT_FILE = "${certs}/etcd-client.pem"; - ETCDCTL_KEY_FILE = "${certs}/etcd-client-key.pem"; - ETCDCTL_CA_FILE = "${certs}/ca.pem"; - ETCDCTL_PEERS = "https://127.0.0.1:2379"; - }; - - networking.firewall.allowedTCPPorts = [ 2380 ]; - }; -in { +import ./make-test.nix ({ pkgs, ... } : { name = "etcd"; meta = with pkgs.stdenv.lib.maintainers; { @@ -73,56 +8,20 @@ in { }; nodes = { - node1 = { config, pkgs, nodes, ... }: { - require = [nodeConfig]; - services.etcd = { - initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380"]; - initialAdvertisePeerUrls = ["https://node1:2380"]; - }; - }; - - node2 = { config, pkgs, ... }: { - require = [nodeConfig]; - services.etcd = { - initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380"]; - initialAdvertisePeerUrls = ["https://node2:2380"]; - }; - }; - - node3 = { config, pkgs, ... }: { - require = [nodeConfig]; - services.etcd = { - initialCluster = ["node1=https://node1:2380" "node2=https://node2:2380" "node3=https://node3:2380"]; - initialAdvertisePeerUrls = ["https://node3:2380"]; - initialClusterState = "existing"; - }; + node = { config, pkgs, nodes, ... }: { + services.etcd.enable = true; }; }; testScript = '' - subtest "should start etcd cluster", sub { - $node1->start(); - $node2->start(); - $node1->waitForUnit("etcd.service"); - $node2->waitForUnit("etcd.service"); - $node2->waitUntilSucceeds("etcdctl cluster-health"); - $node1->succeed("etcdctl set /foo/bar 'Hello world'"); - $node2->succeed("etcdctl get /foo/bar | grep 'Hello world'"); + subtest "should start etcd node", sub { + $node->start(); + $node->waitForUnit("etcd.service"); }; - subtest "should add another member", sub { - $node1->succeed("etcdctl member add node3 https://node3:2380"); - $node3->start(); - $node3->waitForUnit("etcd.service"); - $node3->waitUntilSucceeds("etcdctl member list | grep 'node3'"); - $node3->succeed("etcdctl cluster-health"); - }; - - subtest "should survive member crash", sub { - $node3->crash; - $node1->succeed("etcdctl cluster-health"); - $node1->succeed("etcdctl set /foo/bar 'Hello degraded world'"); - $node1->succeed("etcdctl get /foo/bar | grep 'Hello degraded world'"); - }; + subtest "should write and read some values to etcd", sub { + $node->succeed("etcdctl set /foo/bar 'Hello world'"); + $node->succeed("etcdctl get /foo/bar | grep 'Hello world'"); + } ''; }) From ff5fd1ec401051eb5c259846e4ecd19a0d29a80d Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 26 Aug 2016 22:23:27 -0400 Subject: [PATCH 4/6] etcd-cluster: split up openssl commands --- nixos/tests/etcd-cluster.nix | 77 +++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/nixos/tests/etcd-cluster.nix b/nixos/tests/etcd-cluster.nix index 4eca6558dde..3971997a9bf 100644 --- a/nixos/tests/etcd-cluster.nix +++ b/nixos/tests/etcd-cluster.nix @@ -1,14 +1,52 @@ # This test runs simple etcd cluster import ./make-test.nix ({ pkgs, ... } : let - certs = pkgs.runCommand "certs" { - buildInputs = [pkgs.openssl]; - } '' - mkdir -p $out - openssl genrsa -out $out/ca-key.pem 2048 - openssl req -x509 -new -nodes -key $out/ca-key.pem -days 10000 -out $out/ca.pem -subj "/CN=etcd-ca" - cat << EOF > openssl.cnf + runWithOpenSSL = file: cmd: pkgs.runCommand file { + buildInputs = [ pkgs.openssl ]; + } cmd; + + ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048"; + ca_pem = runWithOpenSSL "ca.pem" '' + openssl req \ + -x509 -new -nodes -key ${ca_key} \ + -days 10000 -out $out -subj "/CN=etcd-ca" + ''; + etcd_key = runWithOpenSSL "etcd-key.pem" "openssl genrsa -out $out 2048"; + etcd_csr = runWithOpenSSL "etcd.csr" '' + openssl req \ + -new -key ${etcd_key} \ + -out $out -subj "/CN=etcd" \ + -config ${openssl_cnf} + ''; + etcd_cert = runWithOpenSSL "etcd.pem" '' + openssl x509 \ + -req -in ${etcd_csr} \ + -CA ${ca_pem} -CAkey ${ca_key} \ + -CAcreateserial -out $out \ + -days 365 -extensions v3_req \ + -extfile ${openssl_cnf} + ''; + + etcd_client_key = runWithOpenSSL "etcd-client-key.pem" + "openssl genrsa -out $out 2048"; + + etcd_client_csr = runWithOpenSSL "etcd-client-key.pem" '' + openssl req \ + -new -key ${etcd_client_key} \ + -out $out -subj "/CN=etcd-client" \ + -config ${client_openssl_cnf} + ''; + + etcd_client_cert = runWithOpenSSL "etcd-client.crt" '' + openssl x509 \ + -req -in ${etcd_client_csr} \ + -CA ${ca_pem} -CAkey ${ca_key} -CAcreateserial \ + -out $out -days 365 -extensions v3_req \ + -extfile ${client_openssl_cnf} + ''; + + openssl_cnf = pkgs.writeText "openssl.cnf" '' ions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] @@ -22,13 +60,9 @@ import ./make-test.nix ({ pkgs, ... } : let DNS.2 = node2 DNS.3 = node3 IP.1 = 127.0.0.1 - EOF + ''; - openssl genrsa -out $out/etcd-key.pem 2048 - openssl req -new -key $out/etcd-key.pem -out etcd.csr -subj "/CN=etcd" -config openssl.cnf - openssl x509 -req -in etcd.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd.pem -days 365 -extensions v3_req -extfile openssl.cnf - - cat << EOF > client-openssl.cnf + client_openssl_cnf = pkgs.writeText "client-openssl.cnf" '' ions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] @@ -36,20 +70,15 @@ import ./make-test.nix ({ pkgs, ... } : let basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuth - EOF - - openssl genrsa -out $out/etcd-client-key.pem 2048 - openssl req -new -key $out/etcd-client-key.pem -out etcd-client.csr -subj "/CN=etcd-client" -config client-openssl.cnf - openssl x509 -req -in etcd-client.csr -CA $out/ca.pem -CAkey $out/ca-key.pem -CAcreateserial -out $out/etcd-client.pem -days 365 -extensions v3_req -extfile client-openssl.cnf ''; nodeConfig = { services = { etcd = { enable = true; - keyFile = "${certs}/etcd-key.pem"; - certFile = "${certs}/etcd.pem"; - trustedCaFile = "${certs}/ca.pem"; + keyFile = etcd_key; + certFile = etcd_cert; + trustedCaFile = ca_pem; peerClientCertAuth = true; listenClientUrls = ["https://127.0.0.1:2379"]; listenPeerUrls = ["https://0.0.0.0:2380"]; @@ -57,9 +86,9 @@ import ./make-test.nix ({ pkgs, ... } : let }; environment.variables = { - ETCDCTL_CERT_FILE = "${certs}/etcd-client.pem"; - ETCDCTL_KEY_FILE = "${certs}/etcd-client-key.pem"; - ETCDCTL_CA_FILE = "${certs}/ca.pem"; + ETCDCTL_CERT_FILE = "${etcd_client_cert}"; + ETCDCTL_KEY_FILE = "${etcd_client_key}"; + ETCDCTL_CA_FILE = "${ca_pem}"; ETCDCTL_PEERS = "https://127.0.0.1:2379"; }; From 235440ec34411a62ccb455fc9537f92999dff618 Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Sat, 3 Sep 2016 14:02:53 +0200 Subject: [PATCH 5/6] etcd: add meta information --- pkgs/servers/etcd/default.nix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkgs/servers/etcd/default.nix b/pkgs/servers/etcd/default.nix index 57eb877cd79..988f6f6c82c 100644 --- a/pkgs/servers/etcd/default.nix +++ b/pkgs/servers/etcd/default.nix @@ -1,5 +1,7 @@ { stdenv, lib, libpcap, buildGoPackage, fetchFromGitHub }: +with lib; + buildGoPackage rec { name = "etcd-${version}"; version = "3.0.6"; @@ -17,4 +19,12 @@ buildGoPackage rec { goDeps = ./deps.json; buildInputs = [ libpcap ]; + + meta = { + description = "Distributed reliable key-value store for the most critical data of a distributed system"; + license = licenses.asl20; + homepage = https://coreos.com/etcd/; + maintainers = with maintainers; [offline]; + platforms = with platforms; linux; + }; } From eaf4dcaee1a092072cc7ee36ba1e82dc1e46a9dd Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Sat, 3 Sep 2016 14:04:54 +0200 Subject: [PATCH 6/6] etcd: add update notice --- pkgs/servers/etcd/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/servers/etcd/default.nix b/pkgs/servers/etcd/default.nix index 988f6f6c82c..3d301a6a35b 100644 --- a/pkgs/servers/etcd/default.nix +++ b/pkgs/servers/etcd/default.nix @@ -4,7 +4,7 @@ with lib; buildGoPackage rec { name = "etcd-${version}"; - version = "3.0.6"; + version = "3.0.6"; # After updating check that nixos tests pass rev = "v${version}"; goPackagePath = "github.com/coreos/etcd";