at 15.09-beta 4.3 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.uwsgi; 7 8 python2Pkgs = pkgs.python2Packages.override { 9 python = pkgs.uwsgi.python2; 10 self = python2Pkgs; 11 }; 12 13 python3Pkgs = pkgs.python3Packages.override { 14 python = pkgs.uwsgi.python3; 15 self = python3Pkgs; 16 }; 17 18 buildCfg = c: if builtins.typeOf c != "set" then builtins.readFile c else builtins.toJSON { 19 uwsgi = 20 if c.type == "normal" 21 then { 22 pythonpath = 23 (if c ? python2Packages 24 then builtins.map (x: "${x}/${pkgs.uwsgi.python2.sitePackages}") (c.python2Packages python2Pkgs) 25 else []) 26 ++ (if c ? python3Packages 27 then builtins.map (x: "${x}/${pkgs.uwsgi.python3.sitePackages}") (c.python3Packages python3Pkgs) 28 else []); 29 plugins = cfg.plugins; 30 } // removeAttrs c [ "type" "python2Packages" "python3Packages" ] 31 else if c.type == "emperor" 32 then { 33 emperor = if builtins.typeOf c.vassals != "set" then c.vassals 34 else pkgs.buildEnv { 35 name = "vassals"; 36 paths = mapAttrsToList (n: c: pkgs.writeTextDir "${n}.json" (buildCfg c)) c.vassals; 37 }; 38 } // removeAttrs c [ "type" "vassals" ] 39 else abort "type should be either 'normal' or 'emperor'"; 40 }; 41 42 uwsgi = pkgs.uwsgi.override { 43 plugins = cfg.plugins; 44 }; 45 46in { 47 48 options = { 49 services.uwsgi = { 50 51 enable = mkOption { 52 type = types.bool; 53 default = false; 54 description = "Enable uWSGI"; 55 }; 56 57 runDir = mkOption { 58 type = types.string; 59 default = "/run/uwsgi"; 60 description = "Where uWSGI communication sockets can live"; 61 }; 62 63 instance = mkOption { 64 type = types.attrs; 65 default = { 66 type = "normal"; 67 }; 68 example = literalExample '' 69 { 70 type = "emperor"; 71 vassals = { 72 moin = { 73 type = "normal"; 74 python2Packages = self: with self; [ moinmoin ]; 75 socket = "${config.services.uwsgi.runDir}/uwsgi.sock"; 76 }; 77 }; 78 } 79 ''; 80 description = '' 81 uWSGI configuration. This awaits either a path to file or a set which will be made into one. 82 If given a set, it awaits an attribute <literal>type</literal> which can be either <literal>normal</literal> 83 or <literal>emperor</literal>. 84 85 For <literal>normal</literal> mode you can specify <literal>python2Packages</literal> and 86 <literal>python3Packages</literal> as functions from libraries set into lists of libraries. 87 For <literal>emperor</literal> mode, you should use <literal>vassals</literal> attribute 88 which should be either a set of names and configurations or a path to a directory. 89 ''; 90 }; 91 92 plugins = mkOption { 93 type = types.listOf types.str; 94 default = []; 95 description = "Plugins used with uWSGI"; 96 }; 97 98 user = mkOption { 99 type = types.str; 100 default = "uwsgi"; 101 description = "User account under which uwsgi runs."; 102 }; 103 104 group = mkOption { 105 type = types.str; 106 default = "uwsgi"; 107 description = "Group account under which uwsgi runs."; 108 }; 109 }; 110 }; 111 112 config = mkIf cfg.enable { 113 systemd.services.uwsgi = { 114 wantedBy = [ "multi-user.target" ]; 115 preStart = '' 116 mkdir -p ${cfg.runDir} 117 chown ${cfg.user}:${cfg.group} ${cfg.runDir} 118 ''; 119 serviceConfig = { 120 Type = "notify"; 121 ExecStart = "${uwsgi}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${pkgs.writeText "uwsgi.json" (buildCfg cfg.instance)}"; 122 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 123 ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; 124 NotifyAccess = "main"; 125 KillSignal = "SIGQUIT"; 126 }; 127 }; 128 129 users.extraUsers = optionalAttrs (cfg.user == "uwsgi") (singleton 130 { name = "uwsgi"; 131 group = cfg.group; 132 uid = config.ids.uids.uwsgi; 133 }); 134 135 users.extraGroups = optionalAttrs (cfg.group == "uwsgi") (singleton 136 { name = "uwsgi"; 137 gid = config.ids.gids.uwsgi; 138 }); 139 }; 140}