mumble: migrate to inventory

This commit is contained in:
Jörg Thalheim
2025-04-16 18:01:32 +02:00
parent 51b184e8be
commit bcd2b1ae1f
5 changed files with 222 additions and 251 deletions

View File

@@ -1,143 +1,102 @@
(import ../lib/test-base.nix) ( {
{ ... }: pkgs,
let self,
common = clanLib,
{ self, pkgs, ... }: ...
{ }:
imports = [ clanLib.test.makeTestClan {
self.clanModules.mumble inherit pkgs self;
{ nixosTest = (
clan.services.mumble.user = "alice"; { lib, ... }:
} let
self.nixosModules.clanCore common =
(self.inputs.nixpkgs + "/nixos/tests/common/x11.nix") { pkgs, modulesPath, ... }:
{ {
clan.core.settings.directory = ./.; imports = [
environment.systemPackages = [ pkgs.killall ]; (modulesPath + "/../tests/common/x11.nix")
clan.core.facts.services.mumble.secret."mumble-key".path = "/etc/mumble-key"; ];
clan.core.facts.services.mumble.public."mumble-cert".path = "/etc/mumble-cert";
}
];
clan.services.mumble.user = "alice";
environment.systemPackages = [ pkgs.killall ];
};
machines = [
"peer1"
"peer2"
];
in
{
name = "mumble";
clan = {
directory = ./.;
inventory = {
machines = lib.genAttrs machines (_: { });
services = {
mumble.default = {
roles.server.machines = machines;
};
};
};
}; };
in
{
name = "mumble";
enableOCR = true; enableOCR = true;
nodes.peer1 = nodes.peer1 = common;
{ ... }: nodes.peer2 = common;
{
imports = [
common
{
environment.etc = {
"mumble-key".source = ./peer_1/peer_1_test_key;
"mumble-cert".source = ./peer_1/peer_1_test_cert;
};
systemd.tmpfiles.settings."vmsecrets" = {
"/var/lib/murmur/sslKey" = {
C.argument = "${./peer_1/peer_1_test_key}";
z = {
mode = "0400";
user = "murmur";
};
};
"/var/lib/murmur/sslCert" = {
C.argument = "${./peer_1/peer_1_test_cert}";
z = {
mode = "0400";
user = "murmur";
};
};
};
clan.core.facts.services.mumble.secret."mumble-key".path = "/etc/mumble-key";
clan.core.facts.services.mumble.public."mumble-cert".path = "/etc/mumble-cert";
}
];
};
nodes.peer2 =
{ ... }:
{
imports = [
common
{
environment.etc = {
"mumble-key".source = ./peer_2/peer_2_test_key;
"mumble-cert".source = ./peer_2/peer_2_test_cert;
};
systemd.tmpfiles.settings."vmsecrets" = {
"/var/lib/murmur/sslKey" = {
C.argument = "${./peer_2/peer_2_test_key}";
z = {
mode = "0400";
user = "murmur";
};
};
"/var/lib/murmur/sslCert" = {
C.argument = "${./peer_2/peer_2_test_cert}";
z = {
mode = "0400";
user = "murmur";
};
};
};
}
];
};
testScript = ''
start_all()
with subtest("Waiting for x"): testScript = ''
peer1.wait_for_x() start_all()
peer2.wait_for_x()
with subtest("Waiting for murmur"): with subtest("Waiting for x"):
peer1.wait_for_unit("murmur.service") peer1.wait_for_x()
peer2.wait_for_unit("murmur.service") peer2.wait_for_x()
with subtest("Starting Mumble"): with subtest("Waiting for murmur"):
# starting mumble is blocking peer1.wait_for_unit("murmur.service")
peer1.execute("mumble >&2 &") peer2.wait_for_unit("murmur.service")
peer2.execute("mumble >&2 &")
with subtest("Wait for Mumble"): with subtest("Starting Mumble"):
peer1.wait_for_window(r"^Mumble$") # starting mumble is blocking
peer2.wait_for_window(r"^Mumble$") peer1.execute("mumble >&2 &")
peer2.execute("mumble >&2 &")
with subtest("Wait for certificate creation"): with subtest("Wait for Mumble"):
peer1.wait_for_window(r"^Mumble$") peer1.wait_for_window(r"^Mumble$")
peer1.sleep(3) # mumble is slow to register handlers peer2.wait_for_window(r"^Mumble$")
peer1.send_chars("\n")
peer1.send_chars("\n")
peer2.wait_for_window(r"^Mumble$")
peer2.sleep(3) # mumble is slow to register handlers
peer2.send_chars("\n")
peer2.send_chars("\n")
with subtest("Wait for server connect"): with subtest("Wait for certificate creation"):
peer1.wait_for_window(r"^Mumble Server Connect$") peer1.wait_for_window(r"^Mumble$")
peer2.wait_for_window(r"^Mumble Server Connect$") peer1.sleep(3) # mumble is slow to register handlers
peer1.send_chars("\n")
peer1.send_chars("\n")
peer2.wait_for_window(r"^Mumble$")
peer2.sleep(3) # mumble is slow to register handlers
peer2.send_chars("\n")
peer2.send_chars("\n")
with subtest("Check validity of server certificates"): with subtest("Wait for server connect"):
peer1.execute("killall .mumble-wrapped") peer1.wait_for_window(r"^Mumble Server Connect$")
peer1.sleep(1) peer2.wait_for_window(r"^Mumble Server Connect$")
peer1.execute("mumble mumble://peer2 >&2 &")
peer1.wait_for_window(r"^Mumble$")
peer1.sleep(3) # mumble is slow to register handlers
peer1.send_chars("\n")
peer1.send_chars("\n")
peer1.wait_for_text("Connected.")
peer2.execute("killall .mumble-wrapped") with subtest("Check validity of server certificates"):
peer2.sleep(1) peer1.execute("killall .mumble-wrapped")
peer2.execute("mumble mumble://peer1 >&2 &") peer1.sleep(1)
peer2.wait_for_window(r"^Mumble$") peer1.execute("mumble mumble://peer2 >&2 &")
peer2.sleep(3) # mumble is slow to register handlers peer1.wait_for_window(r"^Mumble$")
peer2.send_chars("\n") peer1.sleep(3) # mumble is slow to register handlers
peer2.send_chars("\n") peer1.send_chars("\n")
peer2.wait_for_text("Connected.") peer1.send_chars("\n")
''; peer1.wait_for_text("Connected.")
}
) peer2.execute("killall .mumble-wrapped")
peer2.sleep(1)
peer2.execute("mumble mumble://peer1 >&2 &")
peer2.wait_for_window(r"^Mumble$")
peer2.sleep(3) # mumble is slow to register handlers
peer2.send_chars("\n")
peer2.send_chars("\n")
peer2.wait_for_text("Connected.")
'';
}
);
}

