212 lines
6.5 KiB
Nix
212 lines
6.5 KiB
Nix
{
|
|
pkgs,
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
mkManagePy = pkgs.callPackage ./utils/mkManagePy.nix { };
|
|
mkStaticAssets =
|
|
{ app, managePy, mainModule }:
|
|
pkgs.runCommand "django-${app}-static" {} ''
|
|
mkdir -p "$out/static"
|
|
STATIC_ROOT="\"$out/static\"" \
|
|
DJANGO_SETTINGS_MODULE="${mainModule}_settings.mock" \
|
|
${lib.getExe managePy} collectstatic --noinput
|
|
'';
|
|
|
|
mkSettingsModule =
|
|
{
|
|
runtimeSettings,
|
|
settings,
|
|
secrets,
|
|
mainModule,
|
|
extraConfig,
|
|
p,
|
|
}:
|
|
p.callPackage ./utils/mkSettingsModule.nix {
|
|
inherit
|
|
runtimeSettings
|
|
settings
|
|
secrets
|
|
mainModule
|
|
extraConfig
|
|
;
|
|
};
|
|
|
|
djangoAppModule = lib.types.submodule (
|
|
{ config, name, ... }:
|
|
{
|
|
options = {
|
|
enable = lib.mkEnableOption (lib.mdDoc "Enable django application") // {
|
|
default = true;
|
|
};
|
|
src = lib.mkOption { type = lib.types.path; };
|
|
sourceRoot = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
example = "myproject/";
|
|
description = "Directory in the source directory to find the django app (must point to basedir of manage.py)";
|
|
};
|
|
mainModule = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Name of the django application";
|
|
default = name;
|
|
defaultText = lib.literalMD "Defaults to attribute name in djangoAppModule.";
|
|
};
|
|
settings = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
freeformType = with lib.types; attrsOf anything;
|
|
options = { };
|
|
};
|
|
description = ''
|
|
Settings to pass to django.
|
|
'';
|
|
example = {
|
|
DATABASES = {
|
|
"default" = {
|
|
"ENGINE" = "django.db.backends.sqlite3";
|
|
"NAME" = "/var/lib/django-myproject/db.sqlite3";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
runtimeSettings = lib.mkOption {
|
|
type = with lib.types; attrsOf str;
|
|
default= {};
|
|
description = ''
|
|
Settings to pass to only at runtime.
|
|
|
|
Useful for settings that depends on the python package.
|
|
'';
|
|
};
|
|
secrets = lib.mkOption {
|
|
type = lib.types.attrsOf lib.types.path;
|
|
default = { };
|
|
example = {
|
|
SECRET_KEY = "/etc/django-secret.json";
|
|
DATABASES = "/etc/django-db-config.json";
|
|
};
|
|
description = ''
|
|
Secrets to pass to django through a file. The content of the file will be loaded as json
|
|
'';
|
|
};
|
|
extraConfig = lib.mkOption {
|
|
type = lib.types.lines;
|
|
default = "";
|
|
description = "Extra python code to append at the end of the production settings module.";
|
|
};
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 51666;
|
|
description = "Port for the gunicorn process";
|
|
};
|
|
processes = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 2;
|
|
};
|
|
threads = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 2;
|
|
};
|
|
staticAssets = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = mkStaticAssets {
|
|
inherit (config) mainModule managePy;
|
|
app = name;
|
|
};
|
|
description = "Satic assets to be served directly by nginx. The default value should be good enough in most cases.";
|
|
};
|
|
manageFilePath = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "${config.sourceRoot}manage.py";
|
|
description = "Path relative to src pointing to manage.py file";
|
|
};
|
|
pythonPackage = lib.mkOption {
|
|
internal = true;
|
|
type = lib.types.path;
|
|
description = "Final python environment containing everything including the settings module";
|
|
default = pkgs.python3.withPackages (
|
|
p:
|
|
[
|
|
p.django
|
|
p.gunicorn
|
|
(mkSettingsModule {
|
|
inherit (config)
|
|
secrets
|
|
settings
|
|
mainModule
|
|
extraConfig
|
|
;
|
|
runtimeSettings = builtins.attrNames config.runtimeSettings;
|
|
inherit p;
|
|
})
|
|
]
|
|
++ config.extraPackages p
|
|
);
|
|
};
|
|
extraPackages = lib.mkOption {
|
|
type = lib.types.functionTo (lib.types.listOf lib.types.package);
|
|
default = p: [ ];
|
|
defaultText = lib.literalExpression "p: []";
|
|
description = ''
|
|
Extra Python packages available to django app. The
|
|
value must be a function which receives the attrset defined
|
|
in {var}`python3Packages` as the sole argument.
|
|
'';
|
|
};
|
|
managePy = lib.mkOption {
|
|
internal = true;
|
|
type = lib.types.package;
|
|
default = mkManagePy {
|
|
inherit (config) pythonPackage manageFilePath src;
|
|
app = name;
|
|
};
|
|
description = "Manage py script";
|
|
};
|
|
};
|
|
config = {
|
|
runtimeSettings.STATIC_ROOT = "";#config.staticAssets;
|
|
};
|
|
}
|
|
);
|
|
in
|
|
{
|
|
options = {
|
|
services.django = lib.mkOption {
|
|
type = lib.types.attrsOf djangoAppModule;
|
|
description = "Attribute set of djanfo app modules";
|
|
};
|
|
};
|
|
config.systemd.services = lib.mapAttrs' (
|
|
app: cfg:
|
|
lib.nameValuePair "django-${app}" (
|
|
lib.mkIf cfg.enable {
|
|
description = "${app} django service";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.target" ];
|
|
wants = [ "network.target" ];
|
|
serviceConfig = rec {
|
|
Type = "notify";
|
|
#NotifyAllow = "exec";
|
|
DynamicUser = true;
|
|
|
|
LoadCredential = lib.mapAttrsToList (k: v: "${k}:${v}") cfg.secrets;
|
|
StateDirectory = "django-${app}";
|
|
};
|
|
environment = {
|
|
DJANGO_SETTINGS_MODULE = "${cfg.mainModule}_settings.prod";
|
|
} // (lib.mapAttrs (_: v: builtins.toJSON v) cfg.runtimeSettings);
|
|
script = ''
|
|
${lib.getExe cfg.managePy} migrate
|
|
exec ${cfg.pythonPackage}/bin/gunicorn ${cfg.mainModule}.wsgi \
|
|
--pythonpath ${cfg.src}/${cfg.sourceRoot} \
|
|
-b 127.0.0.1:${builtins.toString cfg.port} \
|
|
--workers=${builtins.toString cfg.processes} \
|
|
--threads=${builtins.toString cfg.threads}
|
|
'';
|
|
}
|
|
)
|
|
) config.services.django;
|
|
}
|