diff options
Diffstat (limited to 'nixos/modules/services/databases')
-rw-r--r-- | nixos/modules/services/databases/cassandra.nix | 15 | ||||
-rw-r--r-- | nixos/modules/services/databases/couchdb.nix | 25 | ||||
-rw-r--r-- | nixos/modules/services/databases/foundationdb.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/databases/mongodb.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/databases/mysql.nix | 260 | ||||
-rw-r--r-- | nixos/modules/services/databases/openldap.nix | 468 | ||||
-rw-r--r-- | nixos/modules/services/databases/postgresql.nix | 158 | ||||
-rw-r--r-- | nixos/modules/services/databases/redis.nix | 87 | ||||
-rw-r--r-- | nixos/modules/services/databases/riak-cs.nix | 202 | ||||
-rw-r--r-- | nixos/modules/services/databases/riak.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/databases/stanchion.nix | 194 | ||||
-rw-r--r-- | nixos/modules/services/databases/victoriametrics.nix | 6 |
12 files changed, 580 insertions, 841 deletions
diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix index 90c094f68b6..d55a7db3915 100644 --- a/nixos/modules/services/databases/cassandra.nix +++ b/nixos/modules/services/databases/cassandra.nix @@ -38,13 +38,18 @@ let cassandraYaml = builtins.toJSON cassandraConfigWithAddresses; cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh"; cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig; + passAsFile = [ "extraEnvSh" ]; + inherit (cfg) extraEnvSh; buildCommand = '' mkdir -p "$out" echo "$cassandraYaml" > "$out/cassandra.yaml" ln -s "$cassandraLogbackConfig" "$out/logback.xml" - cp "$cassandraEnvPkg" "$out/cassandra-env.sh" + ( cat "$cassandraEnvPkg" + echo "# lines from services.cassandra.extraEnvSh: " + cat "$extraEnvShPath" + ) > "$out/cassandra-env.sh" # Delete default JMX Port, otherwise we can't set it using env variable sed -i '/JMX_PORT="7199"/d' "$out/cassandra-env.sh" @@ -224,6 +229,14 @@ in { Extra options to be merged into cassandra.yaml as nix attribute set. ''; }; + extraEnvSh = mkOption { + type = types.lines; + default = ""; + example = "CLASSPATH=$CLASSPATH:\${extraJar}"; + description = '' + Extra shell lines to be appended onto cassandra-env.sh. + ''; + }; fullRepairInterval = mkOption { type = types.nullOr types.str; default = "3w"; diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix index 53224db1d89..f385331e878 100644 --- a/nixos/modules/services/databases/couchdb.nix +++ b/nixos/modules/services/databases/couchdb.nix @@ -11,7 +11,13 @@ let database_dir = ${cfg.databaseDir} uri_file = ${cfg.uriFile} view_index_dir = ${cfg.viewIndexDir} - '' + (if useVersion2 then + '' + (if cfg.adminPass != null then + '' + [admins] + ${cfg.adminUser} = ${cfg.adminPass} + '' else + '' + '') + (if useVersion2 then '' [chttpd] '' else @@ -54,6 +60,23 @@ in { ''; }; + adminUser = mkOption { + type = types.str; + default = "admin"; + description = '' + Couchdb (i.e. fauxton) account with permission for all dbs and + tasks. + ''; + }; + + adminPass = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Couchdb (i.e. fauxton) account with permission for all dbs and + tasks. + ''; + }; user = mkOption { type = types.str; diff --git a/nixos/modules/services/databases/foundationdb.nix b/nixos/modules/services/databases/foundationdb.nix index 18727acc7c7..e22127403e9 100644 --- a/nixos/modules/services/databases/foundationdb.nix +++ b/nixos/modules/services/databases/foundationdb.nix @@ -233,7 +233,7 @@ in type = types.str; default = "Check.Valid=1,Check.Unexpired=1"; description = '' - "Peer verification string". This may be used to adjust which TLS + "Peer verification string". This may be used to adjust which TLS client certificates a server will accept, as a form of user authorization; for example, it may only accept TLS clients who offer a certificate abiding by some locality or organization name. diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix index 0f81a8a69e0..db1e5fedf50 100644 --- a/nixos/modules/services/databases/mongodb.nix +++ b/nixos/modules/services/databases/mongodb.nix @@ -183,7 +183,7 @@ in postStart = '' if test -e "${cfg.dbpath}/.first_startup"; then ${optionalString (cfg.initialScript != null) '' - ${mongodb}/bin/mongo -u root -p ${cfg.initialRootPassword} admin "${cfg.initialScript}" + ${mongodb}/bin/mongo ${optionalString (cfg.enableAuth) "-u root -p ${cfg.initialRootPassword}"} admin "${cfg.initialScript}" ''} rm -f "${cfg.dbpath}/.first_startup" fi diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index 2e8c5b7640b..7d0a3f9afc4 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -6,12 +6,10 @@ let cfg = config.services.mysql; - mysql = cfg.package; - - isMariaDB = lib.getName mysql == lib.getName pkgs.mariadb; + isMariaDB = lib.getName cfg.package == lib.getName pkgs.mariadb; mysqldOptions = - "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}"; + "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${cfg.package}"; settingsFile = pkgs.writeText "my.cnf" ( generators.toINI { listsAsDuplicateKeys = true; } cfg.settings + @@ -22,7 +20,7 @@ in { imports = [ - (mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd") + (mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") (mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") ]; @@ -46,25 +44,31 @@ in type = types.nullOr types.str; default = null; example = literalExample "0.0.0.0"; - description = "Address to bind to. The default is to bind to all addresses"; + description = "Address to bind to. The default is to bind to all addresses."; }; port = mkOption { type = types.int; default = 3306; - description = "Port of MySQL"; + description = "Port of MySQL."; }; user = mkOption { type = types.str; default = "mysql"; - description = "User account under which MySQL runs"; + description = "User account under which MySQL runs."; + }; + + group = mkOption { + type = types.str; + default = "mysql"; + description = "Group under which MySQL runs."; }; dataDir = mkOption { type = types.path; example = "/var/lib/mysql"; - description = "Location where MySQL stores its table files"; + description = "Location where MySQL stores its table files."; }; configFile = mkOption { @@ -171,7 +175,7 @@ in initialScript = mkOption { 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"; + description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database."; }; ensureDatabases = mkOption { @@ -259,33 +263,33 @@ in serverId = mkOption { type = types.int; default = 1; - description = "Id of the MySQL server instance. This number must be unique for each instance"; + description = "Id of the MySQL server instance. This number must be unique for each instance."; }; masterHost = mkOption { type = types.str; - description = "Hostname of the MySQL master server"; + description = "Hostname of the MySQL master server."; }; slaveHost = mkOption { type = types.str; - description = "Hostname of the MySQL slave server"; + description = "Hostname of the MySQL slave server."; }; masterUser = mkOption { type = types.str; - description = "Username of the MySQL replication user"; + description = "Username of the MySQL replication user."; }; masterPassword = mkOption { type = types.str; - description = "Password of the MySQL replication user"; + description = "Password of the MySQL replication user."; }; masterPort = mkOption { type = types.int; default = 3306; - description = "Port number on which the MySQL master server runs"; + description = "Port number on which the MySQL master server runs."; }; }; }; @@ -317,29 +321,33 @@ in binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; }) (mkIf (!isMariaDB) { - plugin-load-add = optional (cfg.ensureUsers != []) "auth_socket.so"; + plugin-load-add = "auth_socket.so"; }) ]; - users.users.mysql = { - description = "MySQL server user"; - group = "mysql"; - uid = config.ids.uids.mysql; + users.users = optionalAttrs (cfg.user == "mysql") { + mysql = { + description = "MySQL server user"; + group = cfg.group; + uid = config.ids.uids.mysql; + }; }; - users.groups.mysql.gid = config.ids.gids.mysql; + users.groups = optionalAttrs (cfg.group == "mysql") { + mysql.gid = config.ids.gids.mysql; + }; - environment.systemPackages = [mysql]; + environment.systemPackages = [ cfg.package ]; environment.etc."my.cnf".source = cfg.configFile; systemd.tmpfiles.rules = [ - "d '${cfg.dataDir}' 0700 ${cfg.user} mysql - -" - "z '${cfg.dataDir}' 0700 ${cfg.user} mysql - -" + "d '${cfg.dataDir}' 0700 '${cfg.user}' '${cfg.group}' - -" + "z '${cfg.dataDir}' 0700 '${cfg.user}' '${cfg.group}' - -" ]; systemd.services.mysql = let - hasNotify = (cfg.package == pkgs.mariadb); + hasNotify = isMariaDB; in { description = "MySQL Server"; @@ -357,125 +365,127 @@ in preStart = if isMariaDB then '' if ! test -e ${cfg.dataDir}/mysql; then - ${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${mysqldOptions} + ${cfg.package}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${mysqldOptions} touch ${cfg.dataDir}/mysql_init fi '' else '' if ! test -e ${cfg.dataDir}/mysql; then - ${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} --initialize-insecure + ${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} --initialize-insecure touch ${cfg.dataDir}/mysql_init fi ''; - serviceConfig = { - Type = if hasNotify then "notify" else "simple"; - Restart = "on-abort"; - RestartSec = "5s"; - # 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"; - ExecStartPost = - let - setupScript = pkgs.writeScript "mysql-setup" '' - #!${pkgs.runtimeShell} -e - - ${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 - ''} - - if [ -f ${cfg.dataDir}/mysql_init ] + postStart = let + # The super user account to use on *first* run of MySQL server + superUser = if isMariaDB then cfg.user else "root"; + in '' + ${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 - ${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} - - ${optionalString (cfg.replication.role == "master") - '' - # Set up the replication master + echo "Tried 30 times, giving up..." + exit 1 + fi - ( echo "use mysql;" - echo "CREATE USER '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' IDENTIFIED WITH mysql_native_password;" - echo "SET PASSWORD FOR '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' = PASSWORD('${cfg.replication.masterPassword}');" - echo "GRANT REPLICATION SLAVE ON *.* TO '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}';" - ) | ${mysql}/bin/mysql -u root -N + echo "MySQL daemon not yet started. Waiting for 1 second..." + count=$((count++)) + sleep 1 + done + ''} + + if [ -f ${cfg.dataDir}/mysql_init ] + then + # While MariaDB comes with a 'mysql' super user account since 10.4.x, MySQL does not + # Since we don't want to run this service as 'root' we need to ensure the account exists on first run + ( echo "CREATE USER IF NOT EXISTS '${cfg.user}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};" + echo "GRANT ALL PRIVILEGES ON *.* TO '${cfg.user}'@'localhost' WITH GRANT OPTION;" + ) | ${cfg.package}/bin/mysql -u ${superUser} -N + + ${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 ''} + ) | ${cfg.package}/bin/mysql -u ${superUser} -N + fi + '') cfg.initialDatabases} - ${optionalString (cfg.replication.role == "slave") - '' - # Set up the replication slave + ${optionalString (cfg.replication.role == "master") + '' + # Set up the replication master - ( echo "stop slave;" - echo "change master to master_host='${cfg.replication.masterHost}', master_user='${cfg.replication.masterUser}', master_password='${cfg.replication.masterPassword}';" - echo "start slave;" - ) | ${mysql}/bin/mysql -u root -N - ''} + ( echo "use mysql;" + echo "CREATE USER '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' IDENTIFIED WITH mysql_native_password;" + echo "SET PASSWORD FOR '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' = PASSWORD('${cfg.replication.masterPassword}');" + echo "GRANT REPLICATION SLAVE ON *.* TO '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}';" + ) | ${cfg.package}/bin/mysql -u ${superUser} -N + ''} - ${optionalString (cfg.initialScript != null) - '' - # Execute initial script - # 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.replication.role == "slave") + '' + # Set up the replication slave - rm ${cfg.dataDir}/mysql_init - fi + ( echo "stop slave;" + echo "change master to master_host='${cfg.replication.masterHost}', master_user='${cfg.replication.masterUser}', master_password='${cfg.replication.masterPassword}';" + echo "start slave;" + ) | ${cfg.package}/bin/mysql -u ${superUser} -N + ''} - ${optionalString (cfg.ensureDatabases != []) '' - ( - ${concatMapStrings (database: '' - echo "CREATE DATABASE IF NOT EXISTS \`${database}\`;" - '') cfg.ensureDatabases} - ) | ${mysql}/bin/mysql -u root -N + ${optionalString (cfg.initialScript != null) + '' + # Execute initial script + # 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} | ${cfg.package}/bin/mysql -u ${superUser} -N ''} - ${concatMapStrings (user: - '' - ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};" - ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' - echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';" - '') user.ensurePermissions)} - ) | ${mysql}/bin/mysql -u root -N - '') cfg.ensureUsers} - ''; - in - # ensureDatbases & ensureUsers depends on this script being run as root - # when the user has secured their mysql install - "+${setupScript}"; + rm ${cfg.dataDir}/mysql_init + fi + + ${optionalString (cfg.ensureDatabases != []) '' + ( + ${concatMapStrings (database: '' + echo "CREATE DATABASE IF NOT EXISTS \`${database}\`;" + '') cfg.ensureDatabases} + ) | ${cfg.package}/bin/mysql -N + ''} + + ${concatMapStrings (user: + '' + ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};" + ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' + echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';" + '') user.ensurePermissions)} + ) | ${cfg.package}/bin/mysql -N + '') cfg.ensureUsers} + ''; + + serviceConfig = { + Type = if hasNotify then "notify" else "simple"; + Restart = "on-abort"; + RestartSec = "5s"; + # The last two environment variables are used for starting Galera clusters + ExecStart = "${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION"; # User and group User = cfg.user; - Group = "mysql"; + Group = cfg.group; # Runtime directory and mode RuntimeDirectory = "mysqld"; RuntimeDirectoryMode = "0755"; diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix index 9b4d9a98b74..f0efc659cff 100644 --- a/nixos/modules/services/databases/openldap.nix +++ b/nixos/modules/services/databases/openldap.nix @@ -1,43 +1,121 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.openldap; - openldap = pkgs.openldap; - - dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents; - configFile = pkgs.writeText "slapd.conf" ((optionalString cfg.defaultSchemas '' - include ${pkgs.openldap.out}/etc/schema/core.schema - include ${pkgs.openldap.out}/etc/schema/cosine.schema - include ${pkgs.openldap.out}/etc/schema/inetorgperson.schema - include ${pkgs.openldap.out}/etc/schema/nis.schema - '') + '' - ${cfg.extraConfig} - database ${cfg.database} - suffix ${cfg.suffix} - rootdn ${cfg.rootdn} - ${if (cfg.rootpw != null) then '' - rootpw ${cfg.rootpw} - '' else '' - include ${cfg.rootpwFile} - ''} - directory ${cfg.dataDir} - ${cfg.extraDatabaseConfig} - ''); - configOpts = if cfg.configDir == null then "-f ${configFile}" - else "-F ${cfg.configDir}"; -in - -{ - - ###### interface - + legacyOptions = [ "rootpwFile" "suffix" "dataDir" "rootdn" "rootpw" ]; + openldap = cfg.package; + configDir = if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d"; + + ldapValueType = let + # Can't do types.either with multiple non-overlapping submodules, so define our own + singleLdapValueType = lib.mkOptionType rec { + name = "LDAP"; + description = "LDAP value"; + check = x: lib.isString x || (lib.isAttrs x && (x ? path || x ? base64)); + merge = lib.mergeEqualOption; + }; + # We don't coerce to lists of single values, as some values must be unique + in types.either singleLdapValueType (types.listOf singleLdapValueType); + + ldapAttrsType = + let + options = { + attrs = mkOption { + type = types.attrsOf ldapValueType; + default = {}; + description = "Attributes of the parent entry."; + }; + children = mkOption { + # Hide the child attributes, to avoid infinite recursion in e.g. documentation + # Actual Nix evaluation is lazy, so this is not an issue there + type = let + hiddenOptions = lib.mapAttrs (name: attr: attr // { visible = false; }) options; + in types.attrsOf (types.submodule { options = hiddenOptions; }); + default = {}; + description = "Child entries of the current entry, with recursively the same structure."; + example = lib.literalExample '' + { + "cn=schema" = { + # The attribute used in the DN must be defined + attrs = { cn = "schema"; }; + children = { + # This entry's DN is expanded to "cn=foo,cn=schema" + "cn=foo" = { ... }; + }; + # These includes are inserted after "cn=schema", but before "cn=foo,cn=schema" + includes = [ ... ]; + }; + } + ''; + }; + includes = mkOption { + type = types.listOf types.path; + default = []; + description = '' + LDIF files to include after the parent's attributes but before its children. + ''; + }; + }; + in types.submodule { inherit options; }; + + valueToLdif = attr: values: let + listValues = if lib.isList values then values else lib.singleton values; + in map (value: + if lib.isAttrs value then + if lib.hasAttr "path" value + then "${attr}:< file://${value.path}" + else "${attr}:: ${value.base64}" + else "${attr}: ${lib.replaceStrings [ "\n" ] [ "\n " ] value}" + ) listValues; + + attrsToLdif = dn: { attrs, children, includes, ... }: ['' + dn: ${dn} + ${lib.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList valueToLdif attrs))} + ''] ++ (map (path: "include: file://${path}\n") includes) ++ ( + lib.flatten (lib.mapAttrsToList (name: value: attrsToLdif "${name},${dn}" value) children) + ); +in { + imports = let + deprecationNote = "This option is removed due to the deprecation of `slapd.conf` upstream. Please migrate to `services.openldap.settings`, see the release notes for advice with this process."; + mkDatabaseOption = old: new: + lib.mkChangedOptionModule [ "services" "openldap" old ] [ "services" "openldap" "settings" "children" ] + (config: let + database = lib.getAttrFromPath [ "services" "openldap" "database" ] config; + value = lib.getAttrFromPath [ "services" "openldap" old ] config; + in lib.setAttrByPath ([ "olcDatabase={1}${database}" "attrs" ] ++ new) value); + in [ + (lib.mkRemovedOptionModule [ "services" "openldap" "extraConfig" ] deprecationNote) + (lib.mkRemovedOptionModule [ "services" "openldap" "extraDatabaseConfig" ] deprecationNote) + + (lib.mkChangedOptionModule [ "services" "openldap" "logLevel" ] [ "services" "openldap" "settings" "attrs" "olcLogLevel" ] + (config: lib.splitString " " (lib.getAttrFromPath [ "services" "openldap" "logLevel" ] config))) + (lib.mkChangedOptionModule [ "services" "openldap" "defaultSchemas" ] [ "services" "openldap" "settings" "children" "cn=schema" "includes"] + (config: lib.optionals (lib.getAttrFromPath [ "services" "openldap" "defaultSchemas" ] config) ( + map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ]))) + + (lib.mkChangedOptionModule [ "services" "openldap" "database" ] [ "services" "openldap" "settings" "children" ] + (config: let + database = lib.getAttrFromPath [ "services" "openldap" "database" ] config; + in { + "olcDatabase={1}${database}".attrs = { + # objectClass is case-insensitive, so don't need to capitalize ${database} + objectClass = [ "olcdatabaseconfig" "olc${database}config" ]; + olcDatabase = "{1}${database}"; + olcDbDirectory = lib.mkDefault "/var/db/openldap"; + }; + "cn=schema".includes = lib.mkDefault ( + map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ] + ); + })) + (mkDatabaseOption "rootpwFile" [ "olcRootPW" "path" ]) + (mkDatabaseOption "suffix" [ "olcSuffix" ]) + (mkDatabaseOption "dataDir" [ "olcDbDirectory" ]) + (mkDatabaseOption "rootdn" [ "olcRootDN" ]) + (mkDatabaseOption "rootpw" [ "olcRootPW" ]) + ]; options = { - services.openldap = { - enable = mkOption { type = types.bool; default = false; @@ -46,6 +124,18 @@ in "; }; + package = mkOption { + type = types.package; + default = pkgs.openldap; + description = '' + OpenLDAP package to use. + + This can be used to, for example, set an OpenLDAP package + with custom overrides to enable modules or other + functionality. + ''; + }; + user = mkOption { type = types.str; default = "openldap"; @@ -65,224 +155,170 @@ in example = [ "ldaps:///" ]; }; - dataDir = mkOption { - type = types.path; - default = "/var/db/openldap"; - description = "The database directory."; - }; - - defaultSchemas = mkOption { - type = types.bool; - default = true; - description = '' - Include the default schemas core, cosine, inetorgperson and nis. - This setting will be ignored if configDir is set. - ''; - }; - - database = mkOption { - type = types.str; - default = "mdb"; - description = '' - Database type to use for the LDAP. - This setting will be ignored if configDir is set. - ''; - }; - - suffix = mkOption { - type = types.str; - example = "dc=example,dc=org"; - description = '' - Specify the DN suffix of queries that will be passed to this backend - database. - This setting will be ignored if configDir is set. - ''; - }; - - rootdn = mkOption { - type = types.str; - example = "cn=admin,dc=example,dc=org"; - description = '' - Specify the distinguished name that is not subject to access control - or administrative limit restrictions for operations on this database. - This setting will be ignored if configDir is set. - ''; - }; - - rootpw = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Password for the root user. - This setting will be ignored if configDir is set. - Using this option will store the root password in plain text in the - world-readable nix store. To avoid this the <literal>rootpwFile</literal> can be used. - ''; - }; - - rootpwFile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Password file for the root user. - The file should contain the string <literal>rootpw</literal> followed by the password. - e.g.: <literal>rootpw mysecurepassword</literal> + settings = mkOption { + type = ldapAttrsType; + description = "Configuration for OpenLDAP, in OLC format"; + example = lib.literalExample '' + { + attrs.olcLogLevel = [ "stats" ]; + children = { + "cn=schema".includes = [ + "\${pkgs.openldap}/etc/schema/core.ldif" + "\${pkgs.openldap}/etc/schema/cosine.ldif" + "\${pkgs.openldap}/etc/schema/inetorgperson.ldif" + ]; + "olcDatabase={-1}frontend" = { + attrs = { + objectClass = "olcDatabaseConfig"; + olcDatabase = "{-1}frontend"; + olcAccess = [ "{0}to * by dn.exact=uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth manage stop by * none stop" ]; + }; + }; + "olcDatabase={0}config" = { + attrs = { + objectClass = "olcDatabaseConfig"; + olcDatabase = "{0}config"; + olcAccess = [ "{0}to * by * none break" ]; + }; + }; + "olcDatabase={1}mdb" = { + attrs = { + objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; + olcDatabase = "{1}mdb"; + olcDbDirectory = "/var/db/ldap"; + olcDbIndex = [ + "objectClass eq" + "cn pres,eq" + "uid pres,eq" + "sn pres,eq,subany" + ]; + olcSuffix = "dc=example,dc=com"; + olcAccess = [ "{0}to * by * read break" ]; + }; + }; + }; + }; ''; }; - logLevel = mkOption { - type = types.str; - default = "0"; - example = "acl trace"; - description = "The log level selector of slapd."; - }; - + # This option overrides settings configDir = mkOption { type = types.nullOr types.path; default = null; - description = "Use this optional config directory instead of using slapd.conf"; + description = '' + Use this config directory instead of generating one from the + <literal>settings</literal> option. Overrides all NixOS settings. If + you use this option,ensure `olcPidFile` is set to `/run/slapd/slapd.conf`. + ''; example = "/var/db/slapd.d"; }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = " - slapd.conf configuration - "; - example = literalExample '' - ''' - include ${pkgs.openldap.out}/etc/schema/core.schema - include ${pkgs.openldap.out}/etc/schema/cosine.schema - include ${pkgs.openldap.out}/etc/schema/inetorgperson.schema - include ${pkgs.openldap.out}/etc/schema/nis.schema - - database bdb - suffix dc=example,dc=org - rootdn cn=admin,dc=example,dc=org - # NOTE: change after first start - rootpw secret - directory /var/db/openldap - ''' - ''; - }; - declarativeContents = mkOption { - type = with types; nullOr lines; - default = null; + type = with types; attrsOf lines; + default = {}; description = '' - Declarative contents for the LDAP database, in LDIF format. + Declarative contents for the LDAP database, in LDIF format by suffix. - Note a few facts when using it. First, the database - <emphasis>must</emphasis> be stored in the directory defined by - <code>dataDir</code>. Second, all <code>dataDir</code> will be erased - when starting the LDAP server. Third, modifications to the database - are not prevented, they are just dropped on the next reboot of the - server. Finally, performance-wise the database and indexes are rebuilt - on each server startup, so this will slow down server startup, + All data will be erased when starting the LDAP server. Modifications + to the database are not prevented, they are just dropped on the next + reboot of the server. Performance-wise the database and indexes are + rebuilt on each server startup, so this will slow down server startup, especially with large databases. ''; - example = '' - dn: dc=example,dc=org - objectClass: domain - dc: example - - dn: ou=users,dc=example,dc=org - objectClass = organizationalUnit - ou: users - - # ... - ''; - }; - - extraDatabaseConfig = mkOption { - type = types.lines; - default = ""; - description = '' - slapd.conf configuration after the database option. - This setting will be ignored if configDir is set. - ''; - example = '' - # Indices to maintain for this directory - # unique id so equality match only - index uid eq - # allows general searching on commonname, givenname and email - index cn,gn,mail eq,sub - # allows multiple variants on surname searching - index sn eq,sub - # sub above includes subintial,subany,subfinal - # optimise department searches - index ou eq - # if searches will include objectClass uncomment following - # index objectClass eq - # shows use of default index parameter - index default eq,sub - # indices missing - uses default eq,sub - index telephonenumber - - # other database parameters - # read more in slapd.conf reference section - cachesize 10000 - checkpoint 128 15 + example = lib.literalExample '' + { + "dc=example,dc=org" = ''' + dn= dn: dc=example,dc=org + objectClass: domain + dc: example + + dn: ou=users,dc=example,dc=org + objectClass = organizationalUnit + ou: users + + # ... + '''; + } ''; }; - }; - }; - meta = { - maintainers = [ lib.maintainers.mic92 ]; - }; - - - ###### implementation + meta.maintainers = with lib.maintainers; [ mic92 kwohlfahrt ]; config = mkIf cfg.enable { - assertions = [ - { - assertion = cfg.configDir != null || cfg.rootpwFile != null || cfg.rootpw != null; - message = "services.openldap: Unless configDir is set, either rootpw or rootpwFile must be set"; - } - ]; - + assertions = map (opt: { + assertion = ((getAttr opt cfg) != "_mkMergedOptionModule") -> (cfg.database != "_mkMergedOptionModule"); + message = "Legacy OpenLDAP option `services.openldap.${opt}` requires `services.openldap.database` (use value \"mdb\" if unsure)"; + }) legacyOptions; environment.systemPackages = [ openldap ]; + # Literal attributes must always be set + services.openldap.settings = { + attrs = { + objectClass = "olcGlobal"; + cn = "config"; + olcPidFile = "/run/slapd/slapd.pid"; + }; + children."cn=schema".attrs = { + cn = "schema"; + objectClass = "olcSchemaConfig"; + }; + }; + systemd.services.openldap = { description = "LDAP server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - preStart = '' + preStart = let + settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings)); + + dbSettings = lib.filterAttrs (name: value: lib.hasPrefix "olcDatabase=" name) cfg.settings.children; + dataDirs = lib.mapAttrs' (name: value: lib.nameValuePair value.attrs.olcSuffix value.attrs.olcDbDirectory) + (lib.filterAttrs (_: value: value.attrs ? olcDbDirectory) dbSettings); + dataFiles = lib.mapAttrs (dn: contents: pkgs.writeText "${dn}.ldif" contents) cfg.declarativeContents; + mkLoadScript = dn: let + dataDir = lib.escapeShellArg (getAttr dn dataDirs); + in '' + rm -rf ${dataDir}/* + ${openldap}/bin/slapadd -F ${lib.escapeShellArg configDir} -b ${dn} -l ${getAttr dn dataFiles} + chown -R "${cfg.user}:${cfg.group}" ${dataDir} + ''; + in '' mkdir -p /run/slapd chown -R "${cfg.user}:${cfg.group}" /run/slapd - ${optionalString (cfg.declarativeContents != null) '' - rm -Rf "${cfg.dataDir}" - ''} - mkdir -p "${cfg.dataDir}" - ${optionalString (cfg.declarativeContents != null) '' - ${openldap.out}/bin/slapadd ${configOpts} -l ${dataFile} - ''} - chown -R "${cfg.user}:${cfg.group}" "${cfg.dataDir}" - ${openldap}/bin/slaptest ${configOpts} + mkdir -p ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)} + chown "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)} + + ${lib.optionalString (cfg.configDir == null) ('' + rm -Rf ${configDir}/* + ${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile} + '')} + chown -R "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} + + ${lib.concatStrings (map mkLoadScript (lib.attrNames cfg.declarativeContents))} + ${openldap}/bin/slaptest -u -F ${lib.escapeShellArg configDir} ''; - serviceConfig.ExecStart = - "${openldap.out}/libexec/slapd -d '${cfg.logLevel}' " + - "-u '${cfg.user}' -g '${cfg.group}' " + - "-h '${concatStringsSep " " cfg.urlList}' " + - "${configOpts}"; + serviceConfig = { + ExecStart = lib.escapeShellArgs ([ + "${openldap}/libexec/slapd" "-u" cfg.user "-g" cfg.group "-F" configDir + "-h" (lib.concatStringsSep " " cfg.urlList) + ]); + Type = "forking"; + PIDFile = cfg.settings.attrs.olcPidFile; + }; }; - users.users.openldap = - { name = cfg.user; + users.users = lib.optionalAttrs (cfg.user == "openldap") { + openldap = { group = cfg.group; - uid = config.ids.uids.openldap; - }; - - users.groups.openldap = - { name = cfg.group; - gid = config.ids.gids.openldap; + isSystemUser = true; }; + }; + users.groups = lib.optionalAttrs (cfg.group == "openldap") { + openldap = {}; + }; }; } diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index 579b6a4d9c6..f582b059277 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -11,23 +11,23 @@ let then cfg.package else cfg.package.withPackages (_: cfg.extraPlugins); + toStr = value: + if true == value then "yes" + else if false == value then "no" + else if isString value then "'${lib.replaceStrings ["'"] ["''"] value}'" + else toString value; + # The main PostgreSQL configuration file. - configFile = pkgs.writeText "postgresql.conf" - '' - hba_file = '${pkgs.writeText "pg_hba.conf" cfg.authentication}' - ident_file = '${pkgs.writeText "pg_ident.conf" cfg.identMap}' - log_destination = 'stderr' - log_line_prefix = '${cfg.logLinePrefix}' - listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}' - port = ${toString cfg.port} - ${cfg.extraConfig} - ''; + configFile = pkgs.writeText "postgresql.conf" (concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${toStr v}") cfg.settings)); groupAccessAvailable = versionAtLeast postgresql.version "11.0"; in { + imports = [ + (mkRemovedOptionModule [ "services" "postgresql" "extraConfig" ] "Use services.postgresql.settings instead.") + ]; ###### interface @@ -55,9 +55,13 @@ in dataDir = mkOption { type = types.path; + defaultText = "/var/lib/postgresql/\${config.services.postgresql.package.psqlSchema}"; example = "/var/lib/postgresql/11"; description = '' - Data directory for PostgreSQL. + The data directory for PostgreSQL. If left as the default value + this directory will automatically be created before the PostgreSQL server starts, otherwise + the sysadmin is responsible for ensuring the directory exists with appropriate ownership + and permissions. ''; }; @@ -65,11 +69,16 @@ in type = types.lines; default = ""; description = '' - Defines how users authenticate themselves to the server. By - default, "trust" access to local users will always be granted - along with any other custom options. If you do not want this, - set this option using "lib.mkForce" to override this - behaviour. + Defines how users authenticate themselves to the server. See the + <link xlink:href="https://www.postgresql.org/docs/current/auth-pg-hba-conf.html"> + PostgreSQL documentation for pg_hba.conf</link> + for details on the expected format of this option. By default, + peer based authentication will be used for users connecting + via the Unix socket, and md5 password authentication will be + used for users connecting via TCP. Any added rules will be + inserted above the default rules. If you'd like to replace the + default rules entirely, you can use <function>lib.mkForce</function> in your + module. ''; }; @@ -208,10 +217,28 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = "Additional text to be appended to <filename>postgresql.conf</filename>."; + settings = mkOption { + type = with types; attrsOf (oneOf [ bool float int str ]); + default = {}; + description = '' + PostgreSQL configuration. Refer to + <link xlink:href="https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE"/> + for an overview of <literal>postgresql.conf</literal>. + + <note><para> + String values will automatically be enclosed in single quotes. Single quotes will be + escaped with two single quotes as described by the upstream documentation linked above. + </para></note> + ''; + example = literalExample '' + { + log_connections = true; + log_statement = "all"; + logging_collector = true + log_disconnections = true + log_destination = lib.mkForce "syslog"; + } + ''; }; recoveryConfig = mkOption { @@ -221,14 +248,15 @@ in Contents of the <filename>recovery.conf</filename> file. ''; }; + superUser = mkOption { type = types.str; - default= if versionAtLeast config.system.stateVersion "17.09" then "postgres" else "root"; + default = "postgres"; internal = true; + readOnly = true; description = '' - NixOS traditionally used 'root' as superuser, most other distros use 'postgres'. - From 17.09 we also try to follow this standard. Internal since changing this value - would lead to breakage while setting up databases. + PostgreSQL superuser account to use for various operations. Internal since changing + this value would lead to breakage while setting up databases. ''; }; }; @@ -240,6 +268,16 @@ in config = mkIf cfg.enable { + services.postgresql.settings = + { + hba_file = "${pkgs.writeText "pg_hba.conf" cfg.authentication}"; + ident_file = "${pkgs.writeText "pg_ident.conf" cfg.identMap}"; + log_destination = "stderr"; + log_line_prefix = cfg.logLinePrefix; + listen_addresses = if cfg.enableTCPIP then "*" else "localhost"; + port = cfg.port; + }; + services.postgresql.package = # Note: when changing the default, make it conditional on # ‘system.stateVersion’ to maintain compatibility with existing @@ -249,10 +287,7 @@ in else if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql_9_5 else throw "postgresql_9_4 was removed, please upgrade your postgresql version."); - services.postgresql.dataDir = - mkDefault (if versionAtLeast config.system.stateVersion "17.09" - then "/var/lib/postgresql/${cfg.package.psqlSchema}" - else "/var/db/postgresql"); + services.postgresql.dataDir = mkDefault "/var/lib/postgresql/${cfg.package.psqlSchema}"; services.postgresql.authentication = mkAfter '' @@ -291,59 +326,28 @@ in preStart = '' - # Create data directory. if ! test -e ${cfg.dataDir}/PG_VERSION; then - mkdir -m 0700 -p ${cfg.dataDir} + # Cleanup the data directory. rm -f ${cfg.dataDir}/*.conf - chown -R postgres:postgres ${cfg.dataDir} - fi - ''; # */ - script = - '' - # Initialise the database. - if ! test -e ${cfg.dataDir}/PG_VERSION; then + # Initialise the database. initdb -U ${cfg.superUser} ${concatStringsSep " " cfg.initdbArgs} + # See postStart! touch "${cfg.dataDir}/.first_startup" fi + ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf" ${optionalString (cfg.recoveryConfig != null) '' ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \ "${cfg.dataDir}/recovery.conf" ''} - ${optionalString (!groupAccessAvailable) '' - # postgresql pre 11.0 doesn't start if state directory mode is group accessible - chmod 0700 "${cfg.dataDir}" - ''} - - exec postgres ''; - serviceConfig = - { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - User = "postgres"; - Group = "postgres"; - PermissionsStartOnly = true; - RuntimeDirectory = "postgresql"; - Type = if versionAtLeast cfg.package.version "9.6" - then "notify" - else "simple"; - - # Shut down Postgres using SIGINT ("Fast Shutdown mode"). See - # http://www.postgresql.org/docs/current/static/server-shutdown.html - KillSignal = "SIGINT"; - KillMode = "mixed"; - - # Give Postgres a decent amount of time to clean up after - # receiving systemd's SIGINT. - TimeoutSec = 120; - }; - # Wait for PostgreSQL to be ready to accept connections. postStart = '' - PSQL="${pkgs.utillinux}/bin/runuser -u ${cfg.superUser} -- psql --port=${toString cfg.port}" + PSQL="psql --port=${toString cfg.port}" while ! $PSQL -d postgres -c "" 2> /dev/null; do if ! kill -0 "$MAINPID"; then exit 1; fi @@ -369,6 +373,32 @@ in '') cfg.ensureUsers} ''; + serviceConfig = mkMerge [ + { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + User = "postgres"; + Group = "postgres"; + RuntimeDirectory = "postgresql"; + Type = if versionAtLeast cfg.package.version "9.6" + then "notify" + else "simple"; + + # Shut down Postgres using SIGINT ("Fast Shutdown mode"). See + # http://www.postgresql.org/docs/current/static/server-shutdown.html + KillSignal = "SIGINT"; + KillMode = "mixed"; + + # Give Postgres a decent amount of time to clean up after + # receiving systemd's SIGINT. + TimeoutSec = 120; + + ExecStart = "${postgresql}/bin/postgres"; + } + (mkIf (cfg.dataDir == "/var/lib/postgresql/${cfg.package.psqlSchema}") { + StateDirectory = "postgresql postgresql/${cfg.package.psqlSchema}"; + StateDirectoryMode = if groupAccessAvailable then "0750" else "0700"; + }) + ]; + unitConfig.RequiresMountsFor = "${cfg.dataDir}"; }; diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index 4d2554786a3..1b90e59b166 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -4,31 +4,16 @@ with lib; let cfg = config.services.redis; - redisBool = b: if b then "yes" else "no"; - condOption = name: value: if value != null then "${name} ${toString value}" else ""; - - redisConfig = pkgs.writeText "redis.conf" '' - port ${toString cfg.port} - ${condOption "bind" cfg.bind} - ${condOption "unixsocket" cfg.unixSocket} - daemonize no - supervised systemd - loglevel ${cfg.logLevel} - logfile ${cfg.logfile} - syslog-enabled ${redisBool cfg.syslog} - databases ${toString cfg.databases} - ${concatMapStrings (d: "save ${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}\n") cfg.save} - dbfilename dump.rdb - dir /var/lib/redis - ${if cfg.slaveOf != null then "slaveof ${cfg.slaveOf.ip} ${toString cfg.slaveOf.port}" else ""} - ${condOption "masterauth" cfg.masterAuth} - ${condOption "requirepass" cfg.requirePass} - appendOnly ${redisBool cfg.appendOnly} - appendfsync ${cfg.appendFsync} - slowlog-log-slower-than ${toString cfg.slowLogLogSlowerThan} - slowlog-max-len ${toString cfg.slowLogMaxLen} - ${cfg.extraConfig} - ''; + + mkValueString = value: + if value == true then "yes" + else if value == false then "no" + else generators.mkValueStringDefault { } value; + + redisConfig = pkgs.writeText "redis.conf" (generators.toKeyValue { + listsAsDuplicateKeys = true; + mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " "; + } cfg.settings); in { imports = [ @@ -37,6 +22,7 @@ in (mkRemovedOptionModule [ "services" "redis" "dbFilename" ] "The redis module now uses /var/lib/redis/dump.rdb as database dump location.") (mkRemovedOptionModule [ "services" "redis" "appendOnlyFilename" ] "This option was never used.") (mkRemovedOptionModule [ "services" "redis" "pidFile" ] "This option was removed.") + (mkRemovedOptionModule [ "services" "redis" "extraConfig" ] "Use services.redis.settings instead.") ]; ###### interface @@ -87,9 +73,12 @@ in bind = mkOption { type = with types; nullOr str; - default = null; # All interfaces - description = "The IP interface to bind to."; - example = "127.0.0.1"; + default = "127.0.0.1"; + description = '' + The IP interface to bind to. + <literal>null</literal> means "all interfaces". + ''; + example = "192.0.2.1"; }; unixSocket = mkOption { @@ -205,10 +194,20 @@ in description = "Maximum number of items to keep in slow log."; }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = "Extra configuration options for redis.conf."; + settings = mkOption { + type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); + default = {}; + description = '' + Redis configuration. Refer to + <link xlink:href="https://redis.io/topics/config"/> + for details on supported values. + ''; + example = literalExample '' + { + unixsocketperm = "700"; + loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ]; + } + ''; }; }; @@ -239,6 +238,30 @@ in environment.systemPackages = [ cfg.package ]; + services.redis.settings = mkMerge [ + { + port = cfg.port; + daemonize = false; + supervised = "systemd"; + loglevel = cfg.logLevel; + logfile = cfg.logfile; + syslog-enabled = cfg.syslog; + databases = cfg.databases; + save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") cfg.save; + dbfilename = "dump.rdb"; + dir = "/var/lib/redis"; + appendOnly = cfg.appendOnly; + appendfsync = cfg.appendFsync; + slowlog-log-slower-than = cfg.slowLogLogSlowerThan; + slowlog-max-len = cfg.slowLogMaxLen; + } + (mkIf (cfg.bind != null) { bind = cfg.bind; }) + (mkIf (cfg.unixSocket != null) { unixsocket = cfg.unixSocket; }) + (mkIf (cfg.slaveOf != null) { slaveof = "${cfg.slaveOf.ip} ${cfg.slaveOf.port}"; }) + (mkIf (cfg.masterAuth != null) { masterauth = cfg.masterAuth; }) + (mkIf (cfg.requirePass != null) { requirepass = cfg.requirePass; }) + ]; + systemd.services.redis = { description = "Redis Server"; diff --git a/nixos/modules/services/databases/riak-cs.nix b/nixos/modules/services/databases/riak-cs.nix deleted file mode 100644 index 2cb204f729a..00000000000 --- a/nixos/modules/services/databases/riak-cs.nix +++ /dev/null @@ -1,202 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.riak-cs; - -in - -{ - - ###### interface - - options = { - - services.riak-cs = { - - enable = mkEnableOption "riak-cs"; - - package = mkOption { - type = types.package; - default = pkgs.riak-cs; - defaultText = "pkgs.riak-cs"; - example = literalExample "pkgs.riak-cs"; - description = '' - Riak package to use. - ''; - }; - - nodeName = mkOption { - type = types.str; - default = "riak-cs@127.0.0.1"; - description = '' - Name of the Erlang node. - ''; - }; - - anonymousUserCreation = mkOption { - type = types.bool; - default = false; - description = '' - Anonymous user creation. - ''; - }; - - riakHost = mkOption { - type = types.str; - default = "127.0.0.1:8087"; - description = '' - Name of riak hosting service. - ''; - }; - - listener = mkOption { - type = types.str; - default = "127.0.0.1:8080"; - description = '' - Name of Riak CS listening service. - ''; - }; - - stanchionHost = mkOption { - type = types.str; - default = "127.0.0.1:8085"; - description = '' - Name of stanchion hosting service. - ''; - }; - - stanchionSsl = mkOption { - type = types.bool; - default = true; - description = '' - Tell stanchion to use SSL. - ''; - }; - - distributedCookie = mkOption { - type = types.str; - default = "riak"; - description = '' - Cookie for distributed node communication. All nodes in the - same cluster should use the same cookie or they will not be able to - communicate. - ''; - }; - - dataDir = mkOption { - type = types.path; - default = "/var/db/riak-cs"; - description = '' - Data directory for Riak CS. - ''; - }; - - logDir = mkOption { - type = types.path; - default = "/var/log/riak-cs"; - description = '' - Log directory for Riak CS. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be appended to <filename>riak-cs.conf</filename>. - ''; - }; - - extraAdvancedConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be appended to <filename>advanced.config</filename>. - ''; - }; - }; - - }; - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ cfg.package ]; - environment.etc."riak-cs/riak-cs.conf".text = '' - nodename = ${cfg.nodeName} - distributed_cookie = ${cfg.distributedCookie} - - platform_log_dir = ${cfg.logDir} - - riak_host = ${cfg.riakHost} - listener = ${cfg.listener} - stanchion_host = ${cfg.stanchionHost} - - anonymous_user_creation = ${if cfg.anonymousUserCreation then "on" else "off"} - - ${cfg.extraConfig} - ''; - - environment.etc."riak-cs/advanced.config".text = '' - ${cfg.extraAdvancedConfig} - ''; - - users.users.riak-cs = { - name = "riak-cs"; - uid = config.ids.uids.riak-cs; - group = "riak"; - description = "Riak CS server user"; - }; - - systemd.services.riak-cs = { - description = "Riak CS Server"; - - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - path = [ - pkgs.utillinux # for `logger` - pkgs.bash - ]; - - environment.HOME = "${cfg.dataDir}"; - environment.RIAK_CS_DATA_DIR = "${cfg.dataDir}"; - environment.RIAK_CS_LOG_DIR = "${cfg.logDir}"; - environment.RIAK_CS_ETC_DIR = "/etc/riak"; - - preStart = '' - if ! test -e ${cfg.logDir}; then - mkdir -m 0755 -p ${cfg.logDir} - chown -R riak-cs ${cfg.logDir} - fi - - if ! test -e ${cfg.dataDir}; then - mkdir -m 0700 -p ${cfg.dataDir} - chown -R riak-cs ${cfg.dataDir} - fi - ''; - - serviceConfig = { - ExecStart = "${cfg.package}/bin/riak-cs console"; - ExecStop = "${cfg.package}/bin/riak-cs stop"; - StandardInput = "tty"; - User = "riak-cs"; - Group = "riak-cs"; - PermissionsStartOnly = true; - # Give Riak a decent amount of time to clean up. - TimeoutStopSec = 120; - LimitNOFILE = 65536; - }; - - unitConfig.RequiresMountsFor = [ - "${cfg.dataDir}" - "${cfg.logDir}" - "/etc/riak" - ]; - }; - }; -} diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix index 885215209bd..657eeea87bf 100644 --- a/nixos/modules/services/databases/riak.nix +++ b/nixos/modules/services/databases/riak.nix @@ -118,7 +118,7 @@ in after = [ "network.target" ]; path = [ - pkgs.utillinux # for `logger` + pkgs.util-linux # for `logger` pkgs.bash ]; diff --git a/nixos/modules/services/databases/stanchion.nix b/nixos/modules/services/databases/stanchion.nix deleted file mode 100644 index 97e55bc70c4..00000000000 --- a/nixos/modules/services/databases/stanchion.nix +++ /dev/null @@ -1,194 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.stanchion; - -in - -{ - - ###### interface - - options = { - - services.stanchion = { - - enable = mkEnableOption "stanchion"; - - package = mkOption { - type = types.package; - default = pkgs.stanchion; - defaultText = "pkgs.stanchion"; - example = literalExample "pkgs.stanchion"; - description = '' - Stanchion package to use. - ''; - }; - - nodeName = mkOption { - type = types.str; - default = "stanchion@127.0.0.1"; - description = '' - Name of the Erlang node. - ''; - }; - - adminKey = mkOption { - type = types.str; - default = ""; - description = '' - Name of admin user. - ''; - }; - - adminSecret = mkOption { - type = types.str; - default = ""; - description = '' - Name of admin secret - ''; - }; - - riakHost = mkOption { - type = types.str; - default = "127.0.0.1:8087"; - description = '' - Name of riak hosting service. - ''; - }; - - listener = mkOption { - type = types.str; - default = "127.0.0.1:8085"; - description = '' - Name of Riak CS listening service. - ''; - }; - - stanchionHost = mkOption { - type = types.str; - default = "127.0.0.1:8085"; - description = '' - Name of stanchion hosting service. - ''; - }; - - distributedCookie = mkOption { - type = types.str; - default = "riak"; - description = '' - Cookie for distributed node communication. All nodes in the - same cluster should use the same cookie or they will not be able to - communicate. - ''; - }; - - dataDir = mkOption { - type = types.path; - default = "/var/db/stanchion"; - description = '' - Data directory for Stanchion. - ''; - }; - - logDir = mkOption { - type = types.path; - default = "/var/log/stanchion"; - description = '' - Log directory for Stanchion. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be appended to <filename>stanchion.conf</filename>. - ''; - }; - }; - }; - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ cfg.package ]; - - environment.etc."stanchion/advanced.config".text = '' - [{stanchion, []}]. - ''; - - environment.etc."stanchion/stanchion.conf".text = '' - listener = ${cfg.listener} - - riak_host = ${cfg.riakHost} - - ${optionalString (cfg.adminKey == "") "#"} admin.key=${optionalString (cfg.adminKey != "") cfg.adminKey} - ${optionalString (cfg.adminSecret == "") "#"} admin.secret=${optionalString (cfg.adminSecret != "") cfg.adminSecret} - - platform_bin_dir = ${pkgs.stanchion}/bin - platform_data_dir = ${cfg.dataDir} - platform_etc_dir = /etc/stanchion - platform_lib_dir = ${pkgs.stanchion}/lib - platform_log_dir = ${cfg.logDir} - - nodename = ${cfg.nodeName} - - distributed_cookie = ${cfg.distributedCookie} - - ${cfg.extraConfig} - ''; - - users.users.stanchion = { - name = "stanchion"; - uid = config.ids.uids.stanchion; - group = "stanchion"; - description = "Stanchion server user"; - }; - - users.groups.stanchion.gid = config.ids.gids.stanchion; - - systemd.tmpfiles.rules = [ - "d '${cfg.logDir}' - stanchion stanchion --" - "d '${cfg.dataDir}' 0700 stanchion stanchion --" - ]; - - systemd.services.stanchion = { - description = "Stanchion Server"; - - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - path = [ - pkgs.utillinux # for `logger` - pkgs.bash - ]; - - environment.HOME = "${cfg.dataDir}"; - environment.STANCHION_DATA_DIR = "${cfg.dataDir}"; - environment.STANCHION_LOG_DIR = "${cfg.logDir}"; - environment.STANCHION_ETC_DIR = "/etc/stanchion"; - - serviceConfig = { - ExecStart = "${cfg.package}/bin/stanchion console"; - ExecStop = "${cfg.package}/bin/stanchion stop"; - StandardInput = "tty"; - User = "stanchion"; - Group = "stanchion"; - # Give Stanchion a decent amount of time to clean up. - TimeoutStopSec = 120; - LimitNOFILE = 65536; - }; - - unitConfig.RequiresMountsFor = [ - "${cfg.dataDir}" - "${cfg.logDir}" - "/etc/stanchion" - ]; - }; - }; -} diff --git a/nixos/modules/services/databases/victoriametrics.nix b/nixos/modules/services/databases/victoriametrics.nix index cb6bf8508fb..5b09115bb2f 100644 --- a/nixos/modules/services/databases/victoriametrics.nix +++ b/nixos/modules/services/databases/victoriametrics.nix @@ -40,17 +40,17 @@ let cfg = config.services.victoriametrics; in systemd.services.victoriametrics = { description = "VictoriaMetrics time series database"; after = [ "network.target" ]; + startLimitBurst = 5; serviceConfig = { Restart = "on-failure"; RestartSec = 1; - StartLimitBurst = 5; StateDirectory = "victoriametrics"; DynamicUser = true; ExecStart = '' ${cfg.package}/bin/victoria-metrics \ -storageDataPath=/var/lib/victoriametrics \ - -httpListenAddr ${cfg.listenAddress} - -retentionPeriod ${toString cfg.retentionPeriod} + -httpListenAddr ${cfg.listenAddress} \ + -retentionPeriod ${toString cfg.retentionPeriod} \ ${lib.escapeShellArgs cfg.extraOptions} ''; }; |