From 53ee544839a789d0fc10e192d3b84e7884246de4 Mon Sep 17 00:00:00 2001 From: netali Date: Fri, 29 Dec 2023 04:21:00 +0100 Subject: [PATCH 1/3] zammad: refactor package --- .../networking/misc/zammad/default.nix | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/pkgs/applications/networking/misc/zammad/default.nix b/pkgs/applications/networking/misc/zammad/default.nix index fde6f943d5170..ed178fc9c1ab8 100644 --- a/pkgs/applications/networking/misc/zammad/default.nix +++ b/pkgs/applications/networking/misc/zammad/default.nix @@ -7,7 +7,6 @@ , bundlerEnv , defaultGemConfig , callPackage -, writeText , procps , ruby , postgresql @@ -19,6 +18,7 @@ , yarn2nix-moretea , cacert , redis +, dataDir ? "/var/lib/zammad" }: let @@ -26,9 +26,7 @@ let version = "6.3.1"; src = applyPatches { - src = fetchFromGitHub (lib.importJSON ./source.json); - patches = [ ./fix-sendmail-location.diff ]; @@ -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; @@ -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 ''; passthru = { From 0e837c6a08ed48136c3cd67731017cecaece690e Mon Sep 17 00:00:00 2001 From: netali Date: Fri, 29 Dec 2023 04:21:13 +0100 Subject: [PATCH 2/3] nixos/zammad: refactor module --- .../manual/release-notes/rl-2411.section.md | 2 + nixos/modules/services/development/zammad.nix | 127 +++++++++--------- 2 files changed, 63 insertions(+), 66 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index 1874a3b336f47..1506f7eab7e70 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -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: . 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`). diff --git a/nixos/modules/services/development/zammad.nix b/nixos/modules/services/development/zammad.nix index 43ae9a34b4043..6e0be83aa384b 100644 --- a/nixos/modules/services/development/zammad.nix +++ b/nixos/modules/services/development/zammad.nix @@ -1,4 +1,5 @@ { config, lib, pkgs, ... }: + let cfg = config.services.zammad; settingsFormat = pkgs.formats.yaml { }; @@ -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"; @@ -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 { @@ -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"; @@ -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. ''; @@ -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; @@ -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 = [ { @@ -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 = [ @@ -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 @@ -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" ]; From 51f8cd4af5abede46423e8ae207620ae8e717099 Mon Sep 17 00:00:00 2001 From: netali Date: Fri, 29 Dec 2023 04:21:25 +0100 Subject: [PATCH 3/3] nixos/tests/zammad: refactor test --- nixos/tests/zammad.nix | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/nixos/tests/zammad.nix b/nixos/tests/zammad.nix index aaf32c6f13fe4..c799a29580039 100644 --- a/nixos/tests/zammad.nix +++ b/nixos/tests/zammad.nix @@ -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 = ''