about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services/databases
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2019-06-12 09:59:45 +0000
committerAlyssa Ross <hi@alyssa.is>2019-06-18 18:14:17 +0000
commitc5571a126859eb658ffd7340cb580f7d91f12bb6 (patch)
tree577573c3bf14d9849246d52daece719a10eaf138 /nixpkgs/nixos/modules/services/databases
parent828bd4e8ddcbcd354ddfd99f55af69ee8ff5d9e7 (diff)
parent98e3b90b6c8f400ae5438ef868eb992a64b75ce5 (diff)
downloadnixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.tar
nixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.tar.gz
nixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.tar.bz2
nixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.tar.lz
nixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.tar.xz
nixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.tar.zst
nixlib-c5571a126859eb658ffd7340cb580f7d91f12bb6.zip
Merge commit '98e3b90b6c8f400ae5438ef868eb992a64b75ce5'
Diffstat (limited to 'nixpkgs/nixos/modules/services/databases')
-rw-r--r--nixpkgs/nixos/modules/services/databases/mongodb.nix67
-rw-r--r--nixpkgs/nixos/modules/services/databases/mysql.nix126
2 files changed, 126 insertions, 67 deletions
diff --git a/nixpkgs/nixos/modules/services/databases/mongodb.nix b/nixpkgs/nixos/modules/services/databases/mongodb.nix
index 3fe4af2f2619..c458a1d648a0 100644
--- a/nixpkgs/nixos/modules/services/databases/mongodb.nix
+++ b/nixpkgs/nixos/modules/services/databases/mongodb.nix
@@ -8,12 +8,13 @@ let
 
   mongodb = cfg.package;
 
-  mongoCnf = pkgs.writeText "mongodb.conf"
+  mongoCnf = cfg: pkgs.writeText "mongodb.conf"
   ''
     net.bindIp: ${cfg.bind_ip}
     ${optionalString cfg.quiet "systemLog.quiet: true"}
     systemLog.destination: syslog
     storage.dbPath: ${cfg.dbpath}
+    ${optionalString cfg.enableAuth "security.authorization: enabled"}
     ${optionalString (cfg.replSetName != "") "replication.replSetName: ${cfg.replSetName}"}
     ${cfg.extraConfig}
   '';
@@ -59,6 +60,18 @@ in
         description = "quieter output";
       };
 
+      enableAuth = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Enable client authentication. Creates a default superuser with username root!";
+      };
+      
+      initialRootPassword = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description = "Password for the root user if auth is enabled.";
+      };
+
       dbpath = mkOption {
         default = "/var/db/mongodb";
         description = "Location where MongoDB stores its files";
@@ -84,6 +97,14 @@ in
         '';
         description = "MongoDB extra configuration in YAML format";
       };
+
+      initialScript = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          A file containing MongoDB statements to execute on first startup.
+        '';
+      };
     };
 
   };
