parent
bcf9da32f7
commit
b3bc157f7f
@ -0,0 +1,141 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.etcd; |
||||
|
||||
in { |
||||
|
||||
options.services.etcd = { |
||||
enable = mkOption { |
||||
description = "Whether to enable etcd."; |
||||
default = false; |
||||
type = types.uniq types.bool; |
||||
}; |
||||
|
||||
name = mkOption { |
||||
description = "Etcd unique node name."; |
||||
default = config.networking.hostName; |
||||
type = types.str; |
||||
}; |
||||
|
||||
advertiseClientUrls = mkOption { |
||||
description = "Etcd list of this member's client URLs to advertise to the rest of the cluster."; |
||||
default = cfg.listenClientUrls; |
||||
type = types.listOf types.str; |
||||
}; |
||||
|
||||
listenClientUrls = mkOption { |
||||
description = "Etcd list of URLs to listen on for client traffic."; |
||||
default = ["http://localhost:2379" "http://localhost:4001"]; |
||||
type = types.listOf types.str; |
||||
}; |
||||
|
||||
listenPeerUrls = mkOption { |
||||
description = "Etcd list of URLs to listen on for peer traffic."; |
||||
default = ["http://localhost:2380" "http://localhost:7001"]; |
||||
type = types.listOf types.str; |
||||
}; |
||||
|
||||
initialAdvertisePeerUrls = mkOption { |
||||
description = "Etcd list of this member's peer URLs to advertise to rest of the cluster."; |
||||
default = cfg.listenPeerUrls; |
||||
type = types.listOf types.str; |
||||
}; |
||||
|
||||
initialCluster = mkOption { |
||||
description = "Etcd initial cluster configuration for bootstrapping."; |
||||
default = ["${cfg.name}=http://localhost:2380" "${cfg.name}=http://localhost:7001"]; |
||||
type = types.listOf types.str; |
||||
}; |
||||
|
||||
initialClusterState = mkOption { |
||||
description = "Etcd initial cluster configuration for bootstrapping."; |
||||
default = "new"; |
||||
type = types.enum ["new" "existing"]; |
||||
}; |
||||
|
||||
initialClusterToken = mkOption { |
||||
description = "Etcd initial cluster token for etcd cluster during bootstrap."; |
||||
default = "etcd-cluster"; |
||||
type = types.str; |
||||
}; |
||||
|
||||
discovery = mkOption { |
||||
description = "Etcd discovery url"; |
||||
default = ""; |
||||
type = types.str; |
||||
}; |
||||
|
||||
extraConf = mkOption { |
||||
description = '' |
||||
Etcd extra configuration. See |
||||
<link xlink:href='https://github.com/coreos/etcd/blob/master/Documentation/configuration.md#environment-variables' /> |
||||
''; |
||||
type = types.attrsOf types.str; |
||||
default = {}; |
||||
example = literalExample '' |
||||
{ |
||||
"CORS": "*", |
||||
"NAME": "default-name", |
||||
"MAX_RESULT_BUFFER": "1024", |
||||
"MAX_CLUSTER_SIZE": "9", |
||||
"MAX_RETRY_ATTEMPTS": "3" |
||||
} |
||||
''; |
||||
}; |
||||
|
||||
dataDir = mkOption { |
||||
type = types.path; |
||||
default = "/var/lib/etcd"; |
||||
description = "Etcd data directory."; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
systemd.services.etcd = { |
||||
description = "Etcd Daemon"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network-interfaces.target" ]; |
||||
|
||||
environment = { |
||||
ETCD_NAME = cfg.name; |
||||
ETCD_DISCOVERY = cfg.discovery; |
||||
ETCD_DATA_DIR = cfg.dataDir; |
||||
ETCD_ADVERTISE_CLIENT_URLS = concatStringsSep "," cfg.advertiseClientUrls; |
||||
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_INITIAL_CLUSTER = concatStringsSep "," cfg.initialCluster; |
||||
ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState; |
||||
ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken; |
||||
}) // (mapAttrs' (n: v: nameValuePair "ETCD_${n}" v) cfg.extraConf); |
||||
|
||||
serviceConfig = { |
||||
ExecStart = "${pkgs.etcd}/bin/etcd"; |
||||
User = "etcd"; |
||||
PermissionsStartOnly = true; |
||||
}; |
||||
preStart = '' |
||||
mkdir -m 0700 -p ${cfg.dataDir} |
||||
if [ "$(id -u)" = 0 ]; then chown etcd ${cfg.dataDir}; fi |
||||
''; |
||||
postStart = '' |
||||
until ${pkgs.curl}/bin/curl -s -o /dev/null '${head cfg.listenClientUrls}/version'; do |
||||
sleep 1; |
||||
done |
||||
''; |
||||
}; |
||||
|
||||
environment.systemPackages = [ pkgs.etcdctl ]; |
||||
|
||||
users.extraUsers = singleton { |
||||
name = "etcd"; |
||||
uid = config.ids.uids.etcd; |
||||
description = "Etcd daemon user"; |
||||
home = cfg.dataDir; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,108 @@ |
||||
# This test runs etcd as single node, multy node and using discovery |
||||
|
||||
import ./make-test.nix { |
||||
name = "etcd"; |
||||
|
||||
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 ]; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
subtest "single node", sub { |
||||
$simple->start(); |
||||
$simple->waitForUnit("etcd.service"); |
||||
$simple->succeed("etcdctl set /foo/bar 'Hello world'"); |
||||
$simple->succeed("etcdctl get /foo/bar | grep 'Hello world'"); |
||||
}; |
||||
|
||||
subtest "multy node", sub { |
||||
$node1->start(); |
||||
$node2->start(); |
||||
$node1->waitForUnit("etcd.service"); |
||||
$node2->waitForUnit("etcd.service"); |
||||
$node1->succeed("etcdctl set /foo/bar 'Hello world'"); |
||||
$node2->succeed("etcdctl get /foo/bar | grep 'Hello world'"); |
||||
$node1->shutdown(); |
||||
$node2->shutdown(); |
||||
}; |
||||
|
||||
subtest "discovery", sub { |
||||
$simple->succeed("curl -X PUT http://localhost:4001/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=2"); |
||||
|
||||
$discovery1->start(); |
||||
$discovery2->start(); |
||||
$discovery1->waitForUnit("etcd.service"); |
||||
$discovery2->waitForUnit("etcd.service"); |
||||
$discovery1->succeed("etcdctl set /foo/bar 'Hello world'"); |
||||
$discovery2->succeed("etcdctl get /foo/bar | grep 'Hello world'"); |
||||
}; |
||||
''; |
||||
} |
Loading…
Reference in new issue