mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-20 17:10:46 +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>
237 lines
6.3 KiB
Nix
237 lines
6.3 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
|
|
cfg = config.services.froide-govplan;
|
|
pythonFmt = pkgs.formats.pythonVars { };
|
|
settingsFile = pythonFmt.generate "extra_settings.py" cfg.settings;
|
|
|
|
pkg = cfg.package.overridePythonAttrs (old: {
|
|
postInstall =
|
|
old.postInstall
|
|
+ ''
|
|
ln -s ${settingsFile} $out/${pkg.python.sitePackages}/froide_govplan/project/extra_settings.py
|
|
'';
|
|
});
|
|
|
|
froide-govplan = pkgs.writeShellApplication {
|
|
name = "froide-govplan";
|
|
runtimeInputs = [ pkgs.coreutils ];
|
|
text = ''
|
|
SUDO="exec"
|
|
if [[ "$USER" != govplan ]]; then
|
|
SUDO="exec /run/wrappers/bin/sudo -u govplan"
|
|
fi
|
|
$SUDO env ${lib.getExe pkg} "$@"
|
|
'';
|
|
};
|
|
|
|
# Service hardening
|
|
defaultServiceConfig = {
|
|
# Secure the services
|
|
ReadWritePaths = [ cfg.dataDir ];
|
|
CacheDirectory = "froide-govplan";
|
|
CapabilityBoundingSet = "";
|
|
# ProtectClock adds DeviceAllow=char-rtc r
|
|
DeviceAllow = "";
|
|
LockPersonality = true;
|
|
MemoryDenyWriteExecute = true;
|
|
NoNewPrivileges = true;
|
|
PrivateDevices = true;
|
|
PrivateMounts = true;
|
|
PrivateTmp = true;
|
|
PrivateUsers = true;
|
|
ProtectClock = true;
|
|
ProtectHome = true;
|
|
ProtectHostname = true;
|
|
ProtectSystem = "strict";
|
|
ProtectControlGroups = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectKernelModules = true;
|
|
ProtectKernelTunables = true;
|
|
ProtectProc = "invisible";
|
|
ProcSubset = "pid";
|
|
RestrictAddressFamilies = [
|
|
"AF_UNIX"
|
|
"AF_INET"
|
|
"AF_INET6"
|
|
];
|
|
RestrictNamespaces = true;
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
SystemCallArchitectures = "native";
|
|
SystemCallFilter = [
|
|
"@system-service"
|
|
"~@privileged @setuid @keyring"
|
|
];
|
|
UMask = "0066";
|
|
};
|
|
|
|
in
|
|
{
|
|
options.services.froide-govplan = {
|
|
|
|
enable = lib.mkEnableOption "Gouvernment planer web app Govplan";
|
|
|
|
package = lib.mkPackageOption pkgs "froide-govplan" { };
|
|
|
|
hostName = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "localhost";
|
|
description = "FQDN for the froide-govplan instance.";
|
|
};
|
|
|
|
dataDir = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/var/lib/froide-govplan";
|
|
description = "Directory to store the Froide-Govplan server data.";
|
|
};
|
|
|
|
secretKeyFile = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default = null;
|
|
description = ''
|
|
Path to a file containing the secret key.
|
|
'';
|
|
};
|
|
|
|
settings = lib.mkOption {
|
|
description = ''
|
|
Configuration options to set in `extra_settings.py`.
|
|
'';
|
|
|
|
default = { };
|
|
|
|
type = lib.types.submodule {
|
|
freeformType = pythonFmt.type;
|
|
|
|
options = {
|
|
ALLOWED_HOSTS = lib.mkOption {
|
|
type = with lib.types; listOf str;
|
|
default = [ "*" ];
|
|
description = ''
|
|
A list of valid fully-qualified domain names (FQDNs) and/or IP
|
|
addresses that can be used to reach the Froide-Govplan service.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
|
|
services.froide-govplan = {
|
|
settings = {
|
|
STATIC_ROOT = "${cfg.dataDir}/static";
|
|
DEBUG = false;
|
|
DATABASES.default = {
|
|
ENGINE = "django.contrib.gis.db.backends.postgis";
|
|
NAME = "govplan";
|
|
USER = "govplan";
|
|
HOST = "/run/postgresql";
|
|
};
|
|
};
|
|
};
|
|
|
|
services.postgresql = {
|
|
enable = true;
|
|
ensureDatabases = [ "govplan" ];
|
|
ensureUsers = [
|
|
{
|
|
name = "govplan";
|
|
ensureDBOwnership = true;
|
|
}
|
|
];
|
|
extensions = ps: with ps; [ postgis ];
|
|
};
|
|
|
|
services.nginx = {
|
|
enable = lib.mkDefault true;
|
|
virtualHosts."${cfg.hostName}".locations = {
|
|
"/".extraConfig = "proxy_pass http://unix:/run/froide-govplan/froide-govplan.socket;";
|
|
"/static/".alias = "${cfg.dataDir}/static/";
|
|
};
|
|
proxyTimeout = lib.mkDefault "120s";
|
|
};
|
|
|
|
systemd = {
|
|
services = {
|
|
|
|
postgresql-setup.serviceConfig.ExecStartPost =
|
|
let
|
|
sqlFile = pkgs.writeText "froide-govplan-postgis-setup.sql" ''
|
|
CREATE EXTENSION IF NOT EXISTS postgis;
|
|
'';
|
|
in
|
|
[
|
|
''
|
|
${lib.getExe' config.services.postgresql.package "psql"} -d govplan -f "${sqlFile}"
|
|
''
|
|
];
|
|
|
|
froide-govplan = {
|
|
description = "Gouvernment planer Govplan";
|
|
serviceConfig = defaultServiceConfig // {
|
|
WorkingDirectory = cfg.dataDir;
|
|
StateDirectory = lib.mkIf (cfg.dataDir == "/var/lib/froide-govplan") "froide-govplan";
|
|
User = "govplan";
|
|
Group = "govplan";
|
|
};
|
|
after = [
|
|
"postgresql.target"
|
|
"network.target"
|
|
"systemd-tmpfiles-setup.service"
|
|
];
|
|
wantedBy = [ "multi-user.target" ];
|
|
environment =
|
|
{
|
|
PYTHONPATH = pkg.pythonPath;
|
|
GDAL_LIBRARY_PATH = "${pkgs.gdal}/lib/libgdal.so";
|
|
GEOS_LIBRARY_PATH = "${pkgs.geos}/lib/libgeos_c.so";
|
|
}
|
|
// lib.optionalAttrs (cfg.secretKeyFile != null) {
|
|
SECRET_KEY_FILE = cfg.secretKeyFile;
|
|
};
|
|
preStart = ''
|
|
# Auto-migrate on first run or if the package has changed
|
|
versionFile="${cfg.dataDir}/src-version"
|
|
version=$(cat "$versionFile" 2>/dev/null || echo 0)
|
|
|
|
if [[ $version != ${pkg.version} ]]; then
|
|
${lib.getExe pkg} migrate --no-input
|
|
${lib.getExe pkg} collectstatic --no-input --clear
|
|
echo ${pkg.version} > "$versionFile"
|
|
fi
|
|
'';
|
|
script = ''
|
|
${pkg.python.pkgs.uvicorn}/bin/uvicorn --uds /run/froide-govplan/froide-govplan.socket \
|
|
--app-dir ${pkg}/${pkg.python.sitePackages}/froide_govplan \
|
|
project.asgi:application
|
|
'';
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
systemd.tmpfiles.rules = [ "d /run/froide-govplan - govplan govplan - -" ];
|
|
|
|
environment.systemPackages = [ froide-govplan ];
|
|
|
|
users.users.govplan = {
|
|
home = "${cfg.dataDir}";
|
|
isSystemUser = true;
|
|
group = "govplan";
|
|
};
|
|
users.groups.govplan = { };
|
|
|
|
};
|
|
|
|
meta.maintainers = with lib.maintainers; [ onny ];
|
|
|
|
}
|