@@ -92,6 +113,11 @@ in
   ###### implementation
 
   config = mkIf config.services.mongodb.enable {
+    assertions = [
+      { assertion = !cfg.enableAuth || cfg.initialRootPassword != null;
+        message = "`enableAuth` requires `initialRootPassword` to be set.";
+      }
+    ];
 
     users.users.mongodb = mkIf (cfg.user == "mongodb")
       { name = "mongodb";
@@ -108,7 +134,7 @@ in
         after = [ "network.target" ];
 
         serviceConfig = {
-          ExecStart = "${mongodb}/bin/mongod --config ${mongoCnf} --fork --pidfilepath ${cfg.pidFile}";
+          ExecStart = "${mongodb}/bin/mongod --config ${mongoCnf cfg} --fork --pidfilepath ${cfg.pidFile}";
           User = cfg.user;
           PIDFile = cfg.pidFile;
           Type = "forking";
@@ -116,15 +142,50 @@ in
           PermissionsStartOnly = true;
         };
 
-        preStart = ''
+        preStart = let
+          cfg_ = cfg // { enableAuth = false; bind_ip = "127.0.0.1"; };
+        in ''
           rm ${cfg.dbpath}/mongod.lock || true
           if ! test -e ${cfg.dbpath}; then
               install -d -m0700 -o ${cfg.user} ${cfg.dbpath}
+              # See postStart!
+              touch ${cfg.dbpath}/.first_startup
           fi
           if ! test -e ${cfg.pidFile}; then
               install -D -o ${cfg.user} /dev/null ${cfg.pidFile}
+          fi '' + lib.optionalString cfg.enableAuth ''
+
+          if ! test -e "${cfg.dbpath}/.auth_setup_complete"; then
+            systemd-run --unit=mongodb-for-setup --uid=${cfg.user} ${mongodb}/bin/mongod --config ${mongoCnf cfg_}
+            # wait for mongodb
+            while ! ${mongodb}/bin/mongo --eval "db.version()" > /dev/null 2>&1; do sleep 0.1; done
+
+          ${mongodb}/bin/mongo <<EOF
+            use admin
+            db.createUser(
+              {
+                user: "root",
+                pwd: "${cfg.initialRootPassword}",
+                roles: [
+                  { role: "userAdminAnyDatabase", db: "admin" },
+                  { role: "dbAdminAnyDatabase", db: "admin" },
+                  { role: "readWriteAnyDatabase", db: "admin" }
+                ]
+              }
+            )
+          EOF
+            touch "${cfg.dbpath}/.auth_setup_complete"
+            systemctl stop mongodb-for-setup
           fi
         '';
+        postStart = ''
+            if test -e "${cfg.dbpath}/.first_startup"; then
+              ${optionalString (cfg.initialScript != null) ''
+                ${mongodb}/bin/mongo -u root -p ${cfg.initialRootPassword} admin "${cfg.initialScript}"
+              ''}
+              rm -f "${cfg.dbpath}/.first_startup"
+            fi
+        '';
       };
 
   };
diff --git a/nixpkgs/nixos/modules/services/databases/mysql.nix b/nixpkgs/nixos/modules/services/databases/mysql.nix
index 89291d4438ff..66d55b650a45 100644
--- a/nixpkgs/nixos/modules/services/databases/mysql.nix
+++ b/nixpkgs/nixos/modules/services/databases/mysql.nix
@@ -18,16 +18,12 @@ let
     in (pName mysql == pName pkgs.mysql57)
        && ((builtins.compareVersions mysql.version "5.7") >= 0);
 
-  pidFile = "${cfg.pidDir}/mysqld.pid";
-
-  mysqldAndInstallOptions =
-    "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}";
   mysqldOptions =
-    "${mysqldAndInstallOptions} --pid-file=${pidFile}";
+    "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}";
   # For MySQL 5.7+, --insecure creates the root user without password
   # (earlier versions and MariaDB do this by default).
   installOptions =
-    "${mysqldAndInstallOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}";
+    "${mysqldOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}";
 
 in
 
@@ -80,11 +76,6 @@ in
         description = "Location where MySQL stores its table files";
       };
 
-      pidDir = mkOption {
-        default = "/run/mysqld";
-        description = "Location of the file which stores the PID of the MySQL server";
-      };
-
       extraOptions = mkOption {
         type = types.lines;
         default = "";
@@ -133,7 +124,7 @@ in
       };
 
       initialScript = mkOption {
-        type = types.nullOr types.lines;
+        type = types.nullOr types.path;
         default = null;
         description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database";
       };
@@ -296,6 +287,10 @@ in
       ${cfg.extraOptions}
     '';
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' 0700 ${cfg.user} mysql -"
+    ];
+
     systemd.services.mysql = let
       hasNotify = (cfg.package == pkgs.mariadb);
     in {
@@ -313,68 +308,69 @@ in
           pkgs.nettools
         ];
 
