From 9b4b8dae63903a551c866adfabebe2bbb0974772 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Sun, 13 Jul 2025 01:37:11 -0400 Subject: [PATCH] nixos/tests/openafs: Add OpenAFS client and server test This configures two nodes as an OpenAFS cell and OpenAFS clients and then tests to make sure that files can be written and read. --- nixos/tests/all-tests.nix | 1 + nixos/tests/openafs.nix | 139 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 nixos/tests/openafs.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 59e67971f083..c1f95c651af9 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1155,6 +1155,7 @@ in onlyoffice = runTest ./onlyoffice.nix; open-web-calendar = runTest ./web-apps/open-web-calendar.nix; open-webui = runTest ./open-webui.nix; + openafs = runTest ./openafs.nix; openarena = runTest ./openarena.nix; openbao = runTest ./openbao.nix; opencloud = runTest ./opencloud.nix; diff --git a/nixos/tests/openafs.nix b/nixos/tests/openafs.nix new file mode 100644 index 000000000000..cfd072fbb23b --- /dev/null +++ b/nixos/tests/openafs.nix @@ -0,0 +1,139 @@ +{ lib, ... }: +let + cellName = "cell.com"; + realmName = lib.toUpper cellName; +in +{ + name = "openafs"; + defaults = + { config, nodes, ... }: + let + cellServDB = { + ${cellName} = lib.mapAttrsToList (_: config: { + ip = config.networking.primaryIPAddress; + dnsname = "${config.networking.hostName}.${config.networking.domain}"; + }) nodes; + }; + in + { + config = { + virtualisation.vlans = [ 1 ]; + networking.useDHCP = false; # Disable external connectivity + networking.domain = cellName; + networking.firewall.enable = false; + + security.krb5 = { + enable = true; + settings.libdefaults.default_realm = realmName; + }; + services.openafsClient = { + enable = true; + inherit cellName; + cellServDB = cellServDB // { + "grand.central.org" = [ + { + ip = "1.1.1.1"; + dnsname = "one.grand.central.org"; + } + ]; + }; + }; + services.openafsServer = { + enable = true; + inherit cellName cellServDB; + }; + security.krb5.settings.realms.${realmName} = { + admin_server = nodes.a.networking.primaryIPAddress; + kdc = [ nodes.a.networking.primaryIPAddress ]; + }; + }; + }; + nodes.a = { + services.kerberos_server = { + enable = true; + settings.realms."CELL.COM".acl = [ + { + principal = "admin"; + access = [ + "add" + "cpw" + ]; + } + ]; + }; + }; + nodes.b = { }; + + testScript = '' + import re + + def setup_kdc(machine): + # Set up realm + machine.succeed( + "kdb5_util create -s -r CELL.COM -P master_key", + "systemctl restart kadmind.service kdc.service", + ) + for unit in ["kadmind", "kdc"]: + machine.wait_for_unit(f"{unit}.service") + # Create admin and afs/ principals + machine.succeed( + "kadmin.local add_principal -randkey admin", + "rm -f /tmp/shared/admin.keytab", + "kadmin.local ktadd -k /tmp/shared/admin.keytab admin", + "kadmin.local add_principal -randkey -e aes256-cts-hmac-sha1-96:normal,aes128-cts-hmac-sha1-96:normal afs/${cellName}", + ) + # Generate a keytab for afs/ + out = machine.succeed( + "rm -f /tmp/shared/rxkad.keytab", + "kadmin.local ktadd -k /tmp/shared/rxkad.keytab -e aes256-cts-hmac-sha1-96:normal,aes128-cts-hmac-sha1-96:normal afs/${cellName}", + ) + m = re.search(r"kvno (\d+)", out) + assert m + kvno = m.group(1) + return kvno + + def setup_afs_daemons(machine, kvno): + machine.succeed( + "mkdir -p /vicepa", + "touch /vicepa/AlwaysAttach", + ) + machine.succeed(*( + f"asetkey add rxkad_krb5 {kvno} {enctype} /tmp/shared/rxkad.keytab afs/${cellName}" + for enctype in (18, 17) + )) + machine.start_job("openafs-server") + machine.wait_until_succeeds("bos adduser localhost admin -localauth") + + start_all() + kvno = setup_kdc(a) + setup_afs_daemons(a, kvno) + setup_afs_daemons(b, kvno) + # Create initial 'admin' user + # N.B. It can take 60+ seconds before the ptserver has quorum and accepts writes, so try a few times until it succeeds + a.wait_until_succeeds("pts createuser -name admin -localauth") + a.succeed( + "pts adduser admin system:administrators -localauth", + ) + # Create initial volumes + a.wait_until_succeeds("vos listvol localhost -localauth") + a.succeed( + "vos create localhost vicepa root.afs -localauth", + "vos create localhost vicepa root.cell -localauth", + ) + # Authenticate and add a file + a.succeed( + "kinit -k -t /tmp/shared/admin.keytab admin", + "aklog", + "echo pass > /afs/${cellName}/test.txt", + ) + # Authenticate and read a file + b.succeed( + "kinit -k -t /tmp/shared/admin.keytab admin", + "aklog", + ) + assert b.succeed("cat /afs/${cellName}/test.txt").strip() == "pass" + + # Ensure the global CellServDB can be overridden. + assert a.succeed("fs listcells -n | grep grand.central.org").strip() == "Cell grand.central.org on hosts 1.1.1.1." + ''; +}