nixosTests: handleTest -> runTest, batch 2 (#414711)

This commit is contained in:
Aleksana
2025-07-05 01:05:09 +08:00
committed by GitHub
42 changed files with 2768 additions and 2954 deletions
+60 -39
View File
@@ -255,12 +255,12 @@ in
inherit runTest;
package = pkgs.bird3;
};
birdwatcher = handleTest ./birdwatcher.nix { };
birdwatcher = runTest ./birdwatcher.nix;
bitbox-bridge = runTest ./bitbox-bridge.nix;
bitcoind = runTest ./bitcoind.nix;
bittorrent = runTest ./bittorrent.nix;
blockbook-frontend = runTest ./blockbook-frontend.nix;
blocky = handleTest ./blocky.nix { };
blocky = runTest ./blocky.nix;
bookstack = runTest ./bookstack.nix;
boot = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./boot.nix { };
bootspec = handleTestOn [ "x86_64-linux" ] ./bootspec.nix { };
@@ -269,7 +269,7 @@ in
borgbackup = runTest ./borgbackup.nix;
borgmatic = runTest ./borgmatic.nix;
botamusique = runTest ./botamusique.nix;
bpf = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./bpf.nix { };
bpf = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./bpf.nix;
bpftune = runTest ./bpftune.nix;
breitbandmessung = runTest ./breitbandmessung.nix;
broadcast-box = runTest ./broadcast-box.nix;
@@ -283,44 +283,53 @@ in
buildkite-agents = runTest ./buildkite-agents.nix;
c2fmzq = runTest ./c2fmzq.nix;
caddy = runTest ./caddy.nix;
cadvisor = handleTestOn [ "x86_64-linux" ] ./cadvisor.nix { };
cadvisor = runTestOn [ "x86_64-linux" ] ./cadvisor.nix;
cage = runTest ./cage.nix;
cagebreak = runTest ./cagebreak.nix;
calibre-web = runTest ./calibre-web.nix;
calibre-server = import ./calibre-server.nix { inherit pkgs runTest; };
canaille = runTest ./canaille.nix;
castopod = runTest ./castopod.nix;
cassandra_4 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_4; };
cassandra = runTest {
imports = [ ./cassandra.nix ];
_module.args.getPackage = pkgs: pkgs.cassandra;
};
centrifugo = runTest ./centrifugo.nix;
ceph-multi-node = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./ceph-multi-node.nix { };
ceph-single-node = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./ceph-single-node.nix { };
ceph-single-node-bluestore = handleTestOn [
ceph-multi-node = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./ceph-multi-node.nix;
ceph-single-node = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./ceph-single-node.nix;
ceph-single-node-bluestore = runTestOn [
"aarch64-linux"
"x86_64-linux"
] ./ceph-single-node-bluestore.nix { };
ceph-single-node-bluestore-dmcrypt = handleTestOn [
] ./ceph-single-node-bluestore.nix;
ceph-single-node-bluestore-dmcrypt = runTestOn [
"aarch64-linux"
"x86_64-linux"
] ./ceph-single-node-bluestore-dmcrypt.nix { };
certmgr = handleTest ./certmgr.nix { };
cfssl = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./cfssl.nix { };
] ./ceph-single-node-bluestore-dmcrypt.nix;
certmgr = import ./certmgr.nix { inherit pkgs runTest; };
cfssl = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./cfssl.nix;
cgit = runTest ./cgit.nix;
charliecloud = runTest ./charliecloud.nix;
chromadb = runTest ./chromadb.nix;
chromium = (handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./chromium.nix { }).stable or { };
chrony = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./chrony.nix { };
chrony-ptp = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./chrony-ptp.nix { };
chrony = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./chrony.nix;
chrony-ptp = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./chrony-ptp.nix;
cinnamon = runTest ./cinnamon.nix;
cinnamon-wayland = runTest ./cinnamon-wayland.nix;
cjdns = runTest ./cjdns.nix;
clatd = runTest ./clatd.nix;
clickhouse = import ./clickhouse { inherit runTest; };
cloud-init = handleTest ./cloud-init.nix { };
cloud-init-hostname = handleTest ./cloud-init-hostname.nix { };
cloud-init = runTest ./cloud-init.nix;
cloud-init-hostname = runTest ./cloud-init-hostname.nix;
cloudlog = runTest ./cloudlog.nix;
cntr = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./cntr.nix { };
cntr = import ./cntr.nix {
inherit (pkgs) lib;
runTest = runTestOn [
"aarch64-linux"
"x86_64-linux"
];
};
cockpit = runTest ./cockpit.nix;
cockroachdb = handleTestOn [ "x86_64-linux" ] ./cockroachdb.nix { };
cockroachdb = runTestOn [ "x86_64-linux" ] ./cockroachdb.nix;
code-server = runTest ./code-server.nix;
coder = runTest ./coder.nix;
collectd = runTest ./collectd.nix;
@@ -346,7 +355,7 @@ in
containers-tmpfs = runTest ./containers-tmpfs.nix;
containers-unified-hierarchy = runTest ./containers-unified-hierarchy.nix;
convos = runTest ./convos.nix;
corerad = handleTest ./corerad.nix { };
corerad = runTest ./corerad.nix;
corteza = runTest ./corteza.nix;
cosmic = runTest {
imports = [ ./cosmic.nix ];
@@ -375,11 +384,11 @@ in
coturn = runTest ./coturn.nix;
couchdb = runTest ./couchdb.nix;
crabfit = runTest ./crabfit.nix;
cri-o = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./cri-o.nix { };
cri-o = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./cri-o.nix;
cryptpad = runTest ./cryptpad.nix;
cups-pdf = runTest ./cups-pdf.nix;
curl-impersonate = runTest ./curl-impersonate.nix;
custom-ca = handleTest ./custom-ca.nix { };
custom-ca = import ./custom-ca.nix { inherit pkgs runTest; };
croc = runTest ./croc.nix;
cross-seed = runTest ./cross-seed.nix;
cyrus-imap = runTest ./cyrus-imap.nix;
@@ -396,16 +405,16 @@ in
dependency-track = runTest ./dependency-track.nix;
devpi-server = runTest ./devpi-server.nix;
dex-oidc = runTest ./dex-oidc.nix;
dhparams = handleTest ./dhparams.nix { };
dhparams = runTest ./dhparams.nix;
disable-installer-tools = runTest ./disable-installer-tools.nix;
discourse = runTest ./discourse.nix;
dnscrypt-proxy2 = handleTestOn [ "x86_64-linux" ] ./dnscrypt-proxy2.nix { };
dnscrypt-proxy2 = runTestOn [ "x86_64-linux" ] ./dnscrypt-proxy2.nix;
dnsdist = import ./dnsdist.nix { inherit pkgs runTest; };
doas = runTest ./doas.nix;
docker = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./docker.nix;
docker-rootless = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./docker-rootless.nix;
docker-registry = runTest ./docker-registry.nix;
docker-tools = handleTestOn [ "x86_64-linux" ] ./docker-tools.nix { };
docker-tools = runTestOn [ "x86_64-linux" ] ./docker-tools.nix;
docker-tools-nix-shell = runTest ./docker-tools-nix-shell.nix;
docker-tools-cross = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./docker-tools-cross.nix;
docker-tools-overlay = runTestOn [ "x86_64-linux" ] ./docker-tools-overlay.nix;
@@ -416,7 +425,7 @@ in
dokuwiki = runTest ./dokuwiki.nix;
dolibarr = runTest ./dolibarr.nix;
domination = runTest ./domination.nix;
dovecot = handleTest ./dovecot.nix { };
dovecot = runTest ./dovecot.nix;
drawterm = discoverTests (import ./drawterm.nix);
draupnir = runTest ./matrix/draupnir.nix;
drbd = runTest ./drbd.nix;
@@ -425,8 +434,8 @@ in
drbd-driver = runTest ./drbd-driver.nix;
dublin-traceroute = runTest ./dublin-traceroute.nix;
dwl = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./dwl.nix;
earlyoom = handleTestOn [ "x86_64-linux" ] ./earlyoom.nix { };
early-mount-options = handleTest ./early-mount-options.nix { };
earlyoom = runTestOn [ "x86_64-linux" ] ./earlyoom.nix;
early-mount-options = runTest ./early-mount-options.nix;
ec2-config = (handleTestOn [ "x86_64-linux" ] ./ec2.nix { }).boot-ec2-config or { };
ec2-nixops = (handleTestOn [ "x86_64-linux" ] ./ec2.nix { }).boot-ec2-nixops or { };
echoip = runTest ./echoip.nix;
@@ -464,8 +473,8 @@ in
activation-etc-overlay-mutable = runTest ./activation/etc-overlay-mutable.nix;
activation-etc-overlay-immutable = runTest ./activation/etc-overlay-immutable.nix;
activation-perlless = runTest ./activation/perlless.nix;
etcd = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd.nix { };
etcd-cluster = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd-cluster.nix { };
etcd = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd.nix;
etcd-cluster = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./etcd/etcd-cluster.nix;
etebase-server = runTest ./etebase-server.nix;
etesync-dav = runTest ./etesync-dav.nix;
evcc = runTest ./evcc.nix;
@@ -473,11 +482,11 @@ in
fakeroute = runTest ./fakeroute.nix;
fancontrol = runTest ./fancontrol.nix;
fanout = runTest ./fanout.nix;
fcitx5 = handleTest ./fcitx5 { };
fcitx5 = runTest ./fcitx5;
fedimintd = runTest ./fedimintd.nix;
fenics = runTest ./fenics.nix;
ferm = runTest ./ferm.nix;
ferretdb = handleTest ./ferretdb.nix { };
ferretdb = import ./ferretdb.nix { inherit pkgs runTest; };
fider = runTest ./fider.nix;
filesender = runTest ./filesender.nix;
filebrowser = runTest ./filebrowser.nix;
@@ -511,11 +520,17 @@ in
};
firefoxpwa = runTest ./firefoxpwa.nix;
firejail = runTest ./firejail.nix;
firewall = handleTest ./firewall.nix { nftables = false; };
firewall-nftables = handleTest ./firewall.nix { nftables = true; };
firewall = runTest {
imports = [ ./firewall.nix ];
_module.args.nftables = false;
};
firewall-nftables = runTest {
imports = [ ./firewall.nix ];
_module.args.nftables = true;
};
fish = runTest ./fish.nix;
firezone = runTest ./firezone/firezone.nix;
flannel = handleTestOn [ "x86_64-linux" ] ./flannel.nix { };
flannel = runTestOn [ "x86_64-linux" ] ./flannel.nix;
flaresolverr = runTest ./flaresolverr.nix;
flood = runTest ./flood.nix;
floorp = runTest {
@@ -537,13 +552,19 @@ in
freenet = runTest ./freenet.nix;
freeswitch = runTest ./freeswitch.nix;
freetube = discoverTests (import ./freetube.nix);
freshrss = handleTest ./freshrss { };
freshrss = import ./freshrss { inherit runTest; };
frigate = runTest ./frigate.nix;
froide-govplan = runTest ./web-apps/froide-govplan.nix;
frp = runTest ./frp.nix;
frr = runTest ./frr.nix;
fsck = handleTest ./fsck.nix { };
fsck-systemd-stage-1 = handleTest ./fsck.nix { systemdStage1 = true; };
fsck = runTest {
imports = [ ./fsck.nix ];
_module.args.systemdStage1 = false;
};
fsck-systemd-stage-1 = runTest {
imports = [ ./fsck.nix ];
_module.args.systemdStage1 = true;
};
ft2-clone = runTest ./ft2-clone.nix;
legit = runTest ./legit.nix;
mimir = runTest ./mimir.nix;
@@ -559,7 +580,7 @@ in
};
gatus = runTest ./gatus.nix;
getaddrinfo = runTest ./getaddrinfo.nix;
gemstash = handleTest ./gemstash.nix { };
gemstash = import ./gemstash.nix { inherit pkgs runTest; };
geoclue2 = runTest ./geoclue2.nix;
geoserver = runTest ./geoserver.nix;
gerrit = runTest ./gerrit.nix;
+3 -15
View File
@@ -1,21 +1,10 @@
# This test does a basic functionality check for birdwatcher
{
system ? builtins.currentSystem,
pkgs ? import ../.. {
inherit system;
config = { };
},
}:
let
inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
inherit (pkgs.lib) optionalString;
in
makeTest {
name = "birdwatcher";
nodes = {
host1 = {
nodes.host1 =
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ jq ];
services.bird = {
enable = true;
@@ -84,7 +73,6 @@ makeTest {
'';
};
};
};
testScript = ''
start_all()
+1 -1
View File
@@ -1,4 +1,4 @@
import ./make-test-python.nix {
{
name = "blocky";
nodes = {
+39 -41
View File
@@ -1,44 +1,42 @@
import ./make-test-python.nix (
{ pkgs, ... }:
{
name = "bpf";
meta.maintainers = with pkgs.lib.maintainers; [ martinetd ];
{ lib, ... }:
{
name = "bpf";
meta.maintainers = with lib.maintainers; [ martinetd ];
nodes.machine =
{ pkgs, ... }:
{
programs.bcc.enable = true;
environment.systemPackages = with pkgs; [ bpftrace ];
};
nodes.machine =
{ pkgs, ... }:
{
programs.bcc.enable = true;
environment.systemPackages = with pkgs; [ bpftrace ];
};
testScript = ''
## bcc
# syscount -d 1 stops 1s after probe started so is good for that
print(machine.succeed("syscount -d 1"))
testScript = ''
## bcc
# syscount -d 1 stops 1s after probe started so is good for that
print(machine.succeed("syscount -d 1"))
## bpftrace
# list probes
machine.succeed("bpftrace -l")
# simple BEGIN probe (user probe on bpftrace itself)
print(machine.succeed("bpftrace -e 'BEGIN { print(\"ok\\n\"); exit(); }'"))
# tracepoint
print(machine.succeed("bpftrace -e 'tracepoint:syscalls:sys_enter_* { print(probe); exit() }'"))
# kprobe
print(machine.succeed("bpftrace -e 'kprobe:schedule { print(probe); exit() }'"))
# BTF
print(machine.succeed("bpftrace -e 'kprobe:schedule { "
" printf(\"tgid: %d\\n\", ((struct task_struct*) curtask)->tgid); exit() "
"}'"))
# module BTF (bpftrace >= 0.17)
# test is currently disabled on aarch64 as kfunc does not work there yet
# https://github.com/iovisor/bpftrace/issues/2496
print(machine.succeed("uname -m | grep aarch64 || "
"bpftrace -e 'kfunc:nft_trans_alloc_gfp { "
" printf(\"portid: %d\\n\", args->ctx->portid); "
"} BEGIN { exit() }'"))
# glibc includes
print(machine.succeed("bpftrace -e '#include <errno.h>\n"
"BEGIN { printf(\"ok %d\\n\", EINVAL); exit(); }'"))
'';
}
)
## bpftrace
# list probes
machine.succeed("bpftrace -l")
# simple BEGIN probe (user probe on bpftrace itself)
print(machine.succeed("bpftrace -e 'BEGIN { print(\"ok\\n\"); exit(); }'"))
# tracepoint
print(machine.succeed("bpftrace -e 'tracepoint:syscalls:sys_enter_* { print(probe); exit() }'"))
# kprobe
print(machine.succeed("bpftrace -e 'kprobe:schedule { print(probe); exit() }'"))
# BTF
print(machine.succeed("bpftrace -e 'kprobe:schedule { "
" printf(\"tgid: %d\\n\", ((struct task_struct*) curtask)->tgid); exit() "
"}'"))
# module BTF (bpftrace >= 0.17)
# test is currently disabled on aarch64 as kfunc does not work there yet
# https://github.com/iovisor/bpftrace/issues/2496
print(machine.succeed("uname -m | grep aarch64 || "
"bpftrace -e 'kfunc:nft_trans_alloc_gfp { "
" printf(\"portid: %d\\n\", args->ctx->portid); "
"} BEGIN { exit() }'"))
# glibc includes
print(machine.succeed("bpftrace -e '#include <errno.h>\n"
"BEGIN { printf(\"ok %d\\n\", EINVAL); exit(); }'"))
'';
}
+27 -33
View File
@@ -1,39 +1,33 @@
import ./make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "cadvisor";
meta.maintainers = with lib.maintainers; [ offline ];
{ lib, ... }:
{
name = "cadvisor";
meta.maintainers = with lib.maintainers; [ offline ];
nodes = {
machine =
{ ... }:
{
services.cadvisor.enable = true;
};
influxdb =
{ lib, ... }:
{
services.cadvisor.enable = true;
services.cadvisor.storageDriver = "influxdb";
services.influxdb.enable = true;
};
nodes = {
machine = {
services.cadvisor.enable = true;
};
testScript = ''
start_all()
machine.wait_for_unit("cadvisor.service")
machine.succeed("curl -f http://localhost:8080/containers/")
influxdb = {
services.cadvisor.enable = true;
services.cadvisor.storageDriver = "influxdb";
services.influxdb.enable = true;
};
};
influxdb.wait_for_unit("influxdb.service")
testScript = ''
start_all()
machine.wait_for_unit("cadvisor.service")
machine.succeed("curl -f http://localhost:8080/containers/")
# create influxdb database
influxdb.succeed(
'curl -f -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE root"'
)
influxdb.wait_for_unit("influxdb.service")
influxdb.wait_for_unit("cadvisor.service")
influxdb.succeed("curl -f http://localhost:8080/containers/")
'';
}
)
# create influxdb database
influxdb.succeed(
'curl -f -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE root"'
)
influxdb.wait_for_unit("cadvisor.service")
influxdb.succeed("curl -f http://localhost:8080/containers/")
'';
}
+145 -147
View File
@@ -1,162 +1,160 @@
import ./make-test-python.nix (
{
pkgs,
lib,
testPackage ? pkgs.cassandra,
...
}:
let
clusterName = "NixOS Automated-Test Cluster";
{
pkgs,
lib,
getPackage ? pkgs: pkgs.cassandra_4,
...
}:
let
testPackage = getPackage pkgs;
clusterName = "NixOS Automated-Test Cluster";
testRemoteAuth = lib.versionAtLeast testPackage.version "3.11";
jmxRoles = [
{
username = "me";
password = "password";
}
];
jmxRolesFile = ./cassandra-jmx-roles;
jmxAuthArgs = "-u ${(builtins.elemAt jmxRoles 0).username} -pw ${(builtins.elemAt jmxRoles 0).password}";
jmxPort = 7200; # Non-standard port so it doesn't accidentally work
jmxPortStr = toString jmxPort;
testRemoteAuth = lib.versionAtLeast testPackage.version "3.11";
jmxRoles = [
{
username = "me";
password = "password";
}
];
jmxRolesFile = ./cassandra-jmx-roles;
jmxAuthArgs = "-u ${(builtins.elemAt jmxRoles 0).username} -pw ${(builtins.elemAt jmxRoles 0).password}";
jmxPort = 7200; # Non-standard port so it doesn't accidentally work
jmxPortStr = toString jmxPort;
# Would usually be assigned to 512M.
# Set it to a different value, so that we can check whether our config
# actually changes it.
numMaxHeapSize = "400";
getHeapLimitCommand = ''
nodetool info -p ${jmxPortStr} | grep "^Heap Memory" | awk '{print $NF}'
'';
checkHeapLimitCommand = pkgs.writeShellScript "check-heap-limit.sh" ''
[ 1 -eq "$(echo "$(${getHeapLimitCommand}) < ${numMaxHeapSize}" | ${pkgs.bc}/bin/bc)" ]
'';
# Would usually be assigned to 512M.
# Set it to a different value, so that we can check whether our config
# actually changes it.
numMaxHeapSize = "400";
getHeapLimitCommand = ''
nodetool info -p ${jmxPortStr} | grep "^Heap Memory" | awk '{print $NF}'
'';
checkHeapLimitCommand = pkgs.writeShellScript "check-heap-limit.sh" ''
[ 1 -eq "$(echo "$(${getHeapLimitCommand}) < ${numMaxHeapSize}" | ${pkgs.bc}/bin/bc)" ]
'';
cassandraCfg = ipAddress: {
enable = true;
inherit clusterName;
listenAddress = ipAddress;
rpcAddress = ipAddress;
seedAddresses = [ "192.168.1.1" ];
package = testPackage;
maxHeapSize = "${numMaxHeapSize}M";
heapNewSize = "100M";
inherit jmxPort;
};
nodeCfg =
ipAddress: extra:
{ pkgs, config, ... }:
rec {
environment.systemPackages = [ testPackage ];
networking = {
firewall.allowedTCPPorts = [
7000
9042
services.cassandra.jmxPort
];
useDHCP = false;
interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
{
address = ipAddress;
prefixLength = 24;
}
];
};
services.cassandra = cassandraCfg ipAddress // extra;
cassandraCfg = pkgs: ipAddress: {
enable = true;
inherit clusterName;
listenAddress = ipAddress;
rpcAddress = ipAddress;
seedAddresses = [ "192.168.1.1" ];
package = getPackage pkgs;
maxHeapSize = "${numMaxHeapSize}M";
heapNewSize = "100M";
inherit jmxPort;
};
nodeCfg =
ipAddress: extra:
{ pkgs, config, ... }:
rec {
environment.systemPackages = [ (getPackage pkgs) ];
networking = {
firewall.allowedTCPPorts = [
7000
9042
services.cassandra.jmxPort
];
useDHCP = false;
interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
{
address = ipAddress;
prefixLength = 24;
}
];
};
in
{
name = "cassandra-${testPackage.version}";
meta = {
maintainers = with lib.maintainers; [ johnazoidberg ];
services.cassandra = cassandraCfg pkgs ipAddress // extra;
};
in
{
name = "cassandra-${testPackage.version}";
meta = {
maintainers = with lib.maintainers; [ johnazoidberg ];
};
nodes = {
cass0 = nodeCfg "192.168.1.1" { };
cass1 = nodeCfg "192.168.1.2" (
lib.optionalAttrs testRemoteAuth {
inherit jmxRoles;
remoteJmx = true;
}
);
cass2 = nodeCfg "192.168.1.3" { jvmOpts = [ "-Dcassandra.replace_address=cass1" ]; };
};
nodes = {
cass0 = nodeCfg "192.168.1.1" { };
cass1 = nodeCfg "192.168.1.2" (
lib.optionalAttrs testRemoteAuth {
inherit jmxRoles;
remoteJmx = true;
}
);
cass2 = nodeCfg "192.168.1.3" { jvmOpts = [ "-Dcassandra.replace_address=cass1" ]; };
};
testScript =
''
# Check configuration
with subtest("Timers exist"):
cass0.succeed("systemctl list-timers | grep cassandra-full-repair.timer")
cass0.succeed("systemctl list-timers | grep cassandra-incremental-repair.timer")
testScript =
''
# Check configuration
with subtest("Timers exist"):
cass0.succeed("systemctl list-timers | grep cassandra-full-repair.timer")
cass0.succeed("systemctl list-timers | grep cassandra-incremental-repair.timer")
with subtest("Can connect via cqlsh"):
cass0.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds("nc -z cass0 9042")
cass0.succeed("echo 'show version;' | cqlsh cass0")
with subtest("Can connect via cqlsh"):
cass0.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds("nc -z cass0 9042")
cass0.succeed("echo 'show version;' | cqlsh cass0")
with subtest("Nodetool is operational"):
cass0.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass0.succeed("nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass0'")
with subtest("Nodetool is operational"):
cass0.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass0.succeed("nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass0'")
with subtest("Cluster name was set"):
cass0.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass0.wait_until_succeeds(
"nodetool describecluster -p ${jmxPortStr} | grep 'Name: ${clusterName}'"
)
with subtest("Cluster name was set"):
cass0.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass0.wait_until_succeeds(
"nodetool describecluster -p ${jmxPortStr} | grep 'Name: ${clusterName}'"
)
with subtest("Heap limit set correctly"):
# Nodetool takes a while until it can display info
cass0.wait_until_succeeds("nodetool info -p ${jmxPortStr}")
cass0.succeed("${checkHeapLimitCommand}")
with subtest("Heap limit set correctly"):
# Nodetool takes a while until it can display info
cass0.wait_until_succeeds("nodetool info -p ${jmxPortStr}")
cass0.succeed("${checkHeapLimitCommand}")
# Check cluster interaction
with subtest("Bring up cluster"):
cass1.wait_for_unit("cassandra.service")
cass1.wait_until_succeeds(
"nodetool -p ${jmxPortStr} ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"
)
cass0.succeed("nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass1'")
''
+ lib.optionalString testRemoteAuth ''
with subtest("Remote authenticated jmx"):
# Doesn't work if not enabled
cass0.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass1.fail("nc -z 192.168.1.1 ${jmxPortStr}")
cass1.fail("nodetool -p ${jmxPortStr} -h 192.168.1.1 status")
# Check cluster interaction
with subtest("Bring up cluster"):
cass1.wait_for_unit("cassandra.service")
cass1.wait_until_succeeds(
"nodetool -p ${jmxPortStr} ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"
)
cass0.succeed("nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass1'")
''
+ lib.optionalString testRemoteAuth ''
with subtest("Remote authenticated jmx"):
# Doesn't work if not enabled
cass0.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass1.fail("nc -z 192.168.1.1 ${jmxPortStr}")
cass1.fail("nodetool -p ${jmxPortStr} -h 192.168.1.1 status")
# Works if enabled
cass1.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass0.succeed("nodetool -p ${jmxPortStr} -h 192.168.1.2 ${jmxAuthArgs} status")
''
+ ''
with subtest("Break and fix node"):
cass1.block()
cass0.wait_until_succeeds(
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep -c '^DN[[:space:]]+cass1'"
)
cass0.succeed("nodetool status -p ${jmxPortStr} | egrep -c '^UN' | grep 1")
cass1.unblock()
cass1.wait_until_succeeds(
"nodetool -p ${jmxPortStr} ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"
)
cass0.succeed("nodetool status -p ${jmxPortStr} | egrep -c '^UN' | grep 2")
# Works if enabled
cass1.wait_until_succeeds("nc -z localhost ${jmxPortStr}")
cass0.succeed("nodetool -p ${jmxPortStr} -h 192.168.1.2 ${jmxAuthArgs} status")
''
+ ''
with subtest("Break and fix node"):
cass1.block()
cass0.wait_until_succeeds(
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep -c '^DN[[:space:]]+cass1'"
)
cass0.succeed("nodetool status -p ${jmxPortStr} | egrep -c '^UN' | grep 1")
cass1.unblock()
cass1.wait_until_succeeds(
"nodetool -p ${jmxPortStr} ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"
)
cass0.succeed("nodetool status -p ${jmxPortStr} | egrep -c '^UN' | grep 2")
with subtest("Replace crashed node"):
cass1.block() # .crash() waits until it's fully shutdown
cass2.start()
cass0.wait_until_fails(
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass1'"
)
with subtest("Replace crashed node"):
cass1.block() # .crash() waits until it's fully shutdown
cass2.start()
cass0.wait_until_fails(
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass1'"
)
cass2.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds(
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass2'"
)
'';
cass2.wait_for_unit("cassandra.service")
cass0.wait_until_succeeds(
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass2'"
)
'';
passthru = {
inherit testPackage;
};
}
)
passthru = {
inherit testPackage;
};
}
+268 -279
View File
@@ -1,297 +1,286 @@
import ./make-test-python.nix (
{ pkgs, lib, ... }:
let
cfg = {
clusterId = "066ae264-2a5d-4729-8001-6ad265f50b03";
monA = {
name = "a";
ip = "192.168.1.1";
};
osd0 = {
name = "0";
ip = "192.168.1.2";
key = "AQBCEJNa3s8nHRAANvdsr93KqzBznuIWm2gOGg==";
uuid = "55ba2294-3e24-478f-bee0-9dca4c231dd9";
};
osd1 = {
name = "1";
ip = "192.168.1.3";
key = "AQBEEJNac00kExAAXEgy943BGyOpVH1LLlHafQ==";
uuid = "5e97a838-85b6-43b0-8950-cb56d554d1e5";
};
osd2 = {
name = "2";
ip = "192.168.1.4";
key = "AQAdyhZeIaUlARAAGRoidDAmS6Vkp546UFEf5w==";
uuid = "ea999274-13d0-4dd5-9af9-ad25a324f72f";
};
{ lib, ... }:
let
cfg = {
clusterId = "066ae264-2a5d-4729-8001-6ad265f50b03";
monA = {
name = "a";
ip = "192.168.1.1";
};
generateCephConfig =
{ daemonConfig }:
osd0 = {
name = "0";
ip = "192.168.1.2";
key = "AQBCEJNa3s8nHRAANvdsr93KqzBznuIWm2gOGg==";
uuid = "55ba2294-3e24-478f-bee0-9dca4c231dd9";
};
osd1 = {
name = "1";
ip = "192.168.1.3";
key = "AQBEEJNac00kExAAXEgy943BGyOpVH1LLlHafQ==";
uuid = "5e97a838-85b6-43b0-8950-cb56d554d1e5";
};
osd2 = {
name = "2";
ip = "192.168.1.4";
key = "AQAdyhZeIaUlARAAGRoidDAmS6Vkp546UFEf5w==";
uuid = "ea999274-13d0-4dd5-9af9-ad25a324f72f";
};
};
generateCephConfig =
{ daemonConfig }:
{
enable = true;
global = {
fsid = cfg.clusterId;
monHost = cfg.monA.ip;
monInitialMembers = cfg.monA.name;
};
}
// daemonConfig;
generateHost =
{ cephConfig, networkConfig }:
{ pkgs, ... }:
{
virtualisation = {
emptyDiskImages = [ 20480 ];
vlans = [ 1 ];
};
networking = networkConfig;
environment.systemPackages = with pkgs; [
bash
sudo
ceph
xfsprogs
libressl.nc
];
boot.kernelModules = [ "xfs" ];
services.ceph = cephConfig;
};
networkMonA = {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = lib.mkOverride 0 [
{
enable = true;
global = {
fsid = cfg.clusterId;
monHost = cfg.monA.ip;
monInitialMembers = cfg.monA.name;
};
address = cfg.monA.ip;
prefixLength = 24;
}
// daemonConfig;
generateHost =
{
pkgs,
cephConfig,
networkConfig,
...
}:
{
virtualisation = {
emptyDiskImages = [ 20480 ];
vlans = [ 1 ];
};
networking = networkConfig;
environment.systemPackages = with pkgs; [
bash
sudo
ceph
xfsprogs
libressl.nc
];
boot.kernelModules = [ "xfs" ];
services.ceph = cephConfig;
};
networkMonA = {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
];
firewall = {
allowedTCPPorts = [
6789
3300
];
allowedTCPPortRanges = [
{
address = cfg.monA.ip;
prefixLength = 24;
from = 6800;
to = 7300;
}
];
firewall = {
allowedTCPPorts = [
6789
3300
];
allowedTCPPortRanges = [
{
from = 6800;
to = 7300;
}
];
};
};
cephConfigMonA = generateCephConfig {
daemonConfig = {
mon = {
enable = true;
daemons = [ cfg.monA.name ];
};
mgr = {
enable = true;
daemons = [ cfg.monA.name ];
};
};
cephConfigMonA = generateCephConfig {
};
networkOsd = osd: {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = lib.mkOverride 0 [
{
address = osd.ip;
prefixLength = 24;
}
];
firewall = {
allowedTCPPortRanges = [
{
from = 6800;
to = 7300;
}
];
};
};
cephConfigOsd =
osd:
generateCephConfig {
daemonConfig = {
mon = {
osd = {
enable = true;
daemons = [ cfg.monA.name ];
};
mgr = {
enable = true;
daemons = [ cfg.monA.name ];
daemons = [ osd.name ];
};
};
};
networkOsd = osd: {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
{
address = osd.ip;
prefixLength = 24;
}
];
firewall = {
allowedTCPPortRanges = [
{
from = 6800;
to = 7300;
}
];
};
# Following deployment is based on the manual deployment described here:
# https://docs.ceph.com/docs/master/install/manual-deployment/
# For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/
testscript =
{ ... }:
''
start_all()
monA.wait_for_unit("network.target")
osd0.wait_for_unit("network.target")
osd1.wait_for_unit("network.target")
osd2.wait_for_unit("network.target")
# Bootstrap ceph-mon daemon
monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.succeed("ceph mon enable-msgr2")
monA.succeed("ceph config set mon auth_allow_insecure_global_id_reclaim false")
# Can't check ceph status until a mon is up
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Start the ceph-mgr daemon, it has no deps and hardly any setup
monA.succeed(
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mgr-a")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Send the admin keyring to the OSD machines
monA.succeed("cp /etc/ceph/ceph.client.admin.keyring /tmp/shared")
osd0.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
osd1.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
osd2.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
# Bootstrap OSDs
osd0.succeed(
"mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
)
osd1.succeed(
"mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
)
osd2.succeed(
"mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd2.name}/keyring --name osd.${cfg.osd2.name} --add-key ${cfg.osd2.key}",
'echo \'{"cephx_secret": "${cfg.osd2.key}"}\' | ceph osd new ${cfg.osd2.uuid} -i -',
)
# Initialize the OSDs with regular filestore
osd0.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}",
)
osd1.succeed(
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd1.name}",
)
osd2.succeed(
"ceph-osd -i ${cfg.osd2.name} --mkfs --osd-uuid ${cfg.osd2.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd2.name}",
)
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.succeed(
"ceph osd pool create multi-node-test 32 32",
"ceph osd pool ls | grep 'multi-node-test'",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable multi-node-test nixos-test",
"ceph osd pool rename multi-node-test multi-node-other-test",
"ceph osd pool ls | grep 'multi-node-other-test'",
)
monA.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
monA.succeed("ceph osd pool set multi-node-other-test size 2")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.wait_until_succeeds("ceph -s | grep '33 active+clean'")
monA.fail(
"ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete multi-node-other-test multi-node-other-test --yes-i-really-really-mean-it",
)
# Shut down ceph on all machines in a very unpolite way
monA.crash()
osd0.crash()
osd1.crash()
osd2.crash()
# Start it up
osd0.start()
osd1.start()
osd2.start()
monA.start()
# Ensure the cluster comes back up again
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
in
{
name = "basic-multi-node-ceph-cluster";
meta = with lib.maintainers; {
maintainers = [ lejonet ];
};
nodes = {
monA = generateHost {
cephConfig = cephConfigMonA;
networkConfig = networkMonA;
};
cephConfigOsd =
osd:
generateCephConfig {
daemonConfig = {
osd = {
enable = true;
daemons = [ osd.name ];
};
};
};
# Following deployment is based on the manual deployment described here:
# https://docs.ceph.com/docs/master/install/manual-deployment/
# For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/
testscript =
{ ... }:
''
start_all()
monA.wait_for_unit("network.target")
osd0.wait_for_unit("network.target")
osd1.wait_for_unit("network.target")
osd2.wait_for_unit("network.target")
# Bootstrap ceph-mon daemon
monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.succeed("ceph mon enable-msgr2")
monA.succeed("ceph config set mon auth_allow_insecure_global_id_reclaim false")
# Can't check ceph status until a mon is up
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Start the ceph-mgr daemon, it has no deps and hardly any setup
monA.succeed(
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mgr-a")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Send the admin keyring to the OSD machines
monA.succeed("cp /etc/ceph/ceph.client.admin.keyring /tmp/shared")
osd0.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
osd1.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
osd2.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
# Bootstrap OSDs
osd0.succeed(
"mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
)
osd1.succeed(
"mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
)
osd2.succeed(
"mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd2.name}/keyring --name osd.${cfg.osd2.name} --add-key ${cfg.osd2.key}",
'echo \'{"cephx_secret": "${cfg.osd2.key}"}\' | ceph osd new ${cfg.osd2.uuid} -i -',
)
# Initialize the OSDs with regular filestore
osd0.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}",
)
osd1.succeed(
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd1.name}",
)
osd2.succeed(
"ceph-osd -i ${cfg.osd2.name} --mkfs --osd-uuid ${cfg.osd2.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd2.name}",
)
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.succeed(
"ceph osd pool create multi-node-test 32 32",
"ceph osd pool ls | grep 'multi-node-test'",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable multi-node-test nixos-test",
"ceph osd pool rename multi-node-test multi-node-other-test",
"ceph osd pool ls | grep 'multi-node-other-test'",
)
monA.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
monA.succeed("ceph osd pool set multi-node-other-test size 2")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.wait_until_succeeds("ceph -s | grep '33 active+clean'")
monA.fail(
"ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete multi-node-other-test multi-node-other-test --yes-i-really-really-mean-it",
)
# Shut down ceph on all machines in a very unpolite way
monA.crash()
osd0.crash()
osd1.crash()
osd2.crash()
# Start it up
osd0.start()
osd1.start()
osd2.start()
monA.start()
# Ensure the cluster comes back up again
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
in
{
name = "basic-multi-node-ceph-cluster";
meta = with pkgs.lib.maintainers; {
maintainers = [ lejonet ];
osd0 = generateHost {
cephConfig = cephConfigOsd cfg.osd0;
networkConfig = networkOsd cfg.osd0;
};
nodes = {
monA = generateHost {
pkgs = pkgs;
cephConfig = cephConfigMonA;
networkConfig = networkMonA;
};
osd0 = generateHost {
pkgs = pkgs;
cephConfig = cephConfigOsd cfg.osd0;
networkConfig = networkOsd cfg.osd0;
};
osd1 = generateHost {
pkgs = pkgs;
cephConfig = cephConfigOsd cfg.osd1;
networkConfig = networkOsd cfg.osd1;
};
osd2 = generateHost {
pkgs = pkgs;
cephConfig = cephConfigOsd cfg.osd2;
networkConfig = networkOsd cfg.osd2;
};
osd1 = generateHost {
cephConfig = cephConfigOsd cfg.osd1;
networkConfig = networkOsd cfg.osd1;
};
osd2 = generateHost {
cephConfig = cephConfigOsd cfg.osd2;
networkConfig = networkOsd cfg.osd2;
};
};
testScript = testscript;
}
)
testScript = testscript;
}
+247 -251
View File
@@ -1,273 +1,269 @@
import ./make-test-python.nix (
{ pkgs, lib, ... }:
{ lib, ... }:
let
# the single node ipv6 address
ip = "2001:db8:ffff::";
# the global ceph cluster id
cluster = "54465b37-b9d8-4539-a1f9-dd33c75ee45a";
# the fsids of OSDs
osd-fsid-map = {
"0" = "1c1b7ea9-06bf-4d30-9a01-37ac3a0254aa";
"1" = "bd5a6f49-69d5-428c-ac25-a99f0c44375c";
"2" = "c90de6c7-86c6-41da-9694-e794096dfc5c";
};
let
# the single node ipv6 address
ip = "2001:db8:ffff::";
# the global ceph cluster id
cluster = "54465b37-b9d8-4539-a1f9-dd33c75ee45a";
# the fsids of OSDs
osd-fsid-map = {
"0" = "1c1b7ea9-06bf-4d30-9a01-37ac3a0254aa";
"1" = "bd5a6f49-69d5-428c-ac25-a99f0c44375c";
"2" = "c90de6c7-86c6-41da-9694-e794096dfc5c";
};
in
{
name = "basic-single-node-ceph-cluster-bluestore-dmcrypt";
meta.maintainers = with lib.maintainers; [
benaryorg
nh2
];
in
{
name = "basic-single-node-ceph-cluster-bluestore-dmcrypt";
meta = {
maintainers = with lib.maintainers; [
benaryorg
nh2
nodes.ceph =
{
lib,
pkgs,
config,
...
}:
{
# disks for bluestore
virtualisation.emptyDiskImages = [
20480
20480
20480
];
};
nodes = {
ceph =
{ pkgs, config, ... }:
{
# disks for bluestore
virtualisation.emptyDiskImages = [
20480
20480
20480
];
# networking setup (no external connectivity required, only local IPv6)
networking.useDHCP = false;
systemd.network = {
# networking setup (no external connectivity required, only local IPv6)
networking.useDHCP = false;
systemd.network = {
enable = true;
wait-online.extraArgs = [
"-i"
"lo"
];
networks = {
"40-loopback" = {
enable = true;
wait-online.extraArgs = [
"-i"
"lo"
];
networks = {
"40-loopback" = {
enable = true;
name = "lo";
DHCP = "no";
addresses = [ { Address = "${ip}/128"; } ];
};
};
name = "lo";
DHCP = "no";
addresses = [ { Address = "${ip}/128"; } ];
};
# do not start the ceph target by default so we can format the disks first
systemd.targets.ceph.wantedBy = lib.mkForce [ ];
# add the packages to systemPackages so the testscript doesn't run into any unexpected issues
# this shouldn't be required on production systems which have their required packages in the unit paths only
# but it helps in case one needs to actually run the tooling anyway
environment.systemPackages = with pkgs; [
ceph
cryptsetup
lvm2
];
services.ceph = {
enable = true;
client.enable = true;
extraConfig = {
public_addr = ip;
cluster_addr = ip;
# ipv6
ms_bind_ipv4 = "false";
ms_bind_ipv6 = "true";
# msgr2 settings
ms_cluster_mode = "secure";
ms_service_mode = "secure";
ms_client_mode = "secure";
ms_mon_cluster_mode = "secure";
ms_mon_service_mode = "secure";
ms_mon_client_mode = "secure";
# less default modules, cuts down on memory and startup time in the tests
mgr_initial_modules = "";
# distribute by OSD, not by host, as per https://docs.ceph.com/en/reef/cephadm/install/#single-host
osd_crush_chooseleaf_type = "0";
};
client.extraConfig."mon.0" = {
host = "ceph";
mon_addr = "v2:[${ip}]:3300";
public_addr = "v2:[${ip}]:3300";
};
global = {
fsid = cluster;
clusterNetwork = "${ip}/64";
publicNetwork = "${ip}/64";
monInitialMembers = "0";
};
mon = {
enable = true;
daemons = [ "0" ];
};
osd = {
enable = true;
daemons = builtins.attrNames osd-fsid-map;
};
mgr = {
enable = true;
daemons = [ "ceph" ];
};
};
systemd.services =
let
osd-name = id: "ceph-osd-${id}";
osd-pre-start = id: [
"!${config.services.ceph.osd.package.out}/bin/ceph-volume lvm activate --bluestore ${id} ${osd-fsid-map.${id}} --no-systemd"
"${config.services.ceph.osd.package.lib}/libexec/ceph/ceph-osd-prestart.sh --id ${id} --cluster ${config.services.ceph.global.clusterName}"
];
osd-post-stop = id: [
"!${config.services.ceph.osd.package.out}/bin/ceph-volume lvm deactivate ${id}"
];
map-osd = id: {
name = osd-name id;
value = {
serviceConfig.ExecStartPre = lib.mkForce (osd-pre-start id);
serviceConfig.ExecStopPost = osd-post-stop id;
unitConfig.ConditionPathExists = lib.mkForce [ ];
unitConfig.StartLimitBurst = lib.mkForce 4;
path = with pkgs; [
util-linux
lvm2
cryptsetup
];
};
};
in
lib.pipe config.services.ceph.osd.daemons [
(builtins.map map-osd)
builtins.listToAttrs
];
};
};
# do not start the ceph target by default so we can format the disks first
systemd.targets.ceph.wantedBy = lib.mkForce [ ];
# add the packages to systemPackages so the testscript doesn't run into any unexpected issues
# this shouldn't be required on production systems which have their required packages in the unit paths only
# but it helps in case one needs to actually run the tooling anyway
environment.systemPackages = with pkgs; [
ceph
cryptsetup
lvm2
];
services.ceph = {
enable = true;
client.enable = true;
extraConfig = {
public_addr = ip;
cluster_addr = ip;
# ipv6
ms_bind_ipv4 = "false";
ms_bind_ipv6 = "true";
# msgr2 settings
ms_cluster_mode = "secure";
ms_service_mode = "secure";
ms_client_mode = "secure";
ms_mon_cluster_mode = "secure";
ms_mon_service_mode = "secure";
ms_mon_client_mode = "secure";
# less default modules, cuts down on memory and startup time in the tests
mgr_initial_modules = "";
# distribute by OSD, not by host, as per https://docs.ceph.com/en/reef/cephadm/install/#single-host
osd_crush_chooseleaf_type = "0";
};
client.extraConfig."mon.0" = {
host = "ceph";
mon_addr = "v2:[${ip}]:3300";
public_addr = "v2:[${ip}]:3300";
};
global = {
fsid = cluster;
clusterNetwork = "${ip}/64";
publicNetwork = "${ip}/64";
monInitialMembers = "0";
};
mon = {
enable = true;
daemons = [ "0" ];
};
osd = {
enable = true;
daemons = builtins.attrNames osd-fsid-map;
};
mgr = {
enable = true;
daemons = [ "ceph" ];
};
};
systemd.services =
let
osd-name = id: "ceph-osd-${id}";
osd-pre-start = id: [
"!${config.services.ceph.osd.package.out}/bin/ceph-volume lvm activate --bluestore ${id} ${osd-fsid-map.${id}} --no-systemd"
"${config.services.ceph.osd.package.lib}/libexec/ceph/ceph-osd-prestart.sh --id ${id} --cluster ${config.services.ceph.global.clusterName}"
];
osd-post-stop = id: [
"!${config.services.ceph.osd.package.out}/bin/ceph-volume lvm deactivate ${id}"
];
map-osd = id: {
name = osd-name id;
value = {
serviceConfig.ExecStartPre = lib.mkForce (osd-pre-start id);
serviceConfig.ExecStopPost = osd-post-stop id;
unitConfig.ConditionPathExists = lib.mkForce [ ];
unitConfig.StartLimitBurst = lib.mkForce 4;
path = with pkgs; [
util-linux
lvm2
cryptsetup
];
};
};
in
lib.pipe config.services.ceph.osd.daemons [
(builtins.map map-osd)
builtins.listToAttrs
];
};
testScript =
{ ... }:
''
start_all()
testScript = ''
start_all()
ceph.wait_for_unit("default.target")
ceph.wait_for_unit("default.target")
# Bootstrap ceph-mon daemon
ceph.succeed(
"mkdir -p /var/lib/ceph/bootstrap-osd",
"ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"ceph-authtool --create-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring --gen-key -n client.bootstrap-osd --cap mon 'profile bootstrap-osd' --cap mgr 'allow r'",
"ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"ceph-authtool /tmp/ceph.mon.keyring --import-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring",
"monmaptool --create --fsid ${cluster} --addv 0 'v2:[${ip}]:3300/0' --clobber /tmp/ceph.initial-monmap",
"mkdir -p /var/lib/ceph/mon/ceph-0",
"ceph-mon --mkfs -i 0 --monmap /tmp/ceph.initial-monmap --keyring /tmp/ceph.mon.keyring",
"chown ceph:ceph -R /tmp/ceph.mon.keyring /var/lib/ceph",
"systemctl start ceph-mon-0.service",
)
# Bootstrap ceph-mon daemon
ceph.succeed(
"mkdir -p /var/lib/ceph/bootstrap-osd",
"ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"ceph-authtool --create-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring --gen-key -n client.bootstrap-osd --cap mon 'profile bootstrap-osd' --cap mgr 'allow r'",
"ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"ceph-authtool /tmp/ceph.mon.keyring --import-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring",
"monmaptool --create --fsid ${cluster} --addv 0 'v2:[${ip}]:3300/0' --clobber /tmp/ceph.initial-monmap",
"mkdir -p /var/lib/ceph/mon/ceph-0",
"ceph-mon --mkfs -i 0 --monmap /tmp/ceph.initial-monmap --keyring /tmp/ceph.mon.keyring",
"chown ceph:ceph -R /tmp/ceph.mon.keyring /var/lib/ceph",
"systemctl start ceph-mon-0.service",
)
ceph.wait_for_unit("ceph-mon-0.service")
# should the mon not start or bind for some reason this gives us a better error message than the config commands running into a timeout
ceph.wait_for_open_port(3300, "${ip}")
ceph.succeed(
# required for HEALTH_OK
"ceph config set mon auth_allow_insecure_global_id_reclaim false",
# IPv6
"ceph config set global ms_bind_ipv4 false",
"ceph config set global ms_bind_ipv6 true",
# the new (secure) protocol
"ceph config set global ms_bind_msgr1 false",
"ceph config set global ms_bind_msgr2 true",
# just a small little thing
"ceph config set mon mon_compact_on_start true",
)
ceph.wait_for_unit("ceph-mon-0.service")
# should the mon not start or bind for some reason this gives us a better error message than the config commands running into a timeout
ceph.wait_for_open_port(3300, "${ip}")
ceph.succeed(
# required for HEALTH_OK
"ceph config set mon auth_allow_insecure_global_id_reclaim false",
# IPv6
"ceph config set global ms_bind_ipv4 false",
"ceph config set global ms_bind_ipv6 true",
# the new (secure) protocol
"ceph config set global ms_bind_msgr1 false",
"ceph config set global ms_bind_msgr2 true",
# just a small little thing
"ceph config set mon mon_compact_on_start true",
)
# Can't check ceph status until a mon is up
ceph.succeed("ceph -s | grep 'mon: 1 daemons'")
# Can't check ceph status until a mon is up
ceph.succeed("ceph -s | grep 'mon: 1 daemons'")
# Bootstrap OSDs (do this before starting the mgr because cryptsetup and the mgr both eat a lot of memory)
ceph.succeed(
# this will automatically do what's required for LVM, cryptsetup, and stores all the data in Ceph's internal databases
"ceph-volume lvm prepare --bluestore --data /dev/vdb --dmcrypt --no-systemd --osd-id 0 --osd-fsid ${osd-fsid-map."0"}",
"ceph-volume lvm prepare --bluestore --data /dev/vdc --dmcrypt --no-systemd --osd-id 1 --osd-fsid ${osd-fsid-map."1"}",
"ceph-volume lvm prepare --bluestore --data /dev/vdd --dmcrypt --no-systemd --osd-id 2 --osd-fsid ${osd-fsid-map."2"}",
"sudo ceph-volume lvm deactivate 0",
"sudo ceph-volume lvm deactivate 1",
"sudo ceph-volume lvm deactivate 2",
"chown -R ceph:ceph /var/lib/ceph",
)
# Bootstrap OSDs (do this before starting the mgr because cryptsetup and the mgr both eat a lot of memory)
ceph.succeed(
# this will automatically do what's required for LVM, cryptsetup, and stores all the data in Ceph's internal databases
"ceph-volume lvm prepare --bluestore --data /dev/vdb --dmcrypt --no-systemd --osd-id 0 --osd-fsid ${osd-fsid-map."0"}",
"ceph-volume lvm prepare --bluestore --data /dev/vdc --dmcrypt --no-systemd --osd-id 1 --osd-fsid ${osd-fsid-map."1"}",
"ceph-volume lvm prepare --bluestore --data /dev/vdd --dmcrypt --no-systemd --osd-id 2 --osd-fsid ${osd-fsid-map."2"}",
"sudo ceph-volume lvm deactivate 0",
"sudo ceph-volume lvm deactivate 1",
"sudo ceph-volume lvm deactivate 2",
"chown -R ceph:ceph /var/lib/ceph",
)
# Start OSDs (again, argon2id eats memory, so this happens before starting the mgr)
ceph.succeed(
"systemctl start ceph-osd-0.service",
"systemctl start ceph-osd-1.service",
"systemctl start ceph-osd-2.service",
)
ceph.wait_until_succeeds("ceph -s | grep 'quorum 0'")
ceph.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
# Start OSDs (again, argon2id eats memory, so this happens before starting the mgr)
ceph.succeed(
"systemctl start ceph-osd-0.service",
"systemctl start ceph-osd-1.service",
"systemctl start ceph-osd-2.service",
)
ceph.wait_until_succeeds("ceph -s | grep 'quorum 0'")
ceph.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
# Start the ceph-mgr daemon, after copying in the keyring
ceph.succeed(
"mkdir -p /var/lib/ceph/mgr/ceph-ceph/",
"ceph auth get-or-create -o /var/lib/ceph/mgr/ceph-ceph/keyring mgr.ceph mon 'allow profile mgr' osd 'allow *' mds 'allow *'",
"chown -R ceph:ceph /var/lib/ceph/mgr/ceph-ceph/",
"systemctl start ceph-mgr-ceph.service",
)
ceph.wait_for_unit("ceph-mgr-ceph")
ceph.wait_until_succeeds("ceph -s | grep 'quorum 0'")
ceph.wait_until_succeeds("ceph -s | grep 'mgr: ceph(active,'")
ceph.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
ceph.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
# Start the ceph-mgr daemon, after copying in the keyring
ceph.succeed(
"mkdir -p /var/lib/ceph/mgr/ceph-ceph/",
"ceph auth get-or-create -o /var/lib/ceph/mgr/ceph-ceph/keyring mgr.ceph mon 'allow profile mgr' osd 'allow *' mds 'allow *'",
"chown -R ceph:ceph /var/lib/ceph/mgr/ceph-ceph/",
"systemctl start ceph-mgr-ceph.service",
)
ceph.wait_for_unit("ceph-mgr-ceph")
ceph.wait_until_succeeds("ceph -s | grep 'quorum 0'")
ceph.wait_until_succeeds("ceph -s | grep 'mgr: ceph(active,'")
ceph.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
ceph.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
# test the actual storage
ceph.succeed(
"ceph osd pool create single-node-test 32 32",
"ceph osd pool ls | grep 'single-node-test'",
# test the actual storage
ceph.succeed(
"ceph osd pool create single-node-test 32 32",
"ceph osd pool ls | grep 'single-node-test'",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable single-node-test nixos-test",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable single-node-test nixos-test",
"ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'",
)
ceph.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
ceph.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
ceph.wait_until_succeeds("ceph -s | grep '33 active+clean'")
ceph.fail(
# the old pool should be gone
"ceph osd pool ls | grep 'multi-node-test'",
# deleting the pool should fail without setting mon_allow_pool_delete
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
)
"ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'",
)
ceph.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
ceph.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
ceph.wait_until_succeeds("ceph -s | grep '33 active+clean'")
ceph.fail(
# the old pool should be gone
"ceph osd pool ls | grep 'multi-node-test'",
# deleting the pool should fail without setting mon_allow_pool_delete
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
)
# rebooting gets rid of any potential tmpfs mounts or device-mapper devices
ceph.shutdown()
ceph.start()
ceph.wait_for_unit("default.target")
# rebooting gets rid of any potential tmpfs mounts or device-mapper devices
ceph.shutdown()
ceph.start()
ceph.wait_for_unit("default.target")
# Start it up (again OSDs first due to memory constraints of cryptsetup and mgr)
ceph.systemctl("start ceph-mon-0.service")
ceph.wait_for_unit("ceph-mon-0")
ceph.systemctl("start ceph-osd-0.service")
ceph.wait_for_unit("ceph-osd-0")
ceph.systemctl("start ceph-osd-1.service")
ceph.wait_for_unit("ceph-osd-1")
ceph.systemctl("start ceph-osd-2.service")
ceph.wait_for_unit("ceph-osd-2")
ceph.systemctl("start ceph-mgr-ceph.service")
ceph.wait_for_unit("ceph-mgr-ceph")
# Start it up (again OSDs first due to memory constraints of cryptsetup and mgr)
ceph.systemctl("start ceph-mon-0.service")
ceph.wait_for_unit("ceph-mon-0")
ceph.systemctl("start ceph-osd-0.service")
ceph.wait_for_unit("ceph-osd-0")
ceph.systemctl("start ceph-osd-1.service")
ceph.wait_for_unit("ceph-osd-1")
ceph.systemctl("start ceph-osd-2.service")
ceph.wait_for_unit("ceph-osd-2")
ceph.systemctl("start ceph-mgr-ceph.service")
ceph.wait_for_unit("ceph-mgr-ceph")
# Ensure the cluster comes back up again
ceph.succeed("ceph -s | grep 'mon: 1 daemons'")
ceph.wait_until_succeeds("ceph -s | grep 'quorum 0'")
ceph.wait_until_succeeds("ceph osd stat | grep -E '3 osds: 3 up[^,]*, 3 in'")
ceph.wait_until_succeeds("ceph -s | grep 'mgr: ceph(active,'")
ceph.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
}
)
# Ensure the cluster comes back up again
ceph.succeed("ceph -s | grep 'mon: 1 daemons'")
ceph.wait_until_succeeds("ceph -s | grep 'quorum 0'")
ceph.wait_until_succeeds("ceph osd stat | grep -E '3 osds: 3 up[^,]*, 3 in'")
ceph.wait_until_succeeds("ceph -s | grep 'mgr: ceph(active,'")
ceph.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
}
+205 -211
View File
@@ -1,236 +1,230 @@
import ./make-test-python.nix (
{ pkgs, lib, ... }:
{ lib, ... }:
let
cfg = {
clusterId = "066ae264-2a5d-4729-8001-6ad265f50b03";
monA = {
name = "a";
ip = "192.168.1.1";
};
osd0 = {
name = "0";
key = "AQBCEJNa3s8nHRAANvdsr93KqzBznuIWm2gOGg==";
uuid = "55ba2294-3e24-478f-bee0-9dca4c231dd9";
};
osd1 = {
name = "1";
key = "AQBEEJNac00kExAAXEgy943BGyOpVH1LLlHafQ==";
uuid = "5e97a838-85b6-43b0-8950-cb56d554d1e5";
};
osd2 = {
name = "2";
key = "AQAdyhZeIaUlARAAGRoidDAmS6Vkp546UFEf5w==";
uuid = "ea999274-13d0-4dd5-9af9-ad25a324f72f";
};
let
cfg = {
clusterId = "066ae264-2a5d-4729-8001-6ad265f50b03";
monA = {
name = "a";
ip = "192.168.1.1";
};
generateCephConfig =
{ daemonConfig }:
{
enable = true;
global = {
fsid = cfg.clusterId;
monHost = cfg.monA.ip;
monInitialMembers = cfg.monA.name;
};
}
// daemonConfig;
osd0 = {
name = "0";
key = "AQBCEJNa3s8nHRAANvdsr93KqzBznuIWm2gOGg==";
uuid = "55ba2294-3e24-478f-bee0-9dca4c231dd9";
};
osd1 = {
name = "1";
key = "AQBEEJNac00kExAAXEgy943BGyOpVH1LLlHafQ==";
uuid = "5e97a838-85b6-43b0-8950-cb56d554d1e5";
};
osd2 = {
name = "2";
key = "AQAdyhZeIaUlARAAGRoidDAmS6Vkp546UFEf5w==";
uuid = "ea999274-13d0-4dd5-9af9-ad25a324f72f";
};
};
generateCephConfig =
{ daemonConfig }:
{
enable = true;
global = {
fsid = cfg.clusterId;
monHost = cfg.monA.ip;
monInitialMembers = cfg.monA.name;
};
}
// daemonConfig;
generateHost =
{
pkgs,
cephConfig,
networkConfig,
...
}:
{
virtualisation = {
emptyDiskImages = [
20480
20480
20480
];
vlans = [ 1 ];
};
networking = networkConfig;
environment.systemPackages = with pkgs; [
bash
sudo
ceph
xfsprogs
generateHost =
{
cephConfig,
networkConfig,
}:
{ pkgs, ... }:
{
virtualisation = {
emptyDiskImages = [
20480
20480
20480
];
boot.kernelModules = [ "xfs" ];
services.ceph = cephConfig;
vlans = [ 1 ];
};
networkMonA = {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
{
address = cfg.monA.ip;
prefixLength = 24;
}
networking = networkConfig;
environment.systemPackages = with pkgs; [
bash
sudo
ceph
xfsprogs
];
boot.kernelModules = [ "xfs" ];
services.ceph = cephConfig;
};
cephConfigMonA = generateCephConfig {
daemonConfig = {
mon = {
enable = true;
daemons = [ cfg.monA.name ];
};
mgr = {
enable = true;
daemons = [ cfg.monA.name ];
};
osd = {
enable = true;
daemons = [
cfg.osd0.name
cfg.osd1.name
cfg.osd2.name
];
};
networkMonA = {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = lib.mkOverride 0 [
{
address = cfg.monA.ip;
prefixLength = 24;
}
];
};
cephConfigMonA = generateCephConfig {
daemonConfig = {
mon = {
enable = true;
daemons = [ cfg.monA.name ];
};
mgr = {
enable = true;
daemons = [ cfg.monA.name ];
};
osd = {
enable = true;
daemons = [
cfg.osd0.name
cfg.osd1.name
cfg.osd2.name
];
};
};
};
# Following deployment is based on the manual deployment described here:
# https://docs.ceph.com/docs/master/install/manual-deployment/
# For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/
testscript =
{ ... }:
''
start_all()
# Following deployment is based on the manual deployment described here:
# https://docs.ceph.com/docs/master/install/manual-deployment/
# For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/
testScript = ''
start_all()
monA.wait_for_unit("network.target")
monA.wait_for_unit("network.target")
# Bootstrap ceph-mon daemon
monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.succeed("ceph mon enable-msgr2")
monA.succeed("ceph config set mon auth_allow_insecure_global_id_reclaim false")
# Bootstrap ceph-mon daemon
monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.succeed("ceph mon enable-msgr2")
monA.succeed("ceph config set mon auth_allow_insecure_global_id_reclaim false")
# Can't check ceph status until a mon is up
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Can't check ceph status until a mon is up
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Start the ceph-mgr daemon, after copying in the keyring
monA.succeed(
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mgr-a")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Start the ceph-mgr daemon, after copying in the keyring
monA.succeed(
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mgr-a")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Bootstrap OSDs
monA.succeed(
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"echo bluestore > /var/lib/ceph/osd/ceph-${cfg.osd0.name}/type",
"ln -sf /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}/block",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"echo bluestore > /var/lib/ceph/osd/ceph-${cfg.osd1.name}/type",
"ln -sf /dev/vdc /var/lib/ceph/osd/ceph-${cfg.osd1.name}/block",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"echo bluestore > /var/lib/ceph/osd/ceph-${cfg.osd2.name}/type",
"ln -sf /dev/vdd /var/lib/ceph/osd/ceph-${cfg.osd2.name}/block",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd2.name}/keyring --name osd.${cfg.osd2.name} --add-key ${cfg.osd2.key}",
'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd2.key}"}\' | ceph osd new ${cfg.osd2.uuid} -i -',
)
# Bootstrap OSDs
monA.succeed(
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"echo bluestore > /var/lib/ceph/osd/ceph-${cfg.osd0.name}/type",
"ln -sf /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}/block",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"echo bluestore > /var/lib/ceph/osd/ceph-${cfg.osd1.name}/type",
"ln -sf /dev/vdc /var/lib/ceph/osd/ceph-${cfg.osd1.name}/block",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"echo bluestore > /var/lib/ceph/osd/ceph-${cfg.osd2.name}/type",
"ln -sf /dev/vdd /var/lib/ceph/osd/ceph-${cfg.osd2.name}/block",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd2.name}/keyring --name osd.${cfg.osd2.name} --add-key ${cfg.osd2.key}",
'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd2.key}"}\' | ceph osd new ${cfg.osd2.uuid} -i -',
)
# Initialize the OSDs with regular filestore
monA.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"ceph-osd -i ${cfg.osd2.name} --mkfs --osd-uuid ${cfg.osd2.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}",
"systemctl start ceph-osd-${cfg.osd1.name}",
"systemctl start ceph-osd-${cfg.osd2.name}",
)
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
# Initialize the OSDs with regular filestore
monA.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"ceph-osd -i ${cfg.osd2.name} --mkfs --osd-uuid ${cfg.osd2.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}",
"systemctl start ceph-osd-${cfg.osd1.name}",
"systemctl start ceph-osd-${cfg.osd2.name}",
)
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.succeed(
"ceph osd pool create single-node-test 32 32",
"ceph osd pool ls | grep 'single-node-test'",
monA.succeed(
"ceph osd pool create single-node-test 32 32",
"ceph osd pool ls | grep 'single-node-test'",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable single-node-test nixos-test",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable single-node-test nixos-test",
"ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'",
)
monA.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
monA.succeed(
"ceph osd getcrushmap -o crush",
"crushtool -d crush -o decrushed",
"sed 's/step chooseleaf firstn 0 type host/step chooseleaf firstn 0 type osd/' decrushed > modcrush",
"crushtool -c modcrush -o recrushed",
"ceph osd setcrushmap -i recrushed",
"ceph osd pool set single-node-other-test size 2",
)
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.wait_until_succeeds("ceph -s | grep '33 active+clean'")
monA.fail(
"ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
)
"ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'",
)
monA.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
monA.succeed(
"ceph osd getcrushmap -o crush",
"crushtool -d crush -o decrushed",
"sed 's/step chooseleaf firstn 0 type host/step chooseleaf firstn 0 type osd/' decrushed > modcrush",
"crushtool -c modcrush -o recrushed",
"ceph osd setcrushmap -i recrushed",
"ceph osd pool set single-node-other-test size 2",
)
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.wait_until_succeeds("ceph -s | grep '33 active+clean'")
monA.fail(
"ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
)
# Shut down ceph by stopping ceph.target.
monA.succeed("systemctl stop ceph.target")
# Shut down ceph by stopping ceph.target.
monA.succeed("systemctl stop ceph.target")
# Start it up
monA.succeed("systemctl start ceph.target")
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.wait_for_unit("ceph-mgr-${cfg.monA.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd0.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd1.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd2.name}")
# Start it up
monA.succeed("systemctl start ceph.target")
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.wait_for_unit("ceph-mgr-${cfg.monA.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd0.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd1.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd2.name}")
# Ensure the cluster comes back up again
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
in
{
name = "basic-single-node-ceph-cluster-bluestore";
meta = with pkgs.lib.maintainers; {
maintainers = [ lukegb ];
# Ensure the cluster comes back up again
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
in
{
name = "basic-single-node-ceph-cluster-bluestore";
meta = with lib.maintainers; {
maintainers = [ lukegb ];
};
nodes = {
monA = generateHost {
cephConfig = cephConfigMonA;
networkConfig = networkMonA;
};
};
nodes = {
monA = generateHost {
pkgs = pkgs;
cephConfig = cephConfigMonA;
networkConfig = networkMonA;
};
};
testScript = testscript;
}
)
inherit testScript;
}
+218 -224
View File
@@ -1,250 +1,244 @@
import ./make-test-python.nix (
{ pkgs, lib, ... }:
{ lib, ... }:
let
cfg = {
clusterId = "066ae264-2a5d-4729-8001-6ad265f50b03";
monA = {
name = "a";
ip = "192.168.1.1";
};
osd0 = {
name = "0";
key = "AQBCEJNa3s8nHRAANvdsr93KqzBznuIWm2gOGg==";
uuid = "55ba2294-3e24-478f-bee0-9dca4c231dd9";
};
osd1 = {
name = "1";
key = "AQBEEJNac00kExAAXEgy943BGyOpVH1LLlHafQ==";
uuid = "5e97a838-85b6-43b0-8950-cb56d554d1e5";
};
osd2 = {
name = "2";
key = "AQAdyhZeIaUlARAAGRoidDAmS6Vkp546UFEf5w==";
uuid = "ea999274-13d0-4dd5-9af9-ad25a324f72f";
};
let
cfg = {
clusterId = "066ae264-2a5d-4729-8001-6ad265f50b03";
monA = {
name = "a";
ip = "192.168.1.1";
};
generateCephConfig =
{ daemonConfig }:
{
enable = true;
global = {
fsid = cfg.clusterId;
monHost = cfg.monA.ip;
monInitialMembers = cfg.monA.name;
};
}
// daemonConfig;
osd0 = {
name = "0";
key = "AQBCEJNa3s8nHRAANvdsr93KqzBznuIWm2gOGg==";
uuid = "55ba2294-3e24-478f-bee0-9dca4c231dd9";
};
osd1 = {
name = "1";
key = "AQBEEJNac00kExAAXEgy943BGyOpVH1LLlHafQ==";
uuid = "5e97a838-85b6-43b0-8950-cb56d554d1e5";
};
osd2 = {
name = "2";
key = "AQAdyhZeIaUlARAAGRoidDAmS6Vkp546UFEf5w==";
uuid = "ea999274-13d0-4dd5-9af9-ad25a324f72f";
};
};
generateCephConfig =
{ daemonConfig }:
{
enable = true;
global = {
fsid = cfg.clusterId;
monHost = cfg.monA.ip;
monInitialMembers = cfg.monA.name;
};
}
// daemonConfig;
generateHost =
{
pkgs,
cephConfig,
networkConfig,
...
}:
{
virtualisation = {
emptyDiskImages = [
20480
20480
20480
];
vlans = [ 1 ];
};
networking = networkConfig;
environment.systemPackages = with pkgs; [
bash
sudo
ceph
xfsprogs
generateHost =
{
cephConfig,
networkConfig,
}:
{ pkgs, ... }:
{
virtualisation = {
emptyDiskImages = [
20480
20480
20480
];
boot.kernelModules = [ "xfs" ];
services.ceph = cephConfig;
vlans = [ 1 ];
};
networkMonA = {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
{
address = cfg.monA.ip;
prefixLength = 24;
}
networking = networkConfig;
environment.systemPackages = with pkgs; [
bash
sudo
ceph
xfsprogs
];
boot.kernelModules = [ "xfs" ];
services.ceph = cephConfig;
};
cephConfigMonA = generateCephConfig {
daemonConfig = {
mon = {
enable = true;
daemons = [ cfg.monA.name ];
};
mgr = {
enable = true;
daemons = [ cfg.monA.name ];
};
osd = {
enable = true;
daemons = [
cfg.osd0.name
cfg.osd1.name
cfg.osd2.name
];
};
networkMonA = {
dhcpcd.enable = false;
interfaces.eth1.ipv4.addresses = lib.mkOverride 0 [
{
address = cfg.monA.ip;
prefixLength = 24;
}
];
};
cephConfigMonA = generateCephConfig {
daemonConfig = {
mon = {
enable = true;
daemons = [ cfg.monA.name ];
};
mgr = {
enable = true;
daemons = [ cfg.monA.name ];
};
osd = {
enable = true;
daemons = [
cfg.osd0.name
cfg.osd1.name
cfg.osd2.name
];
};
};
};
# Following deployment is based on the manual deployment described here:
# https://docs.ceph.com/docs/master/install/manual-deployment/
# For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/
testscript =
{ ... }:
''
start_all()
# Following deployment is based on the manual deployment described here:
# https://docs.ceph.com/docs/master/install/manual-deployment/
# For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/
testScript = ''
start_all()
monA.wait_for_unit("network.target")
monA.wait_for_unit("network.target")
# Bootstrap ceph-mon daemon
monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.succeed("ceph mon enable-msgr2")
monA.succeed("ceph config set mon auth_allow_insecure_global_id_reclaim false")
# Bootstrap ceph-mon daemon
monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.succeed("ceph mon enable-msgr2")
monA.succeed("ceph config set mon auth_allow_insecure_global_id_reclaim false")
# Can't check ceph status until a mon is up
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Can't check ceph status until a mon is up
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Start the ceph-mgr daemon, after copying in the keyring
monA.succeed(
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mgr-a")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Start the ceph-mgr daemon, after copying in the keyring
monA.succeed(
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}",
)
monA.wait_for_unit("ceph-mgr-a")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Bootstrap OSDs
monA.succeed(
"mkfs.xfs /dev/vdb",
"mkfs.xfs /dev/vdc",
"mkfs.xfs /dev/vdd",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mount /dev/vdc /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"mount /dev/vdd /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd2.name}/keyring --name osd.${cfg.osd2.name} --add-key ${cfg.osd2.key}",
'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd2.key}"}\' | ceph osd new ${cfg.osd2.uuid} -i -',
)
# Bootstrap OSDs
monA.succeed(
"mkfs.xfs /dev/vdb",
"mkfs.xfs /dev/vdc",
"mkfs.xfs /dev/vdd",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mount /dev/vdc /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"mount /dev/vdd /var/lib/ceph/osd/ceph-${cfg.osd2.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd2.name}/keyring --name osd.${cfg.osd2.name} --add-key ${cfg.osd2.key}",
'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
'echo \'{"cephx_secret": "${cfg.osd2.key}"}\' | ceph osd new ${cfg.osd2.uuid} -i -',
)
# Initialize the OSDs with regular filestore
monA.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"ceph-osd -i ${cfg.osd2.name} --mkfs --osd-uuid ${cfg.osd2.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}",
"systemctl start ceph-osd-${cfg.osd1.name}",
"systemctl start ceph-osd-${cfg.osd2.name}",
)
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
# Initialize the OSDs with regular filestore
monA.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"ceph-osd -i ${cfg.osd2.name} --mkfs --osd-uuid ${cfg.osd2.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}",
"systemctl start ceph-osd-${cfg.osd1.name}",
"systemctl start ceph-osd-${cfg.osd2.name}",
)
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.succeed(
"ceph osd pool create single-node-test 32 32",
"ceph osd pool ls | grep 'single-node-test'",
monA.succeed(
"ceph osd pool create single-node-test 32 32",
"ceph osd pool ls | grep 'single-node-test'",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable single-node-test nixos-test",
# We need to enable an application on the pool, otherwise it will
# stay unhealthy in state POOL_APP_NOT_ENABLED.
# Creating a CephFS would do this automatically, but we haven't done that here.
# See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application
# We use the custom application name "nixos-test" for this.
"ceph osd pool application enable single-node-test nixos-test",
"ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'",
)
monA.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
monA.succeed(
"ceph osd getcrushmap -o crush",
"crushtool -d crush -o decrushed",
"sed 's/step chooseleaf firstn 0 type host/step chooseleaf firstn 0 type osd/' decrushed > modcrush",
"crushtool -c modcrush -o recrushed",
"ceph osd setcrushmap -i recrushed",
"ceph osd pool set single-node-other-test size 2",
)
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.wait_until_succeeds("ceph -s | grep '33 active+clean'")
monA.fail(
"ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
)
"ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'",
)
monA.wait_until_succeeds("ceph -s | grep '2 pools, 33 pgs'")
monA.succeed(
"ceph osd getcrushmap -o crush",
"crushtool -d crush -o decrushed",
"sed 's/step chooseleaf firstn 0 type host/step chooseleaf firstn 0 type osd/' decrushed > modcrush",
"crushtool -c modcrush -o recrushed",
"ceph osd setcrushmap -i recrushed",
"ceph osd pool set single-node-other-test size 2",
)
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
monA.wait_until_succeeds("ceph -s | grep '33 active+clean'")
monA.fail(
"ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
)
# Shut down ceph by stopping ceph.target.
monA.succeed("systemctl stop ceph.target")
# Shut down ceph by stopping ceph.target.
monA.succeed("systemctl stop ceph.target")
# Start it up
monA.succeed("systemctl start ceph.target")
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.wait_for_unit("ceph-mgr-${cfg.monA.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd0.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd1.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd2.name}")
# Start it up
monA.succeed("systemctl start ceph.target")
monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
monA.wait_for_unit("ceph-mgr-${cfg.monA.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd0.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd1.name}")
monA.wait_for_unit("ceph-osd-${cfg.osd2.name}")
# Ensure the cluster comes back up again
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
# Ensure the cluster comes back up again
monA.succeed("ceph -s | grep 'mon: 1 daemons'")
monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
monA.wait_until_succeeds("ceph osd stat | grep -e '3 osds: 3 up[^,]*, 3 in'")
monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
# Enable the dashboard and recheck health
monA.succeed(
"ceph mgr module enable dashboard",
"ceph config set mgr mgr/dashboard/ssl false",
# default is 8080 but it's better to be explicit
"ceph config set mgr mgr/dashboard/server_port 8080",
)
monA.wait_for_open_port(8080)
monA.wait_until_succeeds("curl -q --fail http://localhost:8080")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
in
{
name = "basic-single-node-ceph-cluster";
meta = with pkgs.lib.maintainers; {
maintainers = [
lejonet
johanot
];
# Enable the dashboard and recheck health
monA.succeed(
"ceph mgr module enable dashboard",
"ceph config set mgr mgr/dashboard/ssl false",
# default is 8080 but it's better to be explicit
"ceph config set mgr mgr/dashboard/server_port 8080",
)
monA.wait_for_open_port(8080)
monA.wait_until_succeeds("curl -q --fail http://localhost:8080")
monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
'';
in
{
name = "basic-single-node-ceph-cluster";
meta = with lib.maintainers; {
maintainers = [
lejonet
johanot
];
};
nodes = {
monA = generateHost {
cephConfig = cephConfigMonA;
networkConfig = networkMonA;
};
};
nodes = {
monA = generateHost {
pkgs = pkgs;
cephConfig = cephConfigMonA;
networkConfig = networkMonA;
};
};
testScript = testscript;
}
)
inherit testScript;
}
+2 -7
View File
@@ -1,10 +1,5 @@
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
}:
{ runTest, pkgs, ... }:
with import ../lib/testing-python.nix { inherit system pkgs; };
let
mkSpec =
{
@@ -63,7 +58,7 @@ let
specs,
testScript,
}:
makeTest {
runTest {
name = "certmgr-" + svcManager;
nodes = {
machine =
+82 -84
View File
@@ -1,89 +1,87 @@
import ./make-test-python.nix (
{ pkgs, ... }:
{
name = "cfssl";
{ pkgs, ... }:
{
name = "cfssl";
nodes.machine =
{
config,
lib,
pkgs,
...
}:
{
networking.firewall.allowedTCPPorts = [ config.services.cfssl.port ];
nodes.machine =
{
config,
lib,
pkgs,
...
}:
{
networking.firewall.allowedTCPPorts = [ config.services.cfssl.port ];
services.cfssl.enable = true;
systemd.services.cfssl.after = [ "cfssl-init.service" ];
services.cfssl.enable = true;
systemd.services.cfssl.after = [ "cfssl-init.service" ];
systemd.services.cfssl-init = {
description = "Initialize the cfssl CA";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "cfssl";
Type = "oneshot";
WorkingDirectory = config.services.cfssl.dataDir;
};
script = with pkgs; ''
${cfssl}/bin/cfssl genkey -initca ${
pkgs.writeText "ca.json" (
builtins.toJSON {
hosts = [ "ca.example.com" ];
key = {
algo = "rsa";
size = 4096;
};
names = [
{
C = "US";
L = "San Francisco";
O = "Internet Widgets, LLC";
OU = "Certificate Authority";
ST = "California";
}
];
}
)
} | ${cfssl}/bin/cfssljson -bare ca
'';
systemd.services.cfssl-init = {
description = "Initialize the cfssl CA";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "cfssl";
Type = "oneshot";
WorkingDirectory = config.services.cfssl.dataDir;
};
};
testScript =
let
cfsslrequest =
with pkgs;
writeScript "cfsslrequest" ''
curl -f -X POST -H "Content-Type: application/json" -d @${csr} \
http://localhost:8888/api/v1/cfssl/newkey | ${cfssl}/bin/cfssljson /tmp/certificate
'';
csr = pkgs.writeText "csr.json" (
builtins.toJSON {
CN = "www.example.com";
hosts = [
"example.com"
"www.example.com"
];
key = {
algo = "rsa";
size = 2048;
};
names = [
{
C = "US";
L = "San Francisco";
O = "Example Company, LLC";
OU = "Operations";
ST = "California";
script = with pkgs; ''
${cfssl}/bin/cfssl genkey -initca ${
pkgs.writeText "ca.json" (
builtins.toJSON {
hosts = [ "ca.example.com" ];
key = {
algo = "rsa";
size = 4096;
};
names = [
{
C = "US";
L = "San Francisco";
O = "Internet Widgets, LLC";
OU = "Certificate Authority";
ST = "California";
}
];
}
];
}
);
in
''
machine.wait_for_unit("cfssl.service")
machine.wait_until_succeeds("${cfsslrequest}")
machine.succeed("ls /tmp/certificate-key.pem")
'';
}
)
)
} | ${cfssl}/bin/cfssljson -bare ca
'';
};
};
testScript =
let
cfsslrequest =
with pkgs;
writeScript "cfsslrequest" ''
curl -f -X POST -H "Content-Type: application/json" -d @${csr} \
http://localhost:8888/api/v1/cfssl/newkey | ${cfssl}/bin/cfssljson /tmp/certificate
'';
csr = pkgs.writeText "csr.json" (
builtins.toJSON {
CN = "www.example.com";
hosts = [
"example.com"
"www.example.com"
];
key = {
algo = "rsa";
size = 2048;
};
names = [
{
C = "US";
L = "San Francisco";
O = "Example Company, LLC";
OU = "Operations";
ST = "California";
}
];
}
);
in
''
machine.wait_for_unit("cfssl.service")
machine.wait_until_succeeds("${cfsslrequest}")
machine.succeed("ls /tmp/certificate-key.pem")
'';
}
+20 -28
View File
@@ -1,32 +1,24 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "chrony-ptp";
{ lib, ... }:
{
name = "chrony-ptp";
meta = {
maintainers = with lib.maintainers; [ gkleen ];
meta.maintainers = with lib.maintainers; [ gkleen ];
nodes.qemuGuest = {
boot.kernelModules = [ "ptp_kvm" ];
services.chrony = {
enable = true;
extraConfig = ''
refclock PHC /dev/ptp_kvm poll 2 dpoll -2 offset 0 stratum 3
'';
};
};
nodes = {
qemuGuest =
{ lib, ... }:
{
boot.kernelModules = [ "ptp_kvm" ];
testScript = ''
start_all()
services.chrony = {
enable = true;
extraConfig = ''
refclock PHC /dev/ptp_kvm poll 2 dpoll -2 offset 0 stratum 3
'';
};
};
};
testScript = ''
start_all()
qemuGuest.wait_for_unit('multi-user.target')
qemuGuest.succeed('systemctl is-active chronyd.service')
'';
}
)
qemuGuest.wait_for_unit('multi-user.target')
qemuGuest.succeed('systemctl is-active chronyd.service')
'';
}
+20 -26
View File
@@ -1,29 +1,23 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "chrony";
{ lib, ... }:
{
name = "chrony";
meta = {
maintainers = with lib.maintainers; [ fpletz ];
meta.maintainers = with lib.maintainers; [ fpletz ];
nodes.machine = {
services.chrony.enable = true;
specialisation.hardened.configuration = {
services.chrony.enableMemoryLocking = true;
};
};
nodes = {
machine = {
services.chrony.enable = true;
specialisation.hardened.configuration = {
services.chrony.enableMemoryLocking = true;
};
};
};
testScript = ''
machine.start()
machine.wait_for_unit('multi-user.target')
machine.succeed('systemctl is-active chronyd.service')
machine.succeed('/run/booted-system/specialisation/hardened/bin/switch-to-configuration test')
machine.succeed('systemctl restart chronyd.service')
machine.wait_for_unit('chronyd.service')
'';
}
)
testScript = ''
machine.start()
machine.wait_for_unit('multi-user.target')
machine.succeed('systemctl is-active chronyd.service')
machine.succeed('/run/booted-system/specialisation/hardened/bin/switch-to-configuration test')
machine.succeed('systemctl restart chronyd.service')
machine.wait_for_unit('chronyd.service')
'';
}
+6 -17
View File
@@ -1,12 +1,4 @@
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
{ lib, pkgs, ... }:
let
# Hostname can also be set through "hostname" in user-data.
# This is how proxmox configures hostname through cloud-init.
@@ -27,16 +19,13 @@ let
${pkgs.cdrkit}/bin/genisoimage -volid cidata -joliet -rock -o $out/metadata.iso $out/iso
'';
};
in
makeTest {
{
name = "cloud-init-hostname";
meta = with pkgs.lib.maintainers; {
maintainers = [
lewo
illustris
];
};
meta.maintainers = with lib.maintainers; [
lewo
illustris
];
nodes.machine2 =
{ ... }:
+15 -24
View File
@@ -1,11 +1,4 @@
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
{ lib, pkgs, ... }:
let
inherit (import ./ssh-keys.nix pkgs)
@@ -61,27 +54,25 @@ let
};
in
makeTest {
{
name = "cloud-init";
meta.maintainers = with pkgs.lib.maintainers; [
meta.maintainers = with lib.maintainers; [
lewo
illustris
];
nodes.machine =
{ ... }:
{
virtualisation.qemu.options = [
"-cdrom"
"${metadataDrive}/metadata.iso"
];
services.cloud-init = {
enable = true;
network.enable = true;
};
services.openssh.enable = true;
networking.hostName = "";
networking.useDHCP = false;
nodes.machine = {
virtualisation.qemu.options = [
"-cdrom"
"${metadataDrive}/metadata.iso"
];
services.cloud-init = {
enable = true;
network.enable = true;
};
services.openssh.enable = true;
networking.hostName = "";
networking.useDHCP = false;
};
testScript = ''
# To wait until cloud-init terminates its run
unnamed.wait_for_unit("cloud-init-local.service")
+24 -36
View File
@@ -1,41 +1,31 @@
# Test for cntr tool
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
lib ? pkgs.lib,
}:
{ runTest, lib }:
let
inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
mkOCITest =
backend:
makeTest {
runTest {
name = "cntr-${backend}";
meta = {
maintainers = with lib.maintainers; [
sorki
mic92
];
};
meta.maintainers = with lib.maintainers; [
sorki
mic92
];
nodes = {
${backend} =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.cntr ];
virtualisation.oci-containers = {
inherit backend;
containers.nginx = {
image = "nginx-container";
imageStream = pkgs.dockerTools.examples.nginxStream;
ports = [ "8181:80" ];
};
nodes.${backend} =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.cntr ];
virtualisation.oci-containers = {
inherit backend;
containers.nginx = {
image = "nginx-container";
imageStream = pkgs.dockerTools.examples.nginxStream;
ports = [ "8181:80" ];
};
};
};
};
testScript = ''
start_all()
@@ -53,18 +43,16 @@ let
'';
};
mkContainersTest = makeTest {
mkContainersTest = runTest {
name = "cntr-containers";
meta = with pkgs.lib.maintainers; {
maintainers = [
sorki
mic92
];
};
meta.maintainers = with lib.maintainers; [
sorki
mic92
];
nodes.machine =
{ lib, ... }:
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.cntr ];
containers.test = {
+24 -28
View File
@@ -45,8 +45,9 @@
# requirements, but would probably allow both aarch64/x86_64 to work.
#
let
{ lib, ... }:
let
# Creates a node. If 'joinNode' parameter, a string containing an IP address,
# is non-null, then the CockroachDB server will attempt to join/connect to
# the cluster node specified at that address.
@@ -59,7 +60,6 @@ let
config,
...
}:
{
# Bank/TPC-C benchmarks take some memory to complete
virtualisation.memorySize = 2048;
@@ -103,32 +103,28 @@ let
${pkgs.chrony}/bin/chronyc waitsync
'';
};
in
import ./make-test-python.nix (
{ pkgs, ... }:
{
name = "cockroachdb";
meta.maintainers = with pkgs.lib.maintainers; [ thoughtpolice ];
{
name = "cockroachdb";
meta.maintainers = with lib.maintainers; [ thoughtpolice ];
nodes = {
node1 = makeNode "country=us,region=east,dc=1" "192.168.1.1" null;
node2 = makeNode "country=us,region=west,dc=2b" "192.168.1.2" "192.168.1.1";
node3 = makeNode "country=eu,region=west,dc=2" "192.168.1.3" "192.168.1.1";
};
nodes = {
node1 = makeNode "country=us,region=east,dc=1" "192.168.1.1" null;
node2 = makeNode "country=us,region=west,dc=2b" "192.168.1.2" "192.168.1.1";
node3 = makeNode "country=eu,region=west,dc=2" "192.168.1.3" "192.168.1.1";
};
# NOTE: All the nodes must start in order and you must NOT use startAll, because
# there's otherwise no way to guarantee that node1 will start before the others try
# to join it.
testScript = ''
for node in node1, node2, node3:
node.start()
node.wait_for_unit("cockroachdb")
node1.succeed(
"cockroach sql --host=192.168.1.1 --insecure -e 'SHOW ALL CLUSTER SETTINGS' 2>&1",
"cockroach workload init bank 'postgresql://root@192.168.1.1:26257?sslmode=disable'",
"cockroach workload run bank --duration=1m 'postgresql://root@192.168.1.1:26257?sslmode=disable'",
)
'';
}
)
# NOTE: All the nodes must start in order and you must NOT use startAll, because
# there's otherwise no way to guarantee that node1 will start before the others try
# to join it.
testScript = ''
for node in node1, node2, node3:
node.start()
node.wait_for_unit("cockroachdb")
node1.succeed(
"cockroach sql --host=192.168.1.1 --insecure -e 'SHOW ALL CLUSTER SETTINGS' 2>&1",
"cockroach workload init bank 'postgresql://root@192.168.1.1:26257?sslmode=disable'",
"cockroach workload run bank --duration=1m 'postgresql://root@192.168.1.1:26257?sslmode=disable'",
)
'';
}
+43 -49
View File
@@ -1,61 +1,55 @@
import ./make-test-python.nix ({
{
name = "corerad";
nodes = {
router =
{ config, pkgs, ... }:
{
config = {
# This machine simulates a router with IPv6 forwarding and a static IPv6 address.
boot.kernel.sysctl = {
"net.ipv6.conf.all.forwarding" = true;
};
networking.interfaces.eth1 = {
ipv6.addresses = [
{
address = "fd00:dead:beef:dead::1";
prefixLength = 64;
}
];
};
services.corerad = {
enable = true;
# Serve router advertisements to the client machine with prefix information matching
# any IPv6 /64 prefixes configured on this interface.
#
# This configuration is identical to the example in the CoreRAD NixOS module.
settings = {
interfaces = [
{
name = "eth0";
monitor = true;
}
{
name = "eth1";
advertise = true;
prefix = [ { prefix = "::/64"; } ];
}
];
debug = {
address = "localhost:9430";
prometheus = true;
};
};
router = {
# This machine simulates a router with IPv6 forwarding and a static IPv6 address.
boot.kernel.sysctl = {
"net.ipv6.conf.all.forwarding" = true;
};
networking.interfaces.eth1 = {
ipv6.addresses = [
{
address = "fd00:dead:beef:dead::1";
prefixLength = 64;
}
];
};
services.corerad = {
enable = true;
# Serve router advertisements to the client machine with prefix information matching
# any IPv6 /64 prefixes configured on this interface.
#
# This configuration is identical to the example in the CoreRAD NixOS module.
settings = {
interfaces = [
{
name = "eth0";
monitor = true;
}
{
name = "eth1";
advertise = true;
prefix = [ { prefix = "::/64"; } ];
}
];
debug = {
address = "localhost:9430";
prometheus = true;
};
};
};
};
client =
{ config, pkgs, ... }:
{ pkgs, ... }:
{
# Use IPv6 SLAAC from router advertisements, and install rdisc6 so we can
# trigger one immediately.
config = {
boot.kernel.sysctl = {
"net.ipv6.conf.all.autoconf" = true;
};
environment.systemPackages = with pkgs; [
ndisc6
];
boot.kernel.sysctl = {
"net.ipv6.conf.all.autoconf" = true;
};
environment.systemPackages = with pkgs; [
ndisc6
];
};
};
@@ -97,4 +91,4 @@ import ./make-test-python.nix ({
"corerad_build_info" in out
), "Build info metric was not found in Prometheus output"
'';
})
}
+15 -20
View File
@@ -1,22 +1,17 @@
# This test runs CRI-O and verifies via critest
import ./make-test-python.nix (
{ pkgs, ... }:
{
name = "cri-o";
meta.maintainers = with pkgs.lib; teams.podman.members;
{ lib, ... }:
{
name = "cri-o";
meta.maintainers = lib.teams.podman.members;
nodes = {
crio = {
virtualisation.cri-o.enable = true;
};
};
nodes.crio = {
virtualisation.cri-o.enable = true;
};
testScript = ''
start_all()
crio.wait_for_unit("crio.service")
crio.succeed(
"critest --ginkgo.focus='Runtime info' --runtime-endpoint unix:///var/run/crio/crio.sock"
)
'';
}
)
testScript = ''
start_all()
crio.wait_for_unit("crio.service")
crio.succeed(
"critest --ginkgo.focus='Runtime info' --runtime-endpoint unix:///var/run/crio/crio.sock"
)
'';
}
+4 -10
View File
@@ -3,13 +3,7 @@
# The test checks that certificates issued by a custom
# trusted CA are accepted but those from an unknown CA are rejected.
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
{ runTest, pkgs }:
let
inherit (pkgs) lib;
@@ -104,7 +98,7 @@ let
};
};
curlTest = makeTest {
curlTest = runTest {
name = "custom-ca-curl";
meta.maintainers = with lib.maintainers; [ rnhmjoj ];
nodes.machine = { ... }: webserverConfig;
@@ -121,7 +115,7 @@ let
mkBrowserTest =
browser: testParams:
makeTest {
runTest {
name = "custom-ca-${browser}";
meta.maintainers = with lib.maintainers; [ rnhmjoj ];
@@ -199,7 +193,7 @@ in
{
curl = curlTest;
}
// pkgs.lib.mapAttrs mkBrowserTest {
// lib.mapAttrs mkBrowserTest {
firefox = {
error = "Security Risk";
};
+1 -1
View File
@@ -1,4 +1,4 @@
import ./make-test-python.nix {
{
name = "dhparams";
nodes.machine =
+33 -37
View File
@@ -1,42 +1,38 @@
import ./make-test-python.nix (
{ pkgs, ... }:
let
localProxyPort = 43;
in
{
name = "dnscrypt-proxy2";
meta = with pkgs.lib.maintainers; {
maintainers = [ joachifm ];
};
{ lib, ... }:
let
localProxyPort = 43;
in
{
name = "dnscrypt-proxy2";
meta.maintainers = with lib.maintainers; [ joachifm ];
nodes = {
# A client running the recommended setup: DNSCrypt proxy as a forwarder
# for a caching DNS client.
client =
{ ... }:
{
security.apparmor.enable = true;
nodes = {
# A client running the recommended setup: DNSCrypt proxy as a forwarder
# for a caching DNS client.
client =
{ ... }:
{
security.apparmor.enable = true;
services.dnscrypt-proxy2.enable = true;
services.dnscrypt-proxy2.settings = {
listen_addresses = [ "127.0.0.1:${toString localProxyPort}" ];
sources.public-resolvers = {
urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
cache_file = "public-resolvers.md";
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
refresh_delay = 72;
};
services.dnscrypt-proxy2.enable = true;
services.dnscrypt-proxy2.settings = {
listen_addresses = [ "127.0.0.1:${toString localProxyPort}" ];
sources.public-resolvers = {
urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
cache_file = "public-resolvers.md";
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
refresh_delay = 72;
};
services.dnsmasq.enable = true;
services.dnsmasq.settings.server = [ "127.0.0.1#${toString localProxyPort}" ];
};
};
testScript = ''
client.wait_for_unit("dnsmasq")
client.wait_for_unit("dnscrypt-proxy2")
client.wait_until_succeeds("ss --numeric --udp --listening | grep -q ${toString localProxyPort}")
'';
}
)
services.dnsmasq.enable = true;
services.dnsmasq.settings.server = [ "127.0.0.1#${toString localProxyPort}" ];
};
};
testScript = ''
client.wait_for_unit("dnsmasq")
client.wait_for_unit("dnscrypt-proxy2")
client.wait_until_succeeds("ss --numeric --udp --listening | grep -q ${toString localProxyPort}")
'';
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
import ./make-test-python.nix {
{
name = "dovecot";
nodes.machine =
+1 -1
View File
@@ -1,5 +1,5 @@
# Test for https://github.com/NixOS/nixpkgs/pull/193469
import ./make-test-python.nix {
{
name = "early-mount-options";
nodes.machine = {
+33 -37
View File
@@ -1,42 +1,38 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "earlyoom";
meta = {
maintainers = with lib.maintainers; [
ncfavier
oxalica
];
};
{ lib, ... }:
{
name = "earlyoom";
meta.maintainers = with lib.maintainers; [
ncfavier
oxalica
];
nodes.machine =
{ pkgs, ... }:
{
# Limit VM resource usage.
virtualisation.memorySize = 1024;
nodes.machine =
{ pkgs, ... }:
{
# Limit VM resource usage.
virtualisation.memorySize = 1024;
services.earlyoom = {
enable = true;
# Use SIGKILL, or `tail` will catch SIGTERM and exit successfully.
freeMemKillThreshold = 90;
};
systemd.services.testbloat = {
description = "Create a lot of memory pressure";
serviceConfig = {
ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero";
};
};
services.earlyoom = {
enable = true;
# Use SIGKILL, or `tail` will catch SIGTERM and exit successfully.
freeMemKillThreshold = 90;
};
testScript = ''
machine.wait_for_unit("earlyoom.service")
systemd.services.testbloat = {
description = "Create a lot of memory pressure";
serviceConfig = {
ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero";
};
};
};
with subtest("earlyoom should kill the bad service"):
machine.fail("systemctl start --wait testbloat.service")
assert machine.get_unit_info("testbloat.service")["Result"] == "signal"
output = machine.succeed('journalctl -u earlyoom.service -b0')
assert 'low memory! at or below SIGKILL limits' in output
'';
}
)
testScript = ''
machine.wait_for_unit("earlyoom.service")
with subtest("earlyoom should kill the bad service"):
machine.fail("systemctl start --wait testbloat.service")
assert machine.get_unit_info("testbloat.service")["Result"] == "signal"
output = machine.succeed('journalctl -u earlyoom.service -b0')
assert 'low memory! at or below SIGKILL limits' in output
'';
}
+154 -159
View File
@@ -1,178 +1,173 @@
# This test runs simple etcd cluster
import ../make-test-python.nix (
{ pkgs, ... }:
let
{ lib, pkgs, ... }:
let
runWithOpenSSL =
file: cmd:
pkgs.runCommand file {
buildInputs = [ pkgs.openssl ];
} cmd;
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}
'';
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_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" ''
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}
'';
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]
[ v3_req ]
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" ''
ions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
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
'';
client_openssl_cnf = pkgs.writeText "client-openssl.cnf" ''
ions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
'';
client_openssl_cnf = pkgs.writeText "client-openssl.cnf" ''
ions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
'';
nodeConfig = {
services = {
etcd = {
enable = true;
keyFile = etcd_key;
certFile = etcd_cert;
trustedCaFile = ca_pem;
clientCertAuth = true;
listenClientUrls = [ "https://127.0.0.1:2379" ];
listenPeerUrls = [ "https://0.0.0.0:2380" ];
};
};
nodeConfig = {
services = {
etcd = {
enable = true;
keyFile = etcd_key;
certFile = etcd_cert;
trustedCaFile = ca_pem;
clientCertAuth = true;
listenClientUrls = [ "https://127.0.0.1:2379" ];
listenPeerUrls = [ "https://0.0.0.0:2380" ];
environment.variables = {
ETCD_CERT_FILE = "${etcd_client_cert}";
ETCD_KEY_FILE = "${etcd_client_key}";
ETCD_CA_FILE = "${ca_pem}";
ETCDCTL_ENDPOINTS = "https://127.0.0.1:2379";
ETCDCTL_CACERT = "${ca_pem}";
ETCDCTL_CERT = "${etcd_cert}";
ETCDCTL_KEY = "${etcd_key}";
};
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 = {
ETCD_CERT_FILE = "${etcd_client_cert}";
ETCD_KEY_FILE = "${etcd_client_key}";
ETCD_CA_FILE = "${ca_pem}";
ETCDCTL_ENDPOINTS = "https://127.0.0.1:2379";
ETCDCTL_CACERT = "${ca_pem}";
ETCDCTL_CERT = "${etcd_cert}";
ETCDCTL_KEY = "${etcd_key}";
node2 =
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
];
initialAdvertisePeerUrls = [ "https://node2:2380" ];
};
};
networking.firewall.allowedTCPPorts = [ 2380 ];
};
in
{
name = "etcd-cluster";
meta = with pkgs.lib.maintainers; {
maintainers = [ offline ];
};
nodes = {
node1 =
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
];
initialAdvertisePeerUrls = [ "https://node1:2380" ];
};
node3 =
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
"node3=https://node3:2380"
];
initialAdvertisePeerUrls = [ "https://node3:2380" ];
initialClusterState = "existing";
};
};
};
node2 =
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
];
initialAdvertisePeerUrls = [ "https://node2:2380" ];
};
};
testScript = ''
with subtest("should start etcd cluster"):
node1.start()
node2.start()
node1.wait_for_unit("etcd.service")
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'")
node3 =
{ ... }:
{
require = [ nodeConfig ];
services.etcd = {
initialCluster = [
"node1=https://node1:2380"
"node2=https://node2:2380"
"node3=https://node3:2380"
];
initialAdvertisePeerUrls = [ "https://node3:2380" ];
initialClusterState = "existing";
};
};
};
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")
testScript = ''
with subtest("should start etcd cluster"):
node1.start()
node2.start()
node1.wait_for_unit("etcd.service")
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'")
'';
}
)
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'")
'';
}
+18 -26
View File
@@ -1,30 +1,22 @@
# This test runs simple etcd node
import ../make-test-python.nix (
{ pkgs, ... }:
{
name = "etcd";
meta = with pkgs.lib.maintainers; {
maintainers = [ offline ];
};
{ lib, ... }:
{
name = "etcd";
meta.maintainers = with lib.maintainers; [ offline ];
nodes = {
node =
{ ... }:
{
services.etcd.enable = true;
};
};
nodes.node = {
services.etcd.enable = true;
};
testScript = ''
with subtest("should start etcd node"):
node.start()
node.wait_for_unit("etcd.service")
# Add additional wait for actual readiness
node.wait_until_succeeds("etcdctl endpoint health")
testScript = ''
with subtest("should start etcd node"):
node.start()
node.wait_for_unit("etcd.service")
# Add additional wait for actual readiness
node.wait_until_succeeds("etcdctl endpoint health")
with subtest("should write and read some values to etcd"):
node.succeed("etcdctl put /foo/bar 'Hello world'")
node.succeed("etcdctl get /foo/bar | grep 'Hello world'")
'';
}
)
with subtest("should write and read some values to etcd"):
node.succeed("etcdctl put /foo/bar 'Hello world'")
node.succeed("etcdctl get /foo/bar | grep 'Hello world'")
'';
}
+139 -141
View File
@@ -1,169 +1,167 @@
import ../make-test-python.nix (
{ lib, ... }:
rec {
name = "fcitx5";
meta.maintainers = with lib.maintainers; [ nevivurn ];
{ lib, ... }:
{
name = "fcitx5";
meta.maintainers = with lib.maintainers; [ nevivurn ];
nodes.machine =
{ pkgs, ... }:
{
imports = [
../common/user-account.nix
nodes.machine =
{ pkgs, ... }:
{
imports = [
../common/user-account.nix
];
environment.systemPackages = [
# To avoid clashing with xfce4-terminal
pkgs.alacritty
];
services.displayManager.autoLogin = {
enable = true;
user = "alice";
};
services.xserver = {
enable = true;
displayManager.lightdm.enable = true;
desktopManager.xfce.enable = true;
};
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5.addons = [
pkgs.fcitx5-chinese-addons
pkgs.fcitx5-hangul
pkgs.fcitx5-m17n
pkgs.fcitx5-mozc
];
environment.systemPackages = [
# To avoid clashing with xfce4-terminal
pkgs.alacritty
];
services.displayManager.autoLogin = {
enable = true;
user = "alice";
};
services.xserver = {
enable = true;
displayManager.lightdm.enable = true;
desktopManager.xfce.enable = true;
};
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5.addons = [
pkgs.fcitx5-chinese-addons
pkgs.fcitx5-hangul
pkgs.fcitx5-m17n
pkgs.fcitx5-mozc
];
fcitx5.settings = {
globalOptions = {
"Hotkey"."EnumerateSkipFirst" = "False";
"Hotkey/TriggerKeys"."0" = "Control+space";
"Hotkey/EnumerateForwardKeys"."0" = "Alt+Shift_L";
"Hotkey/EnumerateBackwardKeys"."0" = "Alt+Shift_R";
fcitx5.settings = {
globalOptions = {
"Hotkey"."EnumerateSkipFirst" = "False";
"Hotkey/TriggerKeys"."0" = "Control+space";
"Hotkey/EnumerateForwardKeys"."0" = "Alt+Shift_L";
"Hotkey/EnumerateBackwardKeys"."0" = "Alt+Shift_R";
};
inputMethod = {
"GroupOrder" = {
"0" = "NixOS_test";
};
inputMethod = {
"GroupOrder" = {
"0" = "NixOS_test";
};
"Groups/0" = {
"Default Layout" = "us";
"DefaultIM" = "wbx";
"Name" = "NixOS_test";
};
"Groups/0/Items/0" = {
"Name" = "keyboard-us";
};
"Groups/0/Items/1" = {
"Layout" = "us";
"Name" = "wbx";
};
"Groups/0/Items/2" = {
"Layout" = "us";
"Name" = "hangul";
};
"Groups/0/Items/3" = {
"Layout" = "us";
"Name" = "m17n_sa_harvard-kyoto";
};
"Groups/0/Items/4" = {
"Layout" = "us";
"Name" = "mozc";
};
"Groups/0" = {
"Default Layout" = "us";
"DefaultIM" = "wbx";
"Name" = "NixOS_test";
};
"Groups/0/Items/0" = {
"Name" = "keyboard-us";
};
"Groups/0/Items/1" = {
"Layout" = "us";
"Name" = "wbx";
};
"Groups/0/Items/2" = {
"Layout" = "us";
"Name" = "hangul";
};
"Groups/0/Items/3" = {
"Layout" = "us";
"Name" = "m17n_sa_harvard-kyoto";
};
"Groups/0/Items/4" = {
"Layout" = "us";
"Name" = "mozc";
};
};
};
};
};
testScript =
{ nodes, ... }:
let
user = nodes.machine.users.users.alice;
xauth = "${user.home}/.Xauthority";
in
''
start_all()
testScript =
{ nodes, ... }:
let
user = nodes.machine.users.users.alice;
xauth = "${user.home}/.Xauthority";
in
''
start_all()
machine.wait_for_x()
machine.wait_for_file("${xauth}")
machine.succeed("xauth merge ${xauth}")
machine.sleep(5)
machine.wait_for_x()
machine.wait_for_file("${xauth}")
machine.succeed("xauth merge ${xauth}")
machine.sleep(5)
machine.wait_until_succeeds("pgrep fcitx5")
machine.succeed("su - ${user.name} -c 'kill $(pgrep fcitx5)'")
machine.sleep(1)
machine.wait_until_succeeds("pgrep fcitx5")
machine.succeed("su - ${user.name} -c 'kill $(pgrep fcitx5)'")
machine.sleep(1)
machine.succeed("su - ${user.name} -c 'alacritty >&2 &'")
machine.wait_for_window("alice@machine")
machine.succeed("su - ${user.name} -c 'alacritty >&2 &'")
machine.wait_for_window("alice@machine")
machine.succeed("su - ${user.name} -c 'fcitx5 >&2 &'")
machine.sleep(10)
machine.succeed("su - ${user.name} -c 'fcitx5 >&2 &'")
machine.sleep(10)
### Type on terminal
machine.send_chars("echo ")
machine.sleep(1)
### Type on terminal
machine.send_chars("echo ")
machine.sleep(1)
### Start fcitx Unicode input
machine.send_key("ctrl-alt-shift-u")
machine.sleep(1)
### Start fcitx Unicode input
machine.send_key("ctrl-alt-shift-u")
machine.sleep(1)
### Search for smiling face
machine.send_chars("smil")
machine.sleep(1)
### Search for smiling face
machine.send_chars("smil")
machine.sleep(1)
### Navigate to the second one
machine.send_key("tab")
machine.sleep(1)
### Navigate to the second one
machine.send_key("tab")
machine.sleep(1)
### Choose it
machine.send_key("\n")
machine.sleep(1)
### Choose it
machine.send_key("\n")
machine.sleep(1)
### Start fcitx language input
machine.send_key("ctrl-spc")
machine.sleep(1)
### Start fcitx language input
machine.send_key("ctrl-spc")
machine.sleep(1)
### Default wubi, enter 一下
machine.send_chars("gggh ")
machine.sleep(1)
### Default wubi, enter 一下
machine.send_chars("gggh ")
machine.sleep(1)
### Switch to Hangul
machine.send_key("alt-shift")
machine.sleep(1)
### Switch to Hangul
machine.send_key("alt-shift")
machine.sleep(1)
### Enter 한
machine.send_chars("gks")
machine.sleep(1)
### Enter 한
machine.send_chars("gks")
machine.sleep(1)
### Switch to Harvard Kyoto
machine.send_key("alt-shift")
machine.sleep(1)
### Switch to Harvard Kyoto
machine.send_key("alt-shift")
machine.sleep(1)
### Enter क
machine.send_chars("ka")
machine.sleep(1)
### Enter क
machine.send_chars("ka")
machine.sleep(1)
### Switch to Mozc
machine.send_key("alt-shift")
machine.sleep(1)
### Switch to Mozc
machine.send_key("alt-shift")
machine.sleep(1)
### Enter か
machine.send_chars("ka\n")
machine.sleep(1)
### Enter か
machine.send_chars("ka\n")
machine.sleep(1)
### Turn off Fcitx
machine.send_key("ctrl-spc")
machine.sleep(1)
### Turn off Fcitx
machine.send_key("ctrl-spc")
machine.sleep(1)
### Redirect typed characters to a file
machine.send_chars(" > fcitx_test.out\n")
machine.sleep(1)
machine.screenshot("terminal_chars")
### Redirect typed characters to a file
machine.send_chars(" > fcitx_test.out\n")
machine.sleep(1)
machine.screenshot("terminal_chars")
### Verify that file contents are as expected
file_content = machine.succeed("cat ${user.home}/fcitx_test.out")
assert file_content == "\n", f'output does not match input:\n{file_content}'
'';
}
)
### Verify that file contents are as expected
file_content = machine.succeed("cat ${user.home}/fcitx_test.out")
assert file_content == "\n", f'output does not match input:\n{file_content}'
'';
}
+4 -11
View File
@@ -1,10 +1,6 @@
{
system ? builtins.currentSystem,
pkgs ? import ../.. { inherit system; },
...
}:
{ runTest, pkgs }:
let
lib = pkgs.lib;
inherit (pkgs) lib;
testScript = ''
machine.start()
machine.wait_for_unit("ferretdb.service")
@@ -12,10 +8,8 @@ let
machine.succeed("mongosh --eval 'use myNewDatabase;' --eval 'db.myCollection.insertOne( { x: 1 } );'")
'';
in
with import ../lib/testing-python.nix { inherit system; };
{
postgresql = makeTest {
postgresql = runTest {
inherit testScript;
name = "ferretdb-postgresql";
meta.maintainers = with lib.maintainers; [ julienmalka ];
@@ -47,8 +41,7 @@ with import ../lib/testing-python.nix { inherit system; };
environment.systemPackages = with pkgs; [ mongosh ];
};
};
sqlite = makeTest {
sqlite = runTest {
inherit testScript;
name = "ferretdb-sqlite";
meta.maintainers = with lib.maintainers; [ julienmalka ];
+96 -98
View File
@@ -1,119 +1,117 @@
# Test the firewall module.
import ./make-test-python.nix (
{ pkgs, nftables, ... }:
{
name = "firewall" + pkgs.lib.optionalString nftables "-nftables";
meta = with pkgs.lib.maintainers; {
maintainers = [
rvfg
garyguo
];
};
{ lib, nftables, ... }:
{
name = "firewall" + lib.optionalString nftables "-nftables";
meta = with lib.maintainers; {
maintainers = [
rvfg
garyguo
];
};
nodes = {
walled =
{ ... }:
{
networking.firewall = {
enable = true;
logRefusedPackets = true;
# Syntax smoke test, not actually verified otherwise
allowedTCPPorts = [
25
993
8005
];
nodes = {
walled =
{ ... }:
{
networking.firewall = {
enable = true;
logRefusedPackets = true;
# Syntax smoke test, not actually verified otherwise
allowedTCPPorts = [
25
993
8005
];
allowedTCPPortRanges = [
{
from = 980;
to = 1000;
}
{
from = 990;
to = 1010;
}
{
from = 8000;
to = 8010;
}
];
interfaces.eth0 = {
allowedTCPPorts = [ 10003 ];
allowedTCPPortRanges = [
{
from = 980;
to = 1000;
}
{
from = 990;
to = 1010;
}
{
from = 8000;
to = 8010;
from = 10000;
to = 10005;
}
];
interfaces.eth0 = {
allowedTCPPorts = [ 10003 ];
allowedTCPPortRanges = [
{
from = 10000;
to = 10005;
}
];
};
interfaces.eth3 = {
allowedUDPPorts = [ 10003 ];
allowedUDPPortRanges = [
{
from = 10000;
to = 10005;
}
];
};
};
networking.nftables.enable = nftables;
services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
specialisation.different-config.configuration = {
networking.firewall.rejectPackets = true;
interfaces.eth3 = {
allowedUDPPorts = [ 10003 ];
allowedUDPPortRanges = [
{
from = 10000;
to = 10005;
}
];
};
};
networking.nftables.enable = nftables;
services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
attacker =
{ ... }:
{
services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
networking.firewall.enable = false;
specialisation.different-config.configuration = {
networking.firewall.rejectPackets = true;
};
};
};
testScript =
{ nodes, ... }:
let
unit = if nftables then "nftables" else "firewall";
in
''
start_all()
attacker =
{ ... }:
{
services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
networking.firewall.enable = false;
};
};
walled.wait_for_unit("${unit}")
walled.wait_for_unit("httpd")
attacker.wait_for_unit("network.target")
testScript =
{ nodes, ... }:
let
unit = if nftables then "nftables" else "firewall";
in
''
start_all()
# Local connections should still work.
walled.succeed("curl -v http://localhost/ >&2")
walled.wait_for_unit("${unit}")
walled.wait_for_unit("httpd")
attacker.wait_for_unit("network.target")
# Connections to the firewalled machine should fail, but ping should succeed.
attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
attacker.succeed("ping -c 1 walled >&2")
# Local connections should still work.
walled.succeed("curl -v http://localhost/ >&2")
# Outgoing connections/pings should still work.
walled.succeed("curl -v http://attacker/ >&2")
walled.succeed("ping -c 1 attacker >&2")
# Connections to the firewalled machine should fail, but ping should succeed.
attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
attacker.succeed("ping -c 1 walled >&2")
# Open tcp port 80 at runtime
walled.succeed("nixos-firewall-tool open tcp 80")
attacker.succeed("curl -v http://walled/ >&2")
# Outgoing connections/pings should still work.
walled.succeed("curl -v http://attacker/ >&2")
walled.succeed("ping -c 1 attacker >&2")
# Reset the firewall
walled.succeed("nixos-firewall-tool reset")
attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
# Open tcp port 80 at runtime
walled.succeed("nixos-firewall-tool open tcp 80")
attacker.succeed("curl -v http://walled/ >&2")
# If we stop the firewall, then connections should succeed.
walled.stop_job("${unit}")
attacker.succeed("curl -v http://walled/ >&2")
# Reset the firewall
walled.succeed("nixos-firewall-tool reset")
attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
# Check whether activation of a new configuration reloads the firewall.
walled.succeed(
"/run/booted-system/specialisation/different-config/bin/switch-to-configuration test 2>&1 | grep -qF ${unit}.service"
)
'';
}
)
# If we stop the firewall, then connections should succeed.
walled.stop_job("${unit}")
attacker.succeed("curl -v http://walled/ >&2")
# Check whether activation of a new configuration reloads the firewall.
walled.succeed(
"/run/booted-system/specialisation/different-config/bin/switch-to-configuration test 2>&1 | grep -qF ${unit}.service"
)
'';
}
+46 -56
View File
@@ -1,66 +1,56 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "flannel";
{ lib, ... }:
{
name = "flannel";
meta = with lib.maintainers; {
maintainers = [ offline ];
};
meta.maintainers = with lib.maintainers; [ offline ];
nodes =
let
flannelConfig =
{ pkgs, ... }:
{
services.flannel = {
enable = true;
backend = {
Type = "udp";
Port = 8285;
};
network = "10.1.0.0/16";
iface = "eth1";
etcd.endpoints = [ "http://etcd:2379" ];
};
networking.firewall.allowedUDPPorts = [ 8285 ];
nodes =
let
flannelConfig = {
services.flannel = {
enable = true;
backend = {
Type = "udp";
Port = 8285;
};
in
{
etcd =
{ ... }:
{
services = {
etcd = {
enable = true;
listenClientUrls = [ "http://0.0.0.0:2379" ]; # requires ip-address for binding
listenPeerUrls = [ "http://0.0.0.0:2380" ]; # requires ip-address for binding
advertiseClientUrls = [ "http://etcd:2379" ];
initialAdvertisePeerUrls = [ "http://etcd:2379" ];
initialCluster = [ "etcd=http://etcd:2379" ];
};
};
network = "10.1.0.0/16";
iface = "eth1";
etcd.endpoints = [ "http://etcd:2379" ];
};
networking.firewall.allowedTCPPorts = [ 2379 ];
};
networking.firewall.allowedUDPPorts = [ 8285 ];
};
in
{
etcd = {
services.etcd = {
enable = true;
listenClientUrls = [ "http://0.0.0.0:2379" ]; # requires ip-address for binding
listenPeerUrls = [ "http://0.0.0.0:2380" ]; # requires ip-address for binding
advertiseClientUrls = [ "http://etcd:2379" ];
initialAdvertisePeerUrls = [ "http://etcd:2379" ];
initialCluster = [ "etcd=http://etcd:2379" ];
};
node1 = flannelConfig;
node2 = flannelConfig;
networking.firewall.allowedTCPPorts = [ 2379 ];
};
testScript = ''
start_all()
node1 = flannelConfig;
node2 = flannelConfig;
};
node1.wait_for_unit("flannel.service")
node2.wait_for_unit("flannel.service")
testScript = ''
start_all()
node1.wait_until_succeeds("ip l show dev flannel0")
ip1 = node1.succeed("ip -4 addr show flannel0 | grep -oP '(?<=inet).*(?=/)'")
node2.wait_until_succeeds("ip l show dev flannel0")
ip2 = node2.succeed("ip -4 addr show flannel0 | grep -oP '(?<=inet).*(?=/)'")
node1.wait_for_unit("flannel.service")
node2.wait_for_unit("flannel.service")
node1.wait_until_succeeds(f"ping -c 1 {ip2}")
node2.wait_until_succeeds(f"ping -c 1 {ip1}")
'';
}
)
node1.wait_until_succeeds("ip l show dev flannel0")
ip1 = node1.succeed("ip -4 addr show flannel0 | grep -oP '(?<=inet).*(?=/)'")
node2.wait_until_succeeds("ip l show dev flannel0")
ip2 = node2.succeed("ip -4 addr show flannel0 | grep -oP '(?<=inet).*(?=/)'")
node1.wait_until_succeeds(f"ping -c 1 {ip2}")
node2.wait_until_succeeds(f"ping -c 1 {ip1}")
'';
}
+25 -27
View File
@@ -1,30 +1,28 @@
import ../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "freshrss-caddy-sqlite";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
{ lib, ... }:
{
name = "freshrss-caddy-sqlite";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
passwordFile = pkgs.writeText "password" "secret";
dataDir = "/srv/freshrss";
webserver = "caddy";
virtualHost = "freshrss:80";
};
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
passwordFile = pkgs.writeText "password" "secret";
dataDir = "/srv/freshrss";
webserver = "caddy";
virtualHost = "freshrss:80";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' http://localhost:80/i/")
assert '<title>Login · FreshRSS</title>' in response, "Login page didn't load successfully"
'';
}
)
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' http://localhost:80/i/")
assert '<title>Login · FreshRSS</title>' in response, "Login page didn't load successfully"
'';
}
+7 -7
View File
@@ -1,10 +1,10 @@
{ system, pkgs, ... }:
{ runTest }:
{
extensions = import ./extensions.nix { inherit system pkgs; };
http-auth = import ./http-auth.nix { inherit system pkgs; };
none-auth = import ./none-auth.nix { inherit system pkgs; };
pgsql = import ./pgsql.nix { inherit system pkgs; };
nginx-sqlite = import ./nginx-sqlite.nix { inherit system pkgs; };
caddy-sqlite = import ./caddy-sqlite.nix { inherit system pkgs; };
extensions = runTest ./extensions.nix;
http-auth = runTest ./http-auth.nix;
none-auth = runTest ./none-auth.nix;
pgsql = runTest ./pgsql.nix;
nginx-sqlite = runTest ./nginx-sqlite.nix;
caddy-sqlite = runTest ./caddy-sqlite.nix;
}
+18 -21
View File
@@ -1,24 +1,21 @@
import ../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "freshrss-extensions";
{
name = "freshrss-extensions";
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
authType = "none";
extensions = [ pkgs.freshrss-extensions.youtube ];
};
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
authType = "none";
extensions = [ pkgs.freshrss-extensions.youtube ];
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s http://localhost:80/i/?c=extension")
assert '<span class="ext_name disabled">YouTube Video Feed</span>' in response, "Extension not present in extensions page."
'';
}
)
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s http://localhost:80/i/?c=extension")
assert '<span class="ext_name disabled">YouTube Video Feed</span>' in response, "Extension not present in extensions page."
'';
}
+19 -23
View File
@@ -1,25 +1,21 @@
import ../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "freshrss-http-auth";
meta.maintainers = with lib.maintainers; [ mattchrist ];
{ lib, ... }:
{
name = "freshrss-http-auth";
meta.maintainers = with lib.maintainers; [ mattchrist ];
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
dataDir = "/srv/freshrss";
authType = "http_auth";
};
};
nodes.machine = {
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
dataDir = "/srv/freshrss";
authType = "http_auth";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' -H 'Remote-User: testuser' http://localhost:80/i/")
assert 'Account: testuser' in response, "http_auth method didn't work."
'';
}
)
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' -H 'Remote-User: testuser' http://localhost:80/i/")
assert 'Account: testuser' in response, "http_auth method didn't work."
'';
}
+23 -25
View File
@@ -1,28 +1,26 @@
import ../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "freshrss-nginx-sqlite";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
{ lib, ... }:
{
name = "freshrss-nginx-sqlite";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
passwordFile = pkgs.writeText "password" "secret";
dataDir = "/srv/freshrss";
};
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
passwordFile = pkgs.writeText "password" "secret";
dataDir = "/srv/freshrss";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' http://localhost:80/i/")
assert '<title>Login · FreshRSS</title>' in response, "Login page didn't load successfully"
'';
}
)
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' http://localhost:80/i/")
assert '<title>Login · FreshRSS</title>' in response, "Login page didn't load successfully"
'';
}
+18 -22
View File
@@ -1,24 +1,20 @@
import ../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "freshrss-none-auth";
meta.maintainers = with lib.maintainers; [ mattchrist ];
{ lib, ... }:
{
name = "freshrss-none-auth";
meta.maintainers = with lib.maintainers; [ mattchrist ];
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
authType = "none";
};
};
nodes.machine = {
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
authType = "none";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s http://localhost:80/i/")
assert '<title> · FreshRSS</title>' in response, "FreshRSS stream page didn't load successfully"
'';
}
)
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s http://localhost:80/i/")
assert '<title> · FreshRSS</title>' in response, "FreshRSS stream page didn't load successfully"
'';
}
+48 -50
View File
@@ -1,54 +1,52 @@
import ../make-test-python.nix (
{ lib, pkgs, ... }:
{
name = "freshrss-pgsql";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
{ lib, ... }:
{
name = "freshrss-pgsql";
meta.maintainers = with lib.maintainers; [
etu
stunkymonkey
];
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
passwordFile = pkgs.writeText "password" "secret";
dataDir = "/srv/freshrss";
database = {
type = "pgsql";
port = 5432;
user = "freshrss";
passFile = pkgs.writeText "db-password" "db-secret";
};
};
services.postgresql = {
enable = true;
ensureDatabases = [ "freshrss" ];
ensureUsers = [
{
name = "freshrss";
ensureDBOwnership = true;
}
];
initialScript = pkgs.writeText "postgresql-password" ''
CREATE ROLE freshrss WITH LOGIN PASSWORD 'db-secret' CREATEDB;
'';
};
systemd.services."freshrss-config" = {
requires = [ "postgresql.target" ];
after = [ "postgresql.target" ];
nodes.machine =
{ pkgs, ... }:
{
services.freshrss = {
enable = true;
baseUrl = "http://localhost";
passwordFile = pkgs.writeText "password" "secret";
dataDir = "/srv/freshrss";
database = {
type = "pgsql";
port = 5432;
user = "freshrss";
passFile = pkgs.writeText "db-password" "db-secret";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(5432)
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' http://localhost:80/i/")
assert '<title>Login · FreshRSS</title>' in response, "Login page didn't load successfully"
'';
}
)
services.postgresql = {
enable = true;
ensureDatabases = [ "freshrss" ];
ensureUsers = [
{
name = "freshrss";
ensureDBOwnership = true;
}
];
initialScript = pkgs.writeText "postgresql-password" ''
CREATE ROLE freshrss WITH LOGIN PASSWORD 'db-secret' CREATEDB;
'';
};
systemd.services."freshrss-config" = {
requires = [ "postgresql.target" ];
after = [ "postgresql.target" ];
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(5432)
machine.wait_for_open_port(80)
response = machine.succeed("curl -vvv -s -H 'Host: freshrss' http://localhost:80/i/")
assert '<title>Login · FreshRSS</title>' in response, "Login page didn't load successfully"
'';
}
+12 -19
View File
@@ -1,29 +1,22 @@
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
systemdStage1 ? false,
}:
{ systemdStage1, ... }:
import ./make-test-python.nix {
{
name = "fsck";
nodes.machine =
{ lib, ... }:
{
virtualisation.emptyDiskImages = [ 1 ];
nodes.machine = {
virtualisation.emptyDiskImages = [ 1 ];
virtualisation.fileSystems = {
"/mnt" = {
device = "/dev/vdb";
fsType = "ext4";
autoFormat = true;
};
virtualisation.fileSystems = {
"/mnt" = {
device = "/dev/vdb";
fsType = "ext4";
autoFormat = true;
};
boot.initrd.systemd.enable = systemdStage1;
};
boot.initrd.systemd.enable = systemdStage1;
};
testScript =
{ nodes, ... }:
let
+16 -32
View File
@@ -1,29 +1,15 @@
{
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../.. { inherit system config; },
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
{ runTest, pkgs }:
let
common_meta = {
maintainers = [ maintainers.viraptor ];
};
inherit (pkgs) lib;
in
{
gemstash_works = makeTest {
gemstash_works = runTest {
name = "gemstash-works";
meta = common_meta;
meta.maintainers = with lib.maintainers; [ viraptor ];
nodes.machine =
{ config, pkgs, ... }:
{
services.gemstash = {
enable = true;
};
};
nodes.machine = {
services.gemstash.enable = true;
};
# gemstash responds to http requests
testScript = ''
@@ -34,21 +20,19 @@ in
'';
};
gemstash_custom_port = makeTest {
gemstash_custom_port = runTest {
name = "gemstash-custom-port";
meta = common_meta;
meta.maintainers = with lib.maintainers; [ viraptor ];
nodes.machine =
{ config, pkgs, ... }:
{
services.gemstash = {
enable = true;
openFirewall = true;
settings = {
bind = "tcp://0.0.0.0:12345";
};
nodes.machine = {
services.gemstash = {
enable = true;
openFirewall = true;
settings = {
bind = "tcp://0.0.0.0:12345";
};
};
};
# gemstash responds to http requests
testScript = ''