nixosTests.etcd-cluster: handleTest -> runTest

This commit is contained in:
Sizhe Zhao 2025-06-07 21:31:41 +08:00
parent 969bed3f90
commit 748a3d5266
No known key found for this signature in database
GPG Key ID: ED1807251A7DA08F
2 changed files with 155 additions and 160 deletions

View File

@ -474,7 +474,7 @@ in
activation-etc-overlay-immutable = runTest ./activation/etc-overlay-immutable.nix; activation-etc-overlay-immutable = runTest ./activation/etc-overlay-immutable.nix;
activation-perlless = runTest ./activation/perlless.nix; activation-perlless = runTest ./activation/perlless.nix;
etcd = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd.nix; etcd = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd.nix;
etcd-cluster = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd-cluster.nix { }; etcd-cluster = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd-cluster.nix;
etebase-server = runTest ./etebase-server.nix; etebase-server = runTest ./etebase-server.nix;
etesync-dav = runTest ./etesync-dav.nix; etesync-dav = runTest ./etesync-dav.nix;
evcc = runTest ./evcc.nix; evcc = runTest ./evcc.nix;

View File

@ -1,178 +1,173 @@
# This test runs simple etcd cluster # This test runs simple etcd cluster
import ../make-test-python.nix ( { lib, pkgs, ... }:
{ pkgs, ... }: let
let runWithOpenSSL =
file: cmd:
pkgs.runCommand file {
buildInputs = [ pkgs.openssl ];
} cmd;
runWithOpenSSL = ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048";
file: cmd: ca_pem = runWithOpenSSL "ca.pem" ''
pkgs.runCommand file { openssl req \
buildInputs = [ pkgs.openssl ]; -x509 -new -nodes -key ${ca_key} \
} cmd; -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}
'';
ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048"; etcd_client_key = runWithOpenSSL "etcd-client-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_csr = runWithOpenSSL "etcd-client-key.pem" '' etcd_client_cert = runWithOpenSSL "etcd-client.crt" ''
openssl req \ openssl x509 \
-new -key ${etcd_client_key} \ -req -in ${etcd_client_csr} \
-out $out -subj "/CN=etcd-client" \ -CA ${ca_pem} -CAkey ${ca_key} -CAcreateserial \
-config ${client_openssl_cnf} -out $out -days 365 -extensions v3_req \
''; -extfile ${client_openssl_cnf}
'';
etcd_client_cert = runWithOpenSSL "etcd-client.crt" '' openssl_cnf = pkgs.writeText "openssl.cnf" ''
openssl x509 \ ions = v3_req
-req -in ${etcd_client_csr} \ distinguished_name = req_distinguished_name
-CA ${ca_pem} -CAkey ${ca_key} -CAcreateserial \ [req_distinguished_name]
-out $out -days 365 -extensions v3_req \ [ v3_req ]
-extfile ${client_openssl_cnf} basicConstraints = CA:FALSE
''; keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = node1
DNS.2 = node2
DNS.3 = node3
IP.1 = 127.0.0.1
'';
openssl_cnf = pkgs.writeText "openssl.cnf" '' client_openssl_cnf = pkgs.writeText "client-openssl.cnf" ''
ions = v3_req ions = v3_req
distinguished_name = req_distinguished_name distinguished_name = req_distinguished_name
[req_distinguished_name] [req_distinguished_name]
[ v3_req ] [ v3_req ]
basicConstraints = CA:FALSE basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth extendedKeyUsage = clientAuth
subjectAltName = @alt_names '';
[alt_names]
DNS.1 = node1
DNS.2 = node2
DNS.3 = node3
IP.1 = 127.0.0.1
'';
client_openssl_cnf = pkgs.writeText "client-openssl.cnf" '' nodeConfig = {
ions = v3_req services = {
distinguished_name = req_distinguished_name etcd = {
[req_distinguished_name] enable = true;
[ v3_req ] keyFile = etcd_key;
basicConstraints = CA:FALSE certFile = etcd_cert;
keyUsage = digitalSignature, keyEncipherment trustedCaFile = ca_pem;
extendedKeyUsage = clientAuth clientCertAuth = true;
''; listenClientUrls = [ "https://127.0.0.1:2379" ];
listenPeerUrls = [ "https://0.0.0.0:2380" ];
};
};
nodeConfig = { environment.variables = {
services = { ETCD_CERT_FILE = "${etcd_client_cert}";
etcd = { ETCD_KEY_FILE = "${etcd_client_key}";
enable = true; ETCD_CA_FILE = "${ca_pem}";
keyFile = etcd_key; ETCDCTL_ENDPOINTS = "https://127.0.0.1:2379";
certFile = etcd_cert; ETCDCTL_CACERT = "${ca_pem}";
trustedCaFile = ca_pem; ETCDCTL_CERT = "${etcd_cert}";
clientCertAuth = true; ETCDCTL_KEY = "${etcd_key}";
listenClientUrls = [ "https://127.0.0.1:2379" ]; };
listenPeerUrls = [ "https://0.0.0.0:2380" ];
networking.firewall.allowedTCPPorts = [ 2380 ];
};
in
{
name = "etcd-cluster";
meta.maintainers = with lib.maintainers; [ offline ];
nodes = {
node1 =
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
];
initialAdvertisePeerUrls = [ "https://node1:2380" ];
}; };
}; };
environment.variables = { node2 =
ETCD_CERT_FILE = "${etcd_client_cert}"; { ... }:
ETCD_KEY_FILE = "${etcd_client_key}"; {
ETCD_CA_FILE = "${ca_pem}"; require = [ nodeConfig ];
ETCDCTL_ENDPOINTS = "https://127.0.0.1:2379"; services.etcd = {
ETCDCTL_CACERT = "${ca_pem}"; initialCluster = [
ETCDCTL_CERT = "${etcd_cert}"; "node1=https://node1:2380"
ETCDCTL_KEY = "${etcd_key}"; "node2=https://node2:2380"
];
initialAdvertisePeerUrls = [ "https://node2:2380" ];
};
}; };
networking.firewall.allowedTCPPorts = [ 2380 ]; node3 =
}; { ... }:
in {
{ require = [ nodeConfig ];
name = "etcd-cluster"; services.etcd = {
initialCluster = [
meta = with pkgs.lib.maintainers; { "node1=https://node1:2380"
maintainers = [ offline ]; "node2=https://node2:2380"
}; "node3=https://node3:2380"
];
nodes = { initialAdvertisePeerUrls = [ "https://node3:2380" ];
node1 = initialClusterState = "existing";
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
];
initialAdvertisePeerUrls = [ "https://node1:2380" ];
};
}; };
};
};
node2 = testScript = ''
{ ... }: with subtest("should start etcd cluster"):
{ node1.start()
require = [ nodeConfig ]; node2.start()
services.etcd = { node1.wait_for_unit("etcd.service")
initialCluster = [ node2.wait_for_unit("etcd.service")
"node1=https://node1:2380" node2.wait_until_succeeds("etcdctl endpoint status")
"node2=https://node2:2380" node1.succeed("etcdctl put /foo/bar 'Hello world'")
]; node2.succeed("etcdctl get /foo/bar | grep 'Hello world'")
initialAdvertisePeerUrls = [ "https://node2:2380" ];
};
};
node3 = with subtest("should add another member"):
{ ... }: node1.wait_until_succeeds("etcdctl member add node3 --peer-urls=https://node3:2380")
{ node3.start()
require = [ nodeConfig ]; node3.wait_for_unit("etcd.service")
services.etcd = { node3.wait_until_succeeds("etcdctl member list | grep 'node3'")
initialCluster = [ node3.succeed("etcdctl endpoint status")
"node1=https://node1:2380"
"node2=https://node2:2380"
"node3=https://node3:2380"
];
initialAdvertisePeerUrls = [ "https://node3:2380" ];
initialClusterState = "existing";
};
};
};
testScript = '' with subtest("should survive member crash"):
with subtest("should start etcd cluster"): node3.crash()
node1.start() node1.succeed("etcdctl endpoint status")
node2.start() node1.succeed("etcdctl put /foo/bar 'Hello degraded world'")
node1.wait_for_unit("etcd.service") node1.succeed("etcdctl get /foo/bar | grep 'Hello degraded world'")
node2.wait_for_unit("etcd.service") '';
node2.wait_until_succeeds("etcdctl endpoint status") }
node1.succeed("etcdctl put /foo/bar 'Hello world'")
node2.succeed("etcdctl get /foo/bar | grep 'Hello world'")
with subtest("should add another member"):
node1.wait_until_succeeds("etcdctl member add node3 --peer-urls=https://node3:2380")
node3.start()
node3.wait_for_unit("etcd.service")
node3.wait_until_succeeds("etcdctl member list | grep 'node3'")
node3.succeed("etcdctl endpoint status")
with subtest("should survive member crash"):
node3.crash()
node1.succeed("etcdctl endpoint status")
node1.succeed("etcdctl put /foo/bar 'Hello degraded world'")
node1.succeed("etcdctl get /foo/bar | grep 'Hello degraded world'")
'';
}
)