Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/zammad: refactor package, module and nixos-test #277456

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@

- `knot-dns` has been updated to version 3.4.x. Check the [migration guide](https://www.knot-dns.cz/docs/latest/html/migration.html#upgrade-3-3-x-to-3-4-x) for breaking changes.

- `zammad` has had its support for MySQL removed, since it was never working correctly and is now deprecated upstream. Check the [migration guide](https://docs.zammad.org/en/latest/appendix/migrate-to-postgresql.html) for how to convert your database to PostgreSQL.

- `services.kubernetes.kubelet.clusterDns` now accepts a list of DNS resolvers rather than a single string, bringing the module more in line with the upstream Kubelet configuration schema.

- `bluemap` has changed the format used to store map tiles, and the database layout has been heavily modified. Upstream recommends a clean reinstallation: <https://github.com/BlueMap-Minecraft/BlueMap/releases/tag/v5.2>. Unless you are using an SQL storage backend, this should only entail deleting the contents of `config.services.bluemap.coreSettings.data` (defaults to `/var/lib/bluemap`) and `config.services.bluemap.webRoot` (defaults to `/var/lib/bluemap/web`).
Expand Down
127 changes: 61 additions & 66 deletions nixos/modules/services/development/zammad.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{ config, lib, pkgs, ... }:

let
cfg = config.services.zammad;
settingsFormat = pkgs.formats.yaml { };
Expand All @@ -7,11 +8,11 @@ let
Type = "simple";
Restart = "always";

User = "zammad";
Group = "zammad";
User = cfg.user;
Group = cfg.group;
PrivateTmp = true;
StateDirectory = "zammad";
WorkingDirectory = cfg.dataDir;
WorkingDirectory = package;
};
environment = {
RAILS_ENV = "production";
Expand All @@ -21,6 +22,9 @@ let
REDIS_URL = "redis://${cfg.redis.host}:${toString cfg.redis.port}";
};
databaseConfig = settingsFormat.generate "database.yml" cfg.database.settings;
package = cfg.package.override {
dataDir = cfg.dataDir;
};
in
{

Expand All @@ -30,6 +34,22 @@ in

package = lib.mkPackageOption pkgs "zammad" { };

user = lib.mkOption {
type = lib.types.str;
default = "zammad";
description = ''
Name of the Zammad user.
'';
};

group = lib.mkOption {
type = lib.types.str;
default = "zammad";
description = ''
Name of the Zammad group.
'';
};

dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/zammad";
Expand Down Expand Up @@ -94,25 +114,9 @@ in
};

database = {
type = lib.mkOption {
type = lib.types.enum [ "PostgreSQL" "MySQL" ];
default = "PostgreSQL";
example = "MySQL";
description = "Database engine to use.";
};

host = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = {
PostgreSQL = "/run/postgresql";
MySQL = "localhost";
}.${cfg.database.type};
defaultText = lib.literalExpression ''
{
PostgreSQL = "/run/postgresql";
MySQL = "localhost";
}.''${config.services.zammad.database.type};
'';
type = lib.types.str;
default = "/run/postgresql";
description = ''
Database host address.
'';
Expand Down Expand Up @@ -195,13 +199,9 @@ in
};

config = lib.mkIf cfg.enable {

services.zammad.database.settings = {
production = lib.mapAttrs (_: v: lib.mkDefault v) (filterNull {
adapter = {
PostgreSQL = "postgresql";
MySQL = "mysql2";
}.${cfg.database.type};
adapter = "postgresql";
database = cfg.database.name;
pool = 50;
timeout = 5000;
Expand All @@ -217,13 +217,12 @@ in
config.services.zammad.websocketPort
];

users.users.zammad = {
users.users.${cfg.user} = {
group = "${cfg.group}";
isSystemUser = true;
home = cfg.dataDir;
group = "zammad";
};

users.groups.zammad = { };
users.groups.${cfg.group} = { };

assertions = [
{
Expand All @@ -240,19 +239,7 @@ in
}
];

services.mysql = lib.optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") {
enable = true;
package = lib.mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{
name = cfg.database.user;
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
}
];
};

services.postgresql = lib.optionalAttrs (cfg.database.createLocally && cfg.database.type == "PostgreSQL") {
services.postgresql = lib.optionalAttrs (cfg.database.createLocally) {
enable = true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
Expand All @@ -278,54 +265,52 @@ in
};
after = [
"network.target"
"systemd-tmpfiles-setup.service"
] ++ lib.optionals (cfg.database.createLocally) [
"postgresql.service"
] ++ lib.optionals cfg.redis.createLocally [
"redis-${cfg.redis.name}.service"
];
requires = [
requires = lib.optionals (cfg.database.createLocally) [
"postgresql.service"
];
description = "Zammad web";
wantedBy = [ "multi-user.target" ];
preStart = ''
# Blindly copy the whole project here.
chmod -R +w .
rm -rf ./public/assets/
rm -rf ./tmp/*
rm -rf ./log/*
cp -r --no-preserve=owner ${cfg.package}/* .
chmod -R +w .
# config file
cp ${databaseConfig} ./config/database.yml
chmod -R +w .
cat ${databaseConfig} > ${cfg.dataDir}/config/database.yml
${lib.optionalString (cfg.database.passwordFile != null) ''
{
echo -n " password: "
cat ${cfg.database.passwordFile}
} >> ./config/database.yml
} >> ${cfg.dataDir}/config/database.yml
''}
${lib.optionalString (cfg.secretKeyBaseFile != null) ''
{
echo "production: "
echo -n " secret_key_base: "
cat ${cfg.secretKeyBaseFile}
} > ./config/secrets.yml
} > ${cfg.dataDir}/config/secrets.yml
''}

if [ `${config.services.postgresql.package}/bin/psql \
--host ${cfg.database.host} \
${lib.optionalString
(cfg.database.port != null)
"--port ${toString cfg.database.port}"} \
--username ${cfg.database.user} \
--dbname ${cfg.database.name} \
--command "SELECT COUNT(*) FROM pg_class c \
JOIN pg_namespace s ON s.oid = c.relnamespace \
WHERE s.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema') \
AND s.nspname NOT LIKE 'pg_temp%';" | sed -n 3p` -eq 0 ]; then
# needed for cleanup
shopt -s extglob

# cleanup state directory from module before refactoring in
# https://github.com/NixOS/nixpkgs/pull/277456
if [[ -e ${cfg.dataDir}/node_modules ]]; then
rm -rf ${cfg.dataDir}/!("tmp"|"config"|"log"|"state_dir_migrated"|"db_seeded")
rm -rf ${cfg.dataDir}/config/!("database.yml"|"secrets.yml")
# state directory cleanup required --> zammad was already installed --> do not seed db
echo true > ${cfg.dataDir}/db_seeded
fi

SEEDED=$(cat ${cfg.dataDir}/db_seeded)
if [[ $SEEDED != "true" ]]; then
echo "Initialize database"
./bin/rake --no-system db:migrate
./bin/rake --no-system db:seed
echo true > ${cfg.dataDir}/db_seeded
else
echo "Migrate database"
./bin/rake --no-system db:migrate
Expand All @@ -335,6 +320,16 @@ in
script = "./script/rails server -b ${cfg.host} -p ${toString cfg.port}";
};

systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -"
"d ${cfg.dataDir}/config 0750 ${cfg.user} ${cfg.group} - -"
"d ${cfg.dataDir}/tmp 0750 ${cfg.user} ${cfg.group} - -"
"d ${cfg.dataDir}/log 0750 ${cfg.user} ${cfg.group} - -"
"f ${cfg.dataDir}/config/secrets.yml 0640 ${cfg.user} ${cfg.group} - -"
"f ${cfg.dataDir}/config/database.yml 0640 ${cfg.user} ${cfg.group} - -"
"f ${cfg.dataDir}/db_seeded 0640 ${cfg.user} ${cfg.group} - -"
];

systemd.services.zammad-websocket = {
inherit serviceConfig environment;
after = [ "zammad-web.service" ];
Expand Down
28 changes: 0 additions & 28 deletions nixos/tests/zammad.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,6 @@ import ./make-test-python.nix (
services.zammad.secretKeyBaseFile = pkgs.writeText "secret" ''
52882ef142066e09ab99ce816ba72522e789505caba224a52d750ec7dc872c2c371b2fd19f16b25dfbdd435a4dd46cb3df9f82eb63fafad715056bdfe25740d6
'';

systemd.services.zammad-locale-cheat =
let cfg = config.services.zammad; in
{
serviceConfig = {
Type = "oneshot";
Restart = "on-failure";

User = "zammad";
Group = "zammad";
PrivateTmp = true;
StateDirectory = "zammad";
WorkingDirectory = cfg.dataDir;
};
wantedBy = [ "zammad-web.service" ];
description = "Hack in the locale files so zammad doesn't try to access the internet";
script = ''
mkdir -p ./config/translations
VERSION=$(cat ${cfg.package}/VERSION)
# If these files are not in place, zammad will try to access the internet.
# For the test, we only need to supply en-us.
echo '[{"locale":"en-us","alias":"en","name":"English (United States)","active":true,"dir":"ltr"}]' \
> ./config/locales-$VERSION.yml
echo '[{"locale":"en-us","format":"time","source":"date","target":"mm/dd/yyyy","target_initial":"mm/dd/yyyy"},{"locale":"en-us","format":"time","source":"timestamp","target":"mm/dd/yyyy HH:MM","target_initial":"mm/dd/yyyy HH:MM"}]' \
> ./config/translations/en-us-$VERSION.yml
'';
};
};

testScript = ''
Expand Down
23 changes: 7 additions & 16 deletions pkgs/applications/networking/misc/zammad/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
, bundlerEnv
, defaultGemConfig
, callPackage
, writeText
, procps
, ruby
, postgresql
Expand All @@ -19,16 +18,15 @@
, yarn2nix-moretea
, cacert
, redis
, dataDir ? "/var/lib/zammad"
}:

let
pname = "zammad";
version = "6.3.1";

src = applyPatches {

src = fetchFromGitHub (lib.importJSON ./source.json);

patches = [
./fix-sendmail-location.diff
];
Expand All @@ -41,16 +39,6 @@ let
'';
};

databaseConfig = writeText "database.yml" ''
production:
url: <%= ENV['DATABASE_URL'] %>
'';

secretsConfig = writeText "secrets.yml" ''
production:
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
'';

rubyEnv = bundlerEnv {
name = "${pname}-gems-${version}";
inherit version;
Expand Down Expand Up @@ -156,9 +144,12 @@ stdenv.mkDerivation {

installPhase = ''
cp -R . $out
cp ${databaseConfig} $out/config/database.yml
cp ${secretsConfig} $out/config/secrets.yml
sed -i -e "s|info|debug|" $out/config/environments/production.rb
rm -rf $out/config/database.yml $out/config/secrets.yml $out/tmp $out/log
# dataDir will be set in the module, and the package gets overriden there
ln -s ${dataDir}/config/database.yml $out/config/database.yml
ln -s ${dataDir}/config/secrets.yml $out/config/secrets.yml
ln -s ${dataDir}/tmp $out/tmp
ln -s ${dataDir}/log $out/log
NetaliDev marked this conversation as resolved.
Show resolved Hide resolved
'';

passthru = {
Expand Down