summary refs log tree commit diff
path: root/nixos/modules/services/misc
diff options
context:
space:
mode:
authortalyz <kim.lindberger@gmail.com>2019-08-01 16:59:24 +0200
committertalyz <kim.lindberger@gmail.com>2019-09-06 16:56:20 +0200
commitb351454cac1eca1dc76e54e880e86d7c2bb21ffa (patch)
tree3fbbf579613b74886196765c2ee7cee1dbbc6f71 /nixos/modules/services/misc
parentcbdf94c0f3ff3edba7452f30c3185e4a5b7965f6 (diff)
downloadnixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.tar
nixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.tar.gz
nixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.tar.bz2
nixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.tar.lz
nixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.tar.xz
nixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.tar.zst
nixpkgs-b351454cac1eca1dc76e54e880e86d7c2bb21ffa.zip
nixos/gitlab: Use postgresql module options to provision local db
Use the postgresql module to provision a local db (if
databaseCreateLocally is true) instead of doing this locally.

Switch to using the local unix socket for db connections by default;
this is needed since dbs created by the postgresql module only support
peer authentication.

Instead of running the rake tasks db:schema:load, db:migrate and
db:seed_fu, run gitlab:db:configure, which in turn runs these tasks
when needed.

Solves issue #53852 for gitlab.
Diffstat (limited to 'nixos/modules/services/misc')
-rw-r--r--nixos/modules/services/misc/gitlab.nix129
1 files changed, 76 insertions, 53 deletions
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 40f921e9204..b4588fa67d8 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -12,7 +12,6 @@ let
   gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket";
   gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket";
   pathUrlQuote = url: replaceStrings ["/"] ["%2F"] url;
