diff options
author | Mx Kookie <kookie@spacekookie.de> | 2020-10-31 19:35:09 +0100 |
---|---|---|
committer | Mx Kookie <kookie@spacekookie.de> | 2020-10-31 19:35:09 +0100 |
commit | c4625b175f8200f643fd6e11010932ea44c78433 (patch) | |
tree | bce3f89888c8ac3991fa5569a878a9eab6801ccc /infra/libkookie/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix | |
parent | 49f735974dd103039ddc4cb576bb76555164a9e7 (diff) | |
parent | d661aa56a8843e991261510c1bb28fdc2f6975ae (diff) |
Add 'infra/libkookie/' from commit 'd661aa56a8843e991261510c1bb28fdc2f6975ae'
git-subtree-dir: infra/libkookie
git-subtree-mainline: 49f735974dd103039ddc4cb576bb76555164a9e7
git-subtree-split: d661aa56a8843e991261510c1bb28fdc2f6975ae
Diffstat (limited to 'infra/libkookie/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix')
-rw-r--r-- | infra/libkookie/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix new file mode 100644 index 000000000000..936e211ec713 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix @@ -0,0 +1,183 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.uwsgi; + + buildCfg = name: c: + let + plugins = + if any (n: !any (m: m == n) cfg.plugins) (c.plugins or []) + then throw "`plugins` attribute in UWSGI configuration contains plugins not in config.services.uwsgi.plugins" + else c.plugins or cfg.plugins; + + hasPython = v: filter (n: n == "python${v}") plugins != []; + hasPython2 = hasPython "2"; + hasPython3 = hasPython "3"; + + python = + if hasPython2 && hasPython3 then + throw "`plugins` attribute in UWSGI configuration shouldn't contain both python2 and python3" + else if hasPython2 then cfg.package.python2 + else if hasPython3 then cfg.package.python3 + else null; + + pythonEnv = python.withPackages (c.pythonPackages or (self: [])); + + uwsgiCfg = { + uwsgi = + if c.type == "normal" + then { + inherit plugins; + } // removeAttrs c [ "type" "pythonPackages" ] + // optionalAttrs (python != null) { + pyhome = "${pythonEnv}"; + env = + # Argh, uwsgi expects list of key-values there instead of a dictionary. + let env' = c.env or []; + getPath = + x: if hasPrefix "PATH=" x + then substring (stringLength "PATH=") (stringLength x) x + else null; + oldPaths = filter (x: x != null) (map getPath env'); + in env' ++ [ "PATH=${optionalString (oldPaths != []) "${last oldPaths}:"}${pythonEnv}/bin" ]; + } + else if c.type == "emperor" + then { + emperor = if builtins.typeOf c.vassals != "set" then c.vassals + else pkgs.buildEnv { + name = "vassals"; + paths = mapAttrsToList buildCfg c.vassals; + }; + } // removeAttrs c [ "type" "vassals" ] + else throw "`type` attribute in UWSGI configuration should be either 'normal' or 'emperor'"; + }; + + in pkgs.writeTextDir "${name}.json" (builtins.toJSON uwsgiCfg); + +in { + + options = { + services.uwsgi = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Enable uWSGI"; + }; + + runDir = mkOption { + type = types.path; + default = "/run/uwsgi"; + description = "Where uWSGI communication sockets can live"; + }; + + package = mkOption { + type = types.package; + internal = true; + }; + + instance = mkOption { + type = with lib.types; let + valueType = nullOr (oneOf [ + bool + int + float + str + (lazyAttrsOf valueType) + (listOf valueType) + (mkOptionType { + name = "function"; + description = "function"; + check = x: isFunction x; + merge = mergeOneOption; + }) + ]) // { + description = "Json value or lambda"; + emptyValue.value = {}; + }; + in valueType; + default = { + type = "normal"; + }; + example = literalExample '' + { + type = "emperor"; + vassals = { + moin = { + type = "normal"; + pythonPackages = self: with self; [ moinmoin ]; + socket = "${config.services.uwsgi.runDir}/uwsgi.sock"; + }; + }; + } + ''; + description = '' + uWSGI configuration. It awaits an attribute <literal>type</literal> inside which can be either + <literal>normal</literal> or <literal>emperor</literal>. + + For <literal>normal</literal> mode you can specify <literal>pythonPackages</literal> as a function + from libraries set into a list of libraries. <literal>pythonpath</literal> will be set accordingly. + + For <literal>emperor</literal> mode, you should use <literal>vassals</literal> attribute + which should be either a set of names and configurations or a path to a directory. + + Other attributes will be used in configuration file as-is. Notice that you can redefine + <literal>plugins</literal> setting here. + ''; + }; + + plugins = mkOption { + type = types.listOf types.str; + default = []; + description = "Plugins used with uWSGI"; + }; + + user = mkOption { + type = types.str; + default = "uwsgi"; + description = "User account under which uwsgi runs."; + }; + + group = mkOption { + type = types.str; + default = "uwsgi"; + description = "Group account under which uwsgi runs."; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.uwsgi = { + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -p ${cfg.runDir} + chown ${cfg.user}:${cfg.group} ${cfg.runDir} + ''; + serviceConfig = { + Type = "notify"; + ExecStart = "${cfg.package}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${buildCfg "server" cfg.instance}/server.json"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; + NotifyAccess = "main"; + KillSignal = "SIGQUIT"; + }; + }; + + users.users = optionalAttrs (cfg.user == "uwsgi") { + uwsgi = { + group = cfg.group; + uid = config.ids.uids.uwsgi; + }; + }; + + users.groups = optionalAttrs (cfg.group == "uwsgi") { + uwsgi.gid = config.ids.gids.uwsgi; + }; + + services.uwsgi.package = pkgs.uwsgi.override { + inherit (cfg) plugins; + }; + }; +} |