nixosTests: handleTest -> runTest, batch 2 (#414711)
This commit is contained in:
+60
-39
@@ -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;
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
import ./make-test-python.nix {
|
||||
{
|
||||
name = "blocky";
|
||||
|
||||
nodes = {
|
||||
|
||||
+39
-41
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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')
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||
)
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
import ./make-test-python.nix {
|
||||
{
|
||||
name = "dhparams";
|
||||
|
||||
nodes.machine =
|
||||
|
||||
@@ -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}")
|
||||
'';
|
||||
}
|
||||
|
||||
+588
-590
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import ./make-test-python.nix {
|
||||
{
|
||||
name = "dovecot";
|
||||
|
||||
nodes.machine =
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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}'
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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}")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 = ''
|
||||
|
||||
Reference in New Issue
Block a user