-  pgSuperUser = config.services.postgresql.superUser;
 
   databaseConfig = {
     production = {
@@ -237,8 +236,11 @@ in {
 
       databaseHost = mkOption {
         type = types.str;
-        default = "127.0.0.1";
-        description = "Gitlab database hostname.";
+        default = "";
+        description = ''
+          Gitlab database hostname. An empty string means <quote>use
+          local unix socket connection</quote>.
+        '';
       };
 
       databasePasswordFile = mkOption {
@@ -252,6 +254,17 @@ in {
         '';
       };
 
+      databaseCreateLocally = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether a database should be automatically created on the
+          local host. Set this to <literal>false</literal> if you plan
+          on provisioning a local database yourself or use an external
+          one.
+        '';
+      };
+
       databaseName = mkOption {
         type = types.str;
         default = "gitlab";
@@ -498,12 +511,16 @@ in {
 
     assertions = [
       {
-        assertion = cfg.initialRootPasswordFile != null;
-        message = "services.gitlab.initialRootPasswordFile must be set!";
+        assertion = cfg.databaseCreateLocally -> (cfg.user == cfg.databaseUsername);
+        message = "For local automatic database provisioning services.gitlab.user and services.gitlab.databaseUsername should be identical.";
+      }
+      {
+        assertion = (cfg.databaseHost != "") -> (cfg.databasePasswordFile != null);
+        message = "When services.gitlab.databaseHost is customized, services.gitlab.databasePasswordFile must be set!";
       }
       {
-        assertion = cfg.databasePasswordFile != null;
-        message = "services.gitlab.databasePasswordFile must be set!";
+        assertion = cfg.initialRootPasswordFile != null;
+        message = "services.gitlab.initialRootPasswordFile must be set!";
       }
       {
         assertion = cfg.secrets.secretFile != null;
@@ -527,8 +544,31 @@ in {
 
     # Redis is required for the sidekiq queue runner.
     services.redis.enable = mkDefault true;
+
     # We use postgres as the main data store.
-    services.postgresql.enable = mkDefault true;
+    services.postgresql = optionalAttrs cfg.databaseCreateLocally {
+      enable = true;
+      ensureUsers = singleton { name = cfg.databaseUsername; };
+    };
+    # The postgresql module doesn't currently support concepts like
+    # objects owners and extensions; for now we tack on what's needed
+    # here.
+    systemd.services.postgresql.postStart = mkAfter (optionalString cfg.databaseCreateLocally ''
+      $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${cfg.databaseName}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${cfg.databaseName}" OWNER "${cfg.databaseUsername}"'
+      current_owner=$($PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.databaseName}'")
+      if [[ "$current_owner" != "${cfg.databaseUsername}" ]]; then
+          $PSQL -tAc 'ALTER DATABASE "${cfg.databaseName}" OWNER TO "${cfg.databaseUsername}"'
+          if [[ -e "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" ]]; then
+              echo "Reassigning ownership of database ${cfg.databaseName} to user ${cfg.databaseUsername} failed on last boot. Failing..."
+              exit 1
+          fi
+          touch "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}"
+          $PSQL "${cfg.databaseName}" -tAc "REASSIGN OWNED BY \"$current_owner\" TO \"${cfg.databaseUsername}\""
+          rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}"
+      fi
+      $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm"
+    '');
+
     # Use postfix to send out mails.
     services.postfix.enable = mkDefault true;
 
@@ -675,15 +715,15 @@ in {
         gnupg
       ];
       preStart = ''
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} cp -f ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} rm -rf ${cfg.statePath}/db/*
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db
+        cp -f ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
+        rm -rf ${cfg.statePath}/db/*
+        cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
+        cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db
 
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${cfg.packages.gitlab-shell}/bin/install
+        ${cfg.packages.gitlab-shell}/bin/install
 
         ${optionalString cfg.smtp.enable ''
-          install -o ${cfg.user} -g ${cfg.group} -m u=rw ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb
+          install -m u=rw ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb
           ${optionalString (cfg.smtp.passwordFile != null) ''
             smtp_password=$(<'${cfg.smtp.passwordFile}')
             ${pkgs.replace}/bin/replace-literal -e '@smtpPassword@' "$smtp_password" '${cfg.statePath}/config/initializers/smtp_settings.rb'
@@ -695,6 +735,24 @@ in {
 
           ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/gitlab_shell_secret
 
+          ${if cfg.databasePasswordFile != null then ''
+              export db_password="$(<'${cfg.databasePasswordFile}')"
+
+              if [[ -z "$db_password" ]]; then
+                >&2 echo "Database password was an empty string!"
+                exit 1
+              fi
+
+              ${pkgs.jq}/bin/jq <${pkgs.writeText "database.yml" (builtins.toJSON databaseConfig)} \
+                                '.production.password = $ENV.db_password' \
+                                >'${cfg.statePath}/config/database.yml'
+            ''
+            else ''
+              ${pkgs.jq}/bin/jq <${pkgs.writeText "database.yml" (builtins.toJSON databaseConfig)} \
+                                >'${cfg.statePath}/config/database.yml'
+            ''
+          }
+
           if [[ -h '${cfg.statePath}/config/secrets.yml' ]]; then
             rm '${cfg.statePath}/config/secrets.yml'
           fi
@@ -708,54 +766,19 @@ in {
                                               db_key_base: $ENV.otp,
                                               openid_connect_signing_key: $ENV.jws}}' \
                             > '${cfg.statePath}/config/secrets.yml'
-
-          chown ${cfg.user}:${cfg.group} '${cfg.statePath}/config/secrets.yml' '${cfg.statePath}/gitlab_shell_secret'
         )
 
-        export db_password="$(<'${cfg.databasePasswordFile}')"
-
-        if [[ -z "$db_password" ]]; then
-          >&2 echo "Database password was an empty string!"
-          exit 1
-        fi
-
-        ${pkgs.jq}/bin/jq <${pkgs.writeText "database.yml" (builtins.toJSON databaseConfig)} \
-                          '.production.password = $ENV.db_password' \
-                          >'${cfg.statePath}/config/database.yml'
-        chown ${cfg.user}:${cfg.group} '${cfg.statePath}/config/database.yml'
-
-        if ! test -e "${cfg.statePath}/db-created"; then
-          if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then
-            ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "CREATE ROLE ${cfg.databaseUsername} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '$db_password'"
-            ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} ${config.services.postgresql.package}/bin/createdb --owner ${cfg.databaseUsername} ${cfg.databaseName}
-
-            # enable required pg_trgm extension for gitlab
-            ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql ${cfg.databaseName} -c "CREATE EXTENSION IF NOT EXISTS pg_trgm"
-          fi
-
-          ${pkgs.sudo}/bin/sudo -u ${cfg.user} -H ${gitlab-rake}/bin/gitlab-rake db:schema:load
-
-          ${pkgs.sudo}/bin/sudo -u ${cfg.user} touch "${cfg.statePath}/db-created"
-        fi
-
-        # Always do the db migrations just to be sure the database is up-to-date
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} -H ${gitlab-rake}/bin/gitlab-rake db:migrate
-
-        if ! test -e "${cfg.statePath}/db-seeded"; then
-          initial_root_password="$(<'${cfg.initialRootPasswordFile}')"
-          ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${gitlab-rake}/bin/gitlab-rake db:seed_fu \
-            GITLAB_ROOT_PASSWORD="$initial_root_password" GITLAB_ROOT_EMAIL='${cfg.initialRootEmail}'
-          ${pkgs.sudo}/bin/sudo -u ${cfg.user} touch "${cfg.statePath}/db-seeded"
-        fi
+        initial_root_password="$(<'${cfg.initialRootPasswordFile}')"
+        ${gitlab-rake}/bin/gitlab-rake gitlab:db:configure GITLAB_ROOT_PASSWORD="$initial_root_password" \
+                                                           GITLAB_ROOT_EMAIL='${cfg.initialRootEmail}'
 
         # We remove potentially broken links to old gitlab-shell versions
         rm -Rf ${cfg.statePath}/repositories/**/*.git/hooks
 
-        ${pkgs.sudo}/bin/sudo -u ${cfg.user} -H ${pkgs.git}/bin/git config --global core.autocrlf "input"
+        ${pkgs.git}/bin/git config --global core.autocrlf "input"
       '';
 
       serviceConfig = {
-        PermissionsStartOnly = true; # preStart must be run as root
         Type = "simple";
         User = cfg.user;
         Group = cfg.group;