Unverified Commit ac24b971 authored by Jenny's avatar Jenny Committed by GitHub
Browse files

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

parents 3eb54812 4ad703d6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@

- Support for CUDA 10 has been dropped, as announced in the 24.11 release notes.

- `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.

- `kanata` was updated to v1.7.0, which introduces several breaking changes.
  See the release notes of
  [v1.7.0](https://github.com/jtroo/kanata/releases/tag/v1.7.0)
+61 −66
Original line number Diff line number Diff line
{ 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" ];
+0 −28
Original line number Diff line number Diff line
@@ -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 = ''
+7 −16
Original line number Diff line number Diff line
@@ -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 = {