View File

@@ -1,7 +1,12 @@
--- ---
description = "Open Source, Low Latency, High Quality Voice Chat." description = "Open Source, Low Latency, High Quality Voice Chat."
categories = ["Audio", "Social"] categories = ["Audio", "Social"]
features = [ "inventory" ]
[constraints]
roles.server.min = 1
--- ---
The mumble clan module gives you: The mumble clan module gives you:
- True low latency voice communication. - True low latency voice communication.

View File

@@ -1,122 +1,6 @@
# Dont import this file
# It is only here for backwards compatibility.
# Dont author new modules with this file.
{ {
lib, imports = [ ./roles/server.nix ];
config,
pkgs,
...
}:
let
dir = config.clan.core.settings.directory;
machineDir = dir + "/vars/per-machine";
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
machineJson = builtins.toJSON machines;
certificateMachinePath = machines: machineDir + "/${machines}" + "/mumble/mumble-cert/value";
certificatesUnchecked = builtins.map (
machine:
let
fullPath = certificateMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) machines;
certificate = lib.filter (machine: machine != null) certificatesUnchecked;
machineCert = builtins.map (
machine: (lib.nameValuePair machine (builtins.readFile (certificateMachinePath machine)))
) certificate;
machineCertJson = builtins.toJSON machineCert;
in
{
options.clan.services.mumble = {
user = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "alice";
description = "The user mumble should be set up for.";
};
};
config = {
services.murmur = {
enable = true;
logDays = -1;
registerName = config.clan.core.settings.machine.name;
openFirewall = true;
bonjour = true;
sslKey = "/var/lib/murmur/sslKey";
sslCert = "/var/lib/murmur/sslCert";
};
clan.core.state.mumble.folders = [
"/var/lib/mumble"
"/var/lib/murmur"
];
systemd.tmpfiles.rules = [
"d '/var/lib/mumble' 0770 '${config.clan.services.mumble.user}' 'users' - -"
];
systemd.tmpfiles.settings."murmur" = {
"/var/lib/murmur/sslKey" = {
C.argument = config.clan.core.vars.generators.mumble.files.mumble-key.path;
Z = {
mode = "0400";
user = "murmur";
};
};
"/var/lib/murmur/sslCert" = {
C.argument = config.clan.core.vars.generators.mumble.files.mumble-cert.path;
Z = {
mode = "0400";
user = "murmur";
};
};
};
environment.systemPackages =
let
mumbleCfgDir = "/var/lib/mumble";
mumbleDatabasePath = "${mumbleCfgDir}/mumble.sqlite";
mumbleCfgPath = "/var/lib/mumble/mumble_settings.json";
populate-channels = pkgs.writers.writePython3 "mumble-populate-channels" {
libraries = [
pkgs.python3Packages.cryptography
pkgs.python3Packages.pyopenssl
];
flakeIgnore = [
# We don't live in the dark ages anymore.
# Languages like Python that are whitespace heavy will overrun
# 79 characters..
"E501"
];
} (builtins.readFile ./mumble-populate-channels.py);
mumble = pkgs.writeShellScriptBin "mumble" ''
set -xeu
mkdir -p ${mumbleCfgDir}
pushd "${mumbleCfgDir}"
XDG_DATA_HOME=${mumbleCfgDir}
XDG_DATA_DIR=${mumbleCfgDir}
${populate-channels} --ensure-config '${mumbleCfgPath}' --db-location ${mumbleDatabasePath}
${populate-channels} --machines '${machineJson}' --username ${config.clan.core.settings.machine.name} --db-location ${mumbleDatabasePath}
${populate-channels} --servers '${machineCertJson}' --username ${config.clan.core.settings.machine.name} --db-location ${mumbleDatabasePath} --cert True
${pkgs.mumble}/bin/mumble --config ${mumbleCfgPath} "$@"
popd
'';
in
[ mumble ];
clan.core.vars.generators.mumble = {
migrateFact = "mumble";
files.mumble-key = { };
files.mumble-cert.secret = false;
runtimeInputs = [
pkgs.coreutils
pkgs.openssl
];
script = ''
openssl genrsa -out "$out/mumble-key" 2048
openssl req -new -x509 -key "$out/mumble-key" -out "$out/mumble-cert"
'';
};
};
} }

