mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-20 09:00:41 +03:00

This avoids restarting the postgresql server, when only ensureDatabases or ensureUsers have been changed. It will also allow to properly wait for recovery to finish later. To wait for "postgresql is ready" in other services, we now provide a postgresql.target. Resolves #400018 Co-authored-by: Marcel <me@m4rc3l.de>
404 lines
10 KiB
Nix
404 lines
10 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
inherit (lib)
|
|
mkDefault
|
|
mkEnableOption
|
|
mkPackageOption
|
|
mkForce
|
|
mkIf
|
|
mkMerge
|
|
mkOption
|
|
types
|
|
;
|
|
inherit (lib)
|
|
concatStringsSep
|
|
literalExpression
|
|
mapAttrsToList
|
|
optional
|
|
optionalString
|
|
;
|
|
|
|
cfg = config.services.moodle;
|
|
fpm = config.services.phpfpm.pools.moodle;
|
|
|
|
user = "moodle";
|
|
group = config.services.httpd.group;
|
|
stateDir = "/var/lib/moodle";
|
|
|
|
moodleConfig = pkgs.writeText "config.php" ''
|
|
<?php // Moodle configuration file
|
|
|
|
unset($CFG);
|
|
global $CFG;
|
|
$CFG = new stdClass();
|
|
|
|
$CFG->dbtype = '${
|
|
{
|
|
mysql = "mariadb";
|
|
pgsql = "pgsql";
|
|
}
|
|
.${cfg.database.type}
|
|
}';
|
|
$CFG->dblibrary = 'native';
|
|
$CFG->dbhost = '${cfg.database.host}';
|
|
$CFG->dbname = '${cfg.database.name}';
|
|
$CFG->dbuser = '${cfg.database.user}';
|
|
${optionalString (
|
|
cfg.database.passwordFile != null
|
|
) "$CFG->dbpass = file_get_contents('${cfg.database.passwordFile}');"}
|
|
$CFG->prefix = 'mdl_';
|
|
$CFG->dboptions = array (
|
|
'dbpersist' => 0,
|
|
'dbport' => '${toString cfg.database.port}',
|
|
${optionalString (cfg.database.socket != null) "'dbsocket' => '${cfg.database.socket}',"}
|
|
'dbcollation' => 'utf8mb4_unicode_ci',
|
|
);
|
|
|
|
$CFG->wwwroot = '${
|
|
if cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL then
|
|
"https"
|
|
else
|
|
"http"
|
|
}://${cfg.virtualHost.hostName}';
|
|
$CFG->dataroot = '${stateDir}';
|
|
$CFG->admin = 'admin';
|
|
|
|
$CFG->directorypermissions = 02777;
|
|
$CFG->disableupdateautodeploy = true;
|
|
|
|
$CFG->pathtogs = '${pkgs.ghostscript}/bin/gs';
|
|
$CFG->pathtophp = '${phpExt}/bin/php';
|
|
$CFG->pathtodu = '${pkgs.coreutils}/bin/du';
|
|
$CFG->aspellpath = '${pkgs.aspell}/bin/aspell';
|
|
$CFG->pathtodot = '${pkgs.graphviz}/bin/dot';
|
|
|
|
${cfg.extraConfig}
|
|
|
|
require_once('${cfg.package}/share/moodle/lib/setup.php');
|
|
|
|
// There is no php closing tag in this file,
|
|
// it is intentional because it prevents trailing whitespace problems!
|
|
'';
|
|
|
|
mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql";
|
|
pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql";
|
|
|
|
phpExt = pkgs.php83.buildEnv {
|
|
extensions =
|
|
{ all, ... }:
|
|
with all;
|
|
[
|
|
iconv
|
|
mbstring
|
|
curl
|
|
openssl
|
|
tokenizer
|
|
soap
|
|
ctype
|
|
zip
|
|
gd
|
|
simplexml
|
|
dom
|
|
intl
|
|
sqlite3
|
|
pgsql
|
|
pdo_sqlite
|
|
pdo_pgsql
|
|
pdo_odbc
|
|
pdo_mysql
|
|
pdo
|
|
mysqli
|
|
session
|
|
zlib
|
|
xmlreader
|
|
fileinfo
|
|
filter
|
|
opcache
|
|
exif
|
|
sodium
|
|
];
|
|
extraConfig = "max_input_vars = 5000";
|
|
};
|
|
in
|
|
{
|
|
# interface
|
|
options.services.moodle = {
|
|
enable = mkEnableOption "Moodle web application";
|
|
|
|
package = mkPackageOption pkgs "moodle" { };
|
|
|
|
initialPassword = mkOption {
|
|
type = types.str;
|
|
example = "correcthorsebatterystaple";
|
|
description = ''
|
|
Specifies the initial password for the admin, i.e. the password assigned if the user does not already exist.
|
|
The password specified here is world-readable in the Nix store, so it should be changed promptly.
|
|
'';
|
|
};
|
|
|
|
database = {
|
|
type = mkOption {
|
|
type = types.enum [
|
|
"mysql"
|
|
"pgsql"
|
|
];
|
|
default = "mysql";
|
|
description = "Database engine to use.";
|
|
};
|
|
|
|
host = mkOption {
|
|
type = types.str;
|
|
default = "localhost";
|
|
description = "Database host address.";
|
|
};
|
|
|
|
port = mkOption {
|
|
type = types.port;
|
|
description = "Database host port.";
|
|
default =
|
|
{
|
|
mysql = 3306;
|
|
pgsql = 5432;
|
|
}
|
|
.${cfg.database.type};
|
|
defaultText = literalExpression "3306";
|
|
};
|
|
|
|
name = mkOption {
|
|
type = types.str;
|
|
default = "moodle";
|
|
description = "Database name.";
|
|
};
|
|
|
|
user = mkOption {
|
|
type = types.str;
|
|
default = "moodle";
|
|
description = "Database user.";
|
|
};
|
|
|
|
passwordFile = mkOption {
|
|
type = types.nullOr types.path;
|
|
default = null;
|
|
example = "/run/keys/moodle-dbpassword";
|
|
description = ''
|
|
A file containing the password corresponding to
|
|
{option}`database.user`.
|
|
'';
|
|
};
|
|
|
|
socket = mkOption {
|
|
type = types.nullOr types.path;
|
|
default =
|
|
if mysqlLocal then
|
|
"/run/mysqld/mysqld.sock"
|
|
else if pgsqlLocal then
|
|
"/run/postgresql"
|
|
else
|
|
null;
|
|
defaultText = literalExpression "/run/mysqld/mysqld.sock";
|
|
description = "Path to the unix socket file to use for authentication.";
|
|
};
|
|
|
|
createLocally = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = "Create the database and database user locally.";
|
|
};
|
|
};
|
|
|
|
virtualHost = mkOption {
|
|
type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
|
|
example = literalExpression ''
|
|
{
|
|
hostName = "moodle.example.org";
|
|
adminAddr = "webmaster@example.org";
|
|
forceSSL = true;
|
|
enableACME = true;
|
|
}
|
|
'';
|
|
description = ''
|
|
Apache configuration can be done by adapting {option}`services.httpd.virtualHosts`.
|
|
See [](#opt-services.httpd.virtualHosts) for further information.
|
|
'';
|
|
};
|
|
|
|
poolConfig = mkOption {
|
|
type =
|
|
with types;
|
|
attrsOf (oneOf [
|
|
str
|
|
int
|
|
bool
|
|
]);
|
|
default = {
|
|
"pm" = "dynamic";
|
|
"pm.max_children" = 32;
|
|
"pm.start_servers" = 2;
|
|
"pm.min_spare_servers" = 2;
|
|
"pm.max_spare_servers" = 4;
|
|
"pm.max_requests" = 500;
|
|
};
|
|
description = ''
|
|
Options for the Moodle PHP pool. See the documentation on `php-fpm.conf`
|
|
for details on configuration directives.
|
|
'';
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
type = types.lines;
|
|
default = "";
|
|
description = ''
|
|
Any additional text to be appended to the config.php
|
|
configuration file. This is a PHP script. For configuration
|
|
details, see <https://docs.moodle.org/37/en/Configuration_file>.
|
|
'';
|
|
example = ''
|
|
$CFG->disableupdatenotifications = true;
|
|
'';
|
|
};
|
|
};
|
|
|
|
# implementation
|
|
config = mkIf cfg.enable {
|
|
|
|
assertions = [
|
|
{
|
|
assertion =
|
|
cfg.database.createLocally -> cfg.database.user == user && cfg.database.user == cfg.database.name;
|
|
message = "services.moodle.database.user must be set to ${user} if services.moodle.database.createLocally is set true";
|
|
}
|
|
{
|
|
assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
|
|
message = "a password cannot be specified if services.moodle.database.createLocally is set to true";
|
|
}
|
|
];
|
|
|
|
services.mysql = mkIf mysqlLocal {
|
|
enable = true;
|
|
package = mkDefault pkgs.mariadb;
|
|
ensureDatabases = [ cfg.database.name ];
|
|
ensureUsers = [
|
|
{
|
|
name = cfg.database.user;
|
|
ensurePermissions = {
|
|
"${cfg.database.name}.*" =
|
|
"SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER";
|
|
};
|
|
}
|
|
];
|
|
};
|
|
|
|
services.postgresql = mkIf pgsqlLocal {
|
|
enable = true;
|
|
ensureDatabases = [ cfg.database.name ];
|
|
ensureUsers = [
|
|
{
|
|
name = cfg.database.user;
|
|
ensureDBOwnership = true;
|
|
}
|
|
];
|
|
};
|
|
|
|
services.phpfpm.pools.moodle = {
|
|
inherit user group;
|
|
phpPackage = phpExt;
|
|
phpEnv.MOODLE_CONFIG = "${moodleConfig}";
|
|
phpOptions = ''
|
|
zend_extension = opcache.so
|
|
opcache.enable = 1
|
|
max_input_vars = 5000
|
|
'';
|
|
settings = {
|
|
"listen.owner" = config.services.httpd.user;
|
|
"listen.group" = config.services.httpd.group;
|
|
} // cfg.poolConfig;
|
|
};
|
|
|
|
services.httpd = {
|
|
enable = true;
|
|
adminAddr = mkDefault cfg.virtualHost.adminAddr;
|
|
extraModules = [ "proxy_fcgi" ];
|
|
virtualHosts.${cfg.virtualHost.hostName} = mkMerge [
|
|
cfg.virtualHost
|
|
{
|
|
documentRoot = mkForce "${cfg.package}/share/moodle";
|
|
extraConfig = ''
|
|
<Directory "${cfg.package}/share/moodle">
|
|
<FilesMatch "\.php$">
|
|
<If "-f %{REQUEST_FILENAME}">
|
|
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
|
|
</If>
|
|
</FilesMatch>
|
|
Options -Indexes
|
|
DirectoryIndex index.php
|
|
</Directory>
|
|
'';
|
|
}
|
|
];
|
|
};
|
|
|
|
systemd.tmpfiles.settings."10-moodle".${stateDir}.d = {
|
|
inherit user group;
|
|
mode = "0750";
|
|
};
|
|
|
|
systemd.services.moodle-init = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
before = [ "phpfpm-moodle.service" ];
|
|
after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.target";
|
|
environment.MOODLE_CONFIG = moodleConfig;
|
|
script = ''
|
|
${phpExt}/bin/php ${cfg.package}/share/moodle/admin/cli/check_database_schema.php && rc=$? || rc=$?
|
|
|
|
[ "$rc" == 1 ] && ${phpExt}/bin/php ${cfg.package}/share/moodle/admin/cli/upgrade.php \
|
|
--non-interactive \
|
|
--allow-unstable
|
|
|
|
[ "$rc" == 2 ] && ${phpExt}/bin/php ${cfg.package}/share/moodle/admin/cli/install_database.php \
|
|
--agree-license \
|
|
--adminpass=${cfg.initialPassword}
|
|
|
|
true
|
|
'';
|
|
serviceConfig = {
|
|
User = user;
|
|
Group = group;
|
|
Type = "oneshot";
|
|
};
|
|
};
|
|
|
|
systemd.services.moodle-cron = {
|
|
description = "Moodle cron service";
|
|
after = [ "moodle-init.service" ];
|
|
environment.MOODLE_CONFIG = moodleConfig;
|
|
serviceConfig = {
|
|
User = user;
|
|
Group = group;
|
|
ExecStart = "${phpExt}/bin/php ${cfg.package}/share/moodle/admin/cli/cron.php";
|
|
};
|
|
};
|
|
|
|
systemd.timers.moodle-cron = {
|
|
description = "Moodle cron timer";
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnCalendar = "minutely";
|
|
};
|
|
};
|
|
|
|
systemd.services.httpd.after =
|
|
optional mysqlLocal "mysql.service"
|
|
++ optional pgsqlLocal "postgresql.target";
|
|
|
|
users.users.${user} = {
|
|
group = group;
|
|
isSystemUser = true;
|
|
};
|
|
};
|
|
}
|