-        preStart =
-          ''
-            if ! test -e ${cfg.dataDir}/mysql; then
-                mkdir -m 0700 -p ${cfg.dataDir}
-                chown -R ${cfg.user} ${cfg.dataDir}
-                ${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${installOptions}
-                touch /tmp/mysql_init
-            fi
-
-            mkdir -m 0755 -p ${cfg.pidDir}
-            chown -R ${cfg.user} ${cfg.pidDir}
-          '';
+        preStart = ''
+          if ! test -e ${cfg.dataDir}/mysql; then
+            ${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${installOptions}
+            touch /tmp/mysql_init
+          fi
+        '';
 
         serviceConfig = {
+          User = cfg.user;
+          Group = "mysql";
           Type = if hasNotify then "notify" else "simple";
           RuntimeDirectory = "mysqld";
+          RuntimeDirectoryMode = "0755";
           # The last two environment variables are used for starting Galera clusters
           ExecStart = "${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION";
         };
 
-        postStart = ''
-          ${lib.optionalString (!hasNotify) ''
-            # Wait until the MySQL server is available for use
-            count=0
-            while [ ! -e /run/mysqld/mysqld.sock ]
-            do
-                if [ $count -eq 30 ]
-                then
-                    echo "Tried 30 times, giving up..."
-                    exit 1
-                fi
-
-                echo "MySQL daemon not yet started. Waiting for 1 second..."
-                count=$((count++))
-                sleep 1
-            done
-          ''}
+        postStart =
+          let
+            cmdWatchForMysqlSocket = ''
+              # Wait until the MySQL server is available for use
+              count=0
+              while [ ! -e /run/mysqld/mysqld.sock ]
+              do
+                  if [ $count -eq 30 ]
+                  then
+                      echo "Tried 30 times, giving up..."
+                      exit 1
+                  fi
+
+                  echo "MySQL daemon not yet started. Waiting for 1 second..."
+                  count=$((count++))
+                  sleep 1
+              done
+            '';
+            cmdInitialDatabases = concatMapStrings (database: ''
+              # Create initial databases
+              if ! test -e "${cfg.dataDir}/${database.name}"; then
+                  echo "Creating initial database: ${database.name}"
+                  ( echo 'create database `${database.name}`;'
+
+                    ${optionalString (database.schema != null) ''
+                    echo 'use `${database.name}`;'
+
+                    # TODO: this silently falls through if database.schema does not exist,
+                    # we should catch this somehow and exit, but can't do it here because we're in a subshell.
+                    if [ -f "${database.schema}" ]
+                    then
+                        cat ${database.schema}
+                    elif [ -d "${database.schema}" ]
+                    then
+                        cat ${database.schema}/mysql-databases/*.sql
+                    fi
+                    ''}
+                  ) | ${mysql}/bin/mysql -u root -N
+              fi
+            '') cfg.initialDatabases;
+          in
 
+          lib.optionalString (!hasNotify) cmdWatchForMysqlSocket + ''
             if [ -f /tmp/mysql_init ]
             then
-                ${concatMapStrings (database:
-                  ''
-                    # Create initial databases
-                    if ! test -e "${cfg.dataDir}/${database.name}"; then
-                        echo "Creating initial database: ${database.name}"
-                        ( echo 'create database `${database.name}`;'
-
-                          ${optionalString (database ? "schema") ''
-                          echo 'use `${database.name}`;'
-
-                          if [ -f "${database.schema}" ]
-                          then
-                              cat ${database.schema}
-                          elif [ -d "${database.schema}" ]
-                          then
-                              cat ${database.schema}/mysql-databases/*.sql
-                          fi
-                          ''}
-                        ) | ${mysql}/bin/mysql -u root -N
-                    fi
-                  '') cfg.initialDatabases}
-
+                ${cmdInitialDatabases}
                 ${optionalString (cfg.replication.role == "master")
                   ''
                     # Set up the replication master
@@ -399,7 +395,9 @@ in
                 ${optionalString (cfg.initialScript != null)
                   ''
                     # Execute initial script
-                    cat ${cfg.initialScript} | ${mysql}/bin/mysql -u root -N
+                    # using toString to avoid copying the file to nix store if given as path instead of string,
+                    # as it might contain credentials
+                    cat ${toString cfg.initialScript} | ${mysql}/bin/mysql -u root -N
                   ''}
 
                 ${optionalString (cfg.rootPassword != null)