View File

@@ -0,0 +1,123 @@
{
lib,
config,
pkgs,
...
}:
let
dir = config.clan.core.settings.directory;
# TODO: this should actually use the inventory to figure out which machines to use.
machineDir = dir + "/vars/per-machine";
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
machineJson = builtins.toJSON machines;
certificateMachinePath = machines: machineDir + "/${machines}" + "/mumble/mumble-cert/value";
certificatesUnchecked = builtins.map (
machine:
let
fullPath = certificateMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) machines;
certificate = lib.filter (machine: machine != null) certificatesUnchecked;
machineCert = builtins.map (
machine: (lib.nameValuePair machine (builtins.readFile (certificateMachinePath machine)))
) certificate;
machineCertJson = builtins.toJSON machineCert;
in
{
options.clan.services.mumble = {
user = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "alice";
description = "The user mumble should be set up for.";
};
};
config = {
services.murmur = {
enable = true;
logDays = -1;
registerName = config.clan.core.settings.machine.name;
openFirewall = true;
bonjour = true;
sslKey = "/var/lib/murmur/sslKey";
sslCert = "/var/lib/murmur/sslCert";
};
clan.core.state.mumble.folders = [
"/var/lib/mumble"
"/var/lib/murmur"
];
systemd.tmpfiles.rules = [
"d '/var/lib/mumble' 0770 '${config.clan.services.mumble.user}' 'users' - -"
];
systemd.tmpfiles.settings."murmur" = {
"/var/lib/murmur/sslKey" = {
C.argument = config.clan.core.vars.generators.mumble.files.mumble-key.path;
Z = {
mode = "0400";
user = "murmur";
};
};
"/var/lib/murmur/sslCert" = {
C.argument = config.clan.core.vars.generators.mumble.files.mumble-cert.path;
Z = {
mode = "0400";
user = "murmur";
};
};
};
environment.systemPackages =
let
mumbleCfgDir = "/var/lib/mumble";
mumbleDatabasePath = "${mumbleCfgDir}/mumble.sqlite";
mumbleCfgPath = "/var/lib/mumble/mumble_settings.json";
populate-channels = pkgs.writers.writePython3 "mumble-populate-channels" {
libraries = [
pkgs.python3Packages.cryptography
pkgs.python3Packages.pyopenssl
];
flakeIgnore = [
# We don't live in the dark ages anymore.
# Languages like Python that are whitespace heavy will overrun
# 79 characters..
"E501"
];
} (builtins.readFile ./mumble-populate-channels.py);
mumble = pkgs.writeShellScriptBin "mumble" ''
set -xeu
mkdir -p ${mumbleCfgDir}
pushd "${mumbleCfgDir}"
XDG_DATA_HOME=${mumbleCfgDir}
XDG_DATA_DIR=${mumbleCfgDir}
${populate-channels} --ensure-config '${mumbleCfgPath}' --db-location ${mumbleDatabasePath}
${populate-channels} --machines '${machineJson}' --username ${config.clan.core.settings.machine.name} --db-location ${mumbleDatabasePath}
${populate-channels} --servers '${machineCertJson}' --username ${config.clan.core.settings.machine.name} --db-location ${mumbleDatabasePath} --cert True
${pkgs.mumble}/bin/mumble --config ${mumbleCfgPath} "$@"
popd
'';
in
[ mumble ];
clan.core.vars.generators.mumble = {
migrateFact = "mumble";
files.mumble-key = { };
files.mumble-cert.secret = false;
runtimeInputs = [
pkgs.coreutils
pkgs.openssl
];
script = ''
openssl genrsa -out "$out/mumble-key" 2048
openssl req -new -x509 -key "$out/mumble-key" -out "$out/mumble-cert"
'';
};
};
}