0
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-07-14 06:00:33 +03:00

mattermost: squash systemd-tmpfiles warning (+ other minor fixes)

There was a systemd-tmpfiles warning about not being able to remove the
'plugins' directory. Squash this warning through removal of unnecessary
systemd-tmpfiles options, and write a test for it.

Add the {option}`services.mattermost.pluginsBundle` option to allow
overriding the plugin directory and also using it for tests. Update
wording in option documentation so it is more clear.

Use formats.json instead of builtins.toJSON so module merging works.

Make the tests go faster by pipelining shutdowns of nodes.
This commit is contained in:
Morgan Jones 2025-01-25 16:20:58 -08:00
parent 99bb443ae3
commit ea485e1207
No known key found for this signature in database
GPG key ID: 5C3EB94D198F1491
2 changed files with 171 additions and 105 deletions

View file

@ -147,15 +147,15 @@ let
else
throw "Invalid database driver: ${cfg.database.driver}";
mattermostPluginDerivations =
with pkgs;
map (
mattermostPluginDerivations = map (
plugin:
stdenv.mkDerivation {
name = "mattermost-plugin";
pkgs.stdenvNoCC.mkDerivation {
name = "${cfg.package.name}-plugin";
installPhase = ''
runHook preInstall
mkdir -p $out/share
cp ${plugin} $out/share/plugin.tar.gz
ln -sf ${plugin} $out/share/plugin.tar.gz
runHook postInstall
'';
dontUnpack = true;
dontPatch = true;
@ -166,15 +166,15 @@ let
) cfg.plugins;
mattermostPlugins =
with pkgs;
if mattermostPluginDerivations == [ ] then
null
else
stdenv.mkDerivation {
pkgs.stdenvNoCC.mkDerivation {
name = "${cfg.package.name}-plugins";
nativeBuildInputs = [ autoPatchelfHook ] ++ mattermostPluginDerivations;
nativeBuildInputs = [ pkgs.autoPatchelfHook ] ++ mattermostPluginDerivations;
buildInputs = [ cfg.package ];
installPhase = ''
runHook preInstall
mkdir -p $out
plugins=(${
escapeShellArgs (map (plugin: "${plugin}/share/plugin.tar.gz") mattermostPluginDerivations)
@ -187,6 +187,7 @@ let
GZIP_OPT=-9 tar -C "$hash" -cvzf "$out/$hash.tar.gz" .
rm -rf "$hash"
done
runHook postInstall
'';
dontUnpack = true;
@ -254,8 +255,8 @@ let
}
);
mattermostConfJSON = pkgs.writeText "mattermost-config.json" (builtins.toJSON mattermostConf);
format = pkgs.formats.json { };
finalConfig = format.generate "mattermost-config.json" mattermostConf;
in
{
imports = [
@ -454,9 +455,9 @@ in
the options specified in services.mattermost will be generated
but won't be overwritten on changes or rebuilds.
If this option is disabled, changes in the system console won't
be possible (default). If an config.json is present, it will be
overwritten!
If this option is disabled, persistent changes in the system
console won't be possible (the default). If a config.json is
present, it will be overwritten at service start!
'';
};
@ -480,7 +481,20 @@ in
description = ''
Plugins to add to the configuration. Overrides any installed if non-null.
This is a list of paths to .tar.gz files or derivations evaluating to
.tar.gz files.
.tar.gz files. You can use `mattermost.buildPlugin` to build plugins;
see the NixOS documentation for more details.
'';
};
pluginsBundle = mkOption {
type = with types; nullOr package;
default = mattermostPlugins;
defaultText = ''
All entries in {config}`services.mattermost.plugins`, repacked
'';
description = ''
Derivation building to a directory of plugin tarballs.
This overrides {option}`services.mattermost.plugins` if provided.
'';
};
@ -508,7 +522,8 @@ in
type = with types; attrsOf (either int str);
default = { };
description = ''
Extra environment variables to export to the Mattermost process, in the systemd unit.
Extra environment variables to export to the Mattermost process
from the systemd unit configuration.
'';
example = {
MM_SERVICESETTINGS_SITEURL = "http://example.com";
@ -524,11 +539,11 @@ in
for mattermost (see [the Mattermost documentation](https://docs.mattermost.com/configure/configuration-settings.html#environment-variables)).
Settings defined in the environment file will overwrite settings
set via nix or via the {option}`services.mattermost.extraConfig`
set via Nix or via the {option}`services.mattermost.extraConfig`
option.
Useful for setting config options without their value ending up in the
(world-readable) nix store, e.g. for a database password.
(world-readable) Nix store, e.g. for a database password.
'';
};
@ -687,7 +702,7 @@ in
};
settings = mkOption {
type = types.attrs;
inherit (format) type;
default = { };
description = ''
Additional configuration options as Nix attribute set in config.json schema.
@ -786,7 +801,7 @@ in
"d= ${tempDir} 0750 ${cfg.user} ${cfg.group} - -"
# Ensure that pluginDir is a directory, as it could be a symlink on prior versions.
"r- ${pluginDir} - - - - -"
# Don't remove or clean it out since it should be persistent, as this is where plugins are unpacked.
"d= ${pluginDir} 0750 ${cfg.user} ${cfg.group} - -"
# Ensure that the plugin directories exist.
@ -801,15 +816,14 @@ in
"L+ ${cfg.dataDir}/client - - - - ${cfg.package}/client"
]
++ (
if mattermostPlugins == null then
# Create the plugin tarball directory if it's a symlink.
if cfg.pluginsBundle == null then
# Create the plugin tarball directory to allow plugin uploads.
[
"r- ${cfg.dataDir}/plugins - - - - -"
"d= ${cfg.dataDir}/plugins 0750 ${cfg.user} ${cfg.group} - -"
]
else
# Symlink the plugin tarball directory, removing anything existing.
[ "L+ ${cfg.dataDir}/plugins - - - - ${mattermostPlugins}" ]
# Symlink the plugin tarball directory, removing anything existing, since it's managed by Nix.
[ "L+ ${cfg.dataDir}/plugins - - - - ${cfg.pluginsBundle}" ]
);
systemd.services.mattermost = rec {
@ -836,7 +850,7 @@ in
configDir=${escapeShellArg cfg.configDir}
logDir=${escapeShellArg cfg.logDir}
package=${escapeShellArg cfg.package}
nixConfig=${escapeShellArg mattermostConfJSON}
nixConfig=${escapeShellArg finalConfig}
''
+ optionalString (versionAtLeast config.system.stateVersion "25.05") ''
# Migrate configs in the pre-25.05 directory structure.

View file

@ -33,7 +33,7 @@ import ../make-test-python.nix (
);
};
system.stateVersion = lib.mkDefault "25.05";
system.stateVersion = lib.mkDefault (lib.versions.majorMinor lib.version);
services.mattermost = lib.recursiveUpdate {
enable = true;
@ -63,7 +63,7 @@ import ../make-test-python.nix (
# Upgrade to the latest Mattermost.
specialisation.latest.configuration = {
services.mattermost.package = lib.mkForce pkgs.mattermostLatest;
system.stateVersion = lib.mkVMOverride "25.05";
system.stateVersion = lib.mkVMOverride (lib.versions.majorMinor lib.version);
};
}
)
@ -90,22 +90,16 @@ import ../make-test-python.nix (
name = "mattermost";
nodes = rec {
postgresMutable =
makeMattermost
{
postgresMutable = makeMattermost {
mutableConfig = true;
preferNixConfig = false;
settings.SupportSettings.HelpLink = "https://search.nixos.org";
}
} { };
postgresMostlyMutable =
makeMattermost
{
# Last version to support the "old" config layout.
system.stateVersion = lib.mkForce "24.11";
# First version to support the "new" config layout.
specialisation.upgrade.configuration.system.stateVersion = lib.mkVMOverride "25.05";
};
postgresMostlyMutable = makeMattermost {
mutableConfig = true;
preferNixConfig = true;
plugins = with pkgs; [
# Build the demo plugin.
(mattermost.buildPlugin {
@ -140,7 +134,16 @@ import ../make-test-python.nix (
};
})
];
} { };
}
{
# Last version to support the "old" config layout.
system.stateVersion = lib.mkForce "24.11";
# Supports the "new" config layout.
specialisation.upgrade.configuration.system.stateVersion = lib.mkVMOverride (
lib.versions.majorMinor lib.version
);
};
postgresImmutable = makeMattermost {
package = pkgs.mattermost.overrideAttrs (prev: {
webapp = prev.webapp.overrideAttrs (prevWebapp: {
@ -343,9 +346,14 @@ import ../make-test-python.nix (
'';
in
''
import sys
import shlex
import threading
import queue
def wait_mattermost_up(node, site_name="${siteName}"):
print(f"wait_mattermost_up({node.name!r}, site_name={site_name!r})", file=sys.stderr)
node.wait_for_unit("multi-user.target")
node.systemctl("start mattermost.service")
node.wait_for_unit("mattermost.service")
node.wait_for_open_port(8065)
@ -353,20 +361,25 @@ import ../make-test-python.nix (
node.succeed(f"curl {shlex.quote('${url}')}/index.html | grep {shlex.quote(site_name)}")
def restart_mattermost(node, site_name="${siteName}"):
print(f"restart_mattermost({node.name!r}, site_name={site_name!r})", file=sys.stderr)
node.systemctl("restart mattermost.service")
wait_mattermost_up(node, site_name)
def expect_config(node, mattermost_version, *configs):
print(f"expect_config({node.name!r}, {mattermost_version!r}, *{configs!r})", file=sys.stderr)
for config in configs:
node.succeed(f"${expectConfig} {shlex.quote(config)} {shlex.quote(mattermost_version)}")
def expect_plugins(node, jq_or_code):
print(f"expect_plugins({node.name!r}, {jq_or_code!r})", file=sys.stderr)
node.succeed(f"${expectPlugins} {shlex.quote(str(jq_or_code))}")
def ensure_post(node, fail_if_not_found=False):
print(f"ensure_post({node.name!r}, fail_if_not_found={fail_if_not_found!r})", file=sys.stderr)
node.succeed(f"${ensurePost} {shlex.quote('${url}')} {1 if fail_if_not_found else 0}")
def set_config(node, *configs, nixos_version='25.05'):
def set_config(node, *configs, nixos_version='${lib.versions.majorMinor lib.version}'):
print(f"set_config({node.name!r}, *{configs!r}, nixos_version={nixos_version!r})", file=sys.stderr)
for config in configs:
args = [shlex.quote("${setConfig}")]
args.append(shlex.quote(config))
@ -374,8 +387,13 @@ import ../make-test-python.nix (
args.append(shlex.quote(str(nixos_version)))
node.succeed(' '.join(args))
def run_mattermost_tests(mutableToplevel: str, mutable,
mostlyMutableToplevel: str, mostlyMutable,
def switch_to_specialisation(node, toplevel: str, specialisation: str):
print(f"switch_to_specialisation({node.name!r}, {toplevel!r}, {specialisation!r})", file=sys.stderr)
node.succeed(f"{toplevel}/specialisation/{specialisation}/bin/switch-to-configuration switch || true")
def run_mattermost_tests(shutdown_queue: queue.Queue,
mutableToplevel: str, mutable,
mostlyMutableToplevel: str, mostlyMutablePlugins: str, mostlyMutable,
immutableToplevel: str, immutable,
environmentFileToplevel: str, environmentFile):
esr, latest = '${pkgs.mattermost.version}', '${pkgs.mattermostLatest.version}'
@ -391,8 +409,7 @@ import ../make-test-python.nix (
set_config(
mutable,
'.SupportSettings.AboutLink = "https://mattermost.com"',
'.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"',
nixos_version='24.11' # Default 'mutable' config is an old version
'.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"'
)
ensure_post(mutable)
restart_mattermost(mutable)
@ -401,23 +418,14 @@ import ../make-test-python.nix (
expect_config(mutable, esr, '.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"')
ensure_post(mutable, fail_if_not_found=True)
# Switch to the newer config
mutable.succeed(f"{mutableToplevel}/specialisation/upgrade/bin/switch-to-configuration switch")
wait_mattermost_up(mutable)
# AboutLink and HelpLink should be changed, still, and the post should still exist
expect_config(mutable, esr, '.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"')
ensure_post(mutable, fail_if_not_found=True)
# Switch to the latest Mattermost version
mutable.succeed(f"{mutableToplevel}/specialisation/latest/bin/switch-to-configuration switch")
switch_to_specialisation(mutable, mutableToplevel, "latest")
wait_mattermost_up(mutable)
# AboutLink and HelpLink should be changed, still, and the post should still exist
expect_config(mutable, latest, '.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"')
ensure_post(mutable, fail_if_not_found=True)
mutable.shutdown()
shutdown_queue.put(mutable)
## Mostly mutable node tests ##
mostlyMutable.start()
@ -434,13 +442,40 @@ import ../make-test-python.nix (
mostlyMutable,
'.SupportSettings.AboutLink = "https://mattermost.com"',
'.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"',
nixos_version='24.11' # Default 'mostlyMutable' config is an old version
)
ensure_post(mostlyMutable)
restart_mattermost(mostlyMutable)
# HelpLink should be changed but AboutLink should not, and the post should exist
expect_config(mostlyMutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"')
ensure_post(mostlyMutable, fail_if_not_found=True)
# Switch to the newer config and make sure the plugins directory is replaced with a directory,
# since it could have been a symlink on previous versions.
mostlyMutable.systemctl("stop mattermost.service")
mostlyMutable.succeed(f"[ ! -L /var/lib/mattermost/data/plugins ] && rm -rf /var/lib/mattermost/data/plugins && ln -s {mostlyMutablePlugins} /var/lib/mattermost/data/plugins || true")
mostlyMutable.succeed('[ -L /var/lib/mattermost/data/plugins ] && [ -d /var/lib/mattermost/data/plugins ]')
switch_to_specialisation(mostlyMutable, mostlyMutableToplevel, "upgrade")
wait_mattermost_up(mostlyMutable)
mostlyMutable.succeed('[ ! -L /var/lib/mattermost/data/plugins ] && [ -d /var/lib/mattermost/data/plugins ]')
# HelpLink should be changed, still, and the post should still exist
expect_config(mostlyMutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"')
ensure_post(mostlyMutable, fail_if_not_found=True)
# Edit the config and make a post
set_config(
mostlyMutable,
'.SupportSettings.AboutLink = "https://mattermost.com/foo"',
'.SupportSettings.HelpLink = "https://nixos.org/nixos/manual/bar"',
'.PluginSettings.PluginStates."com.mattermost.plugin-todo".Enable = true'
)
ensure_post(mostlyMutable)
restart_mattermost(mostlyMutable)
# AboutLink should be overridden by NixOS configuration; HelpLink should be what we set above
expect_config(mostlyMutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"')
expect_config(mostlyMutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual/bar"')
# Single plugin that's now enabled.
expect_plugins(mostlyMutable, 'length == 1')
@ -449,14 +484,14 @@ import ../make-test-python.nix (
ensure_post(mostlyMutable, fail_if_not_found=True)
# Switch to the latest Mattermost version
mostlyMutable.succeed(f"{mostlyMutableToplevel}/specialisation/latest/bin/switch-to-configuration switch")
switch_to_specialisation(mostlyMutable, mostlyMutableToplevel, "latest")
wait_mattermost_up(mostlyMutable)
# AboutLink should be overridden and the post should still exist
expect_config(mostlyMutable, latest, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"')
expect_config(mostlyMutable, latest, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual/bar"')
ensure_post(mostlyMutable, fail_if_not_found=True)
mostlyMutable.shutdown()
shutdown_queue.put(mostlyMutable)
## Immutable node tests ##
immutable.start()
@ -484,14 +519,14 @@ import ../make-test-python.nix (
ensure_post(immutable, fail_if_not_found=True)
# Switch to the latest Mattermost version
immutable.succeed(f"{immutableToplevel}/specialisation/latest/bin/switch-to-configuration switch")
switch_to_specialisation(immutable, immutableToplevel, "latest")
wait_mattermost_up(immutable)
# AboutLink and HelpLink should be changed, still, and the post should still exist
expect_config(immutable, latest, '.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"')
ensure_post(immutable, fail_if_not_found=True)
immutable.shutdown()
shutdown_queue.put(immutable)
## Environment File node tests ##
environmentFile.start()
@ -503,19 +538,31 @@ import ../make-test-python.nix (
ensure_post(environmentFile, fail_if_not_found=True)
# Switch to the latest Mattermost version
environmentFile.succeed(f"{environmentFileToplevel}/specialisation/latest/bin/switch-to-configuration switch")
switch_to_specialisation(environmentFile, environmentFileToplevel, "latest")
wait_mattermost_up(environmentFile)
# AboutLink should be changed still, and the post should still exist
expect_config(environmentFile, latest, '.AboutLink == "https://nixos.org"')
ensure_post(environmentFile, fail_if_not_found=True)
environmentFile.shutdown()
shutdown_queue.put(environmentFile)
# Run shutdowns asynchronously so we can pipeline them.
shutdown_queue: queue.Queue = queue.Queue()
def shutdown_worker():
while True:
node = shutdown_queue.get()
print(f"Shutting down node {node.name!r} asynchronously", file=sys.stderr)
node.shutdown()
shutdown_queue.task_done()
threading.Thread(target=shutdown_worker, daemon=True).start()
run_mattermost_tests(
shutdown_queue,
"${nodes.mysqlMutable.system.build.toplevel}",
mysqlMutable,
"${nodes.mysqlMostlyMutable.system.build.toplevel}",
"${nodes.mysqlMostlyMutable.services.mattermost.pluginsBundle}",
mysqlMostlyMutable,
"${nodes.mysqlImmutable.system.build.toplevel}",
mysqlImmutable,
@ -524,15 +571,20 @@ import ../make-test-python.nix (
)
run_mattermost_tests(
shutdown_queue,
"${nodes.postgresMutable.system.build.toplevel}",
postgresMutable,
"${nodes.postgresMostlyMutable.system.build.toplevel}",
"${nodes.postgresMostlyMutable.services.mattermost.pluginsBundle}",
postgresMostlyMutable,
"${nodes.postgresImmutable.system.build.toplevel}",
postgresImmutable,
"${nodes.postgresEnvironmentFile.system.build.toplevel}",
postgresEnvironmentFile
)
# Drain the queue
shutdown_queue.join()
'';
}
)