at master 5.7 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7let 8 cfg = config.services.tandoor-recipes; 9 pkg = cfg.package; 10 11 # SECRET_KEY through an env file 12 env = { 13 GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}"; 14 DEBUG = "0"; 15 DEBUG_TOOLBAR = "0"; 16 MEDIA_ROOT = "/var/lib/tandoor-recipes"; 17 } 18 // lib.optionalAttrs (config.time.timeZone != null) { 19 TZ = config.time.timeZone; 20 } 21 // (lib.mapAttrs (_: toString) cfg.extraConfig); 22 23 manage = pkgs.writeShellScript "manage" '' 24 set -o allexport # Export the following env vars 25 ${lib.toShellVars env} 26 # UID is a read-only shell variable 27 eval "$(${config.systemd.package}/bin/systemctl show -pUID,GID,MainPID tandoor-recipes.service | tr '[:upper:]' '[:lower:]')" 28 exec ${pkgs.util-linux}/bin/nsenter \ 29 -t $mainpid -m -S $uid -G $gid --wdns=${env.MEDIA_ROOT} \ 30 ${pkg}/bin/tandoor-recipes "$@" 31 ''; 32in 33{ 34 meta.maintainers = with lib.maintainers; [ jvanbruegge ]; 35 36 options.services.tandoor-recipes = { 37 enable = lib.mkOption { 38 type = lib.types.bool; 39 default = false; 40 description = '' 41 Enable Tandoor Recipes. 42 43 When started, the Tandoor Recipes database is automatically created if 44 it doesn't exist and updated if the package has changed. Both tasks are 45 achieved by running a Django migration. 46 47 A script to manage the instance (by wrapping Django's manage.py) is linked to 48 `/var/lib/tandoor-recipes/tandoor-recipes-manage`. 49 ''; 50 }; 51 52 address = lib.mkOption { 53 type = lib.types.str; 54 default = "localhost"; 55 description = "Web interface address."; 56 }; 57 58 port = lib.mkOption { 59 type = lib.types.port; 60 default = 8080; 61 description = "Web interface port."; 62 }; 63 64 extraConfig = lib.mkOption { 65 type = lib.types.attrs; 66 default = { }; 67 description = '' 68 Extra tandoor recipes config options. 69 70 See [the example dot-env file](https://raw.githubusercontent.com/vabene1111/recipes/master/.env.template) 71 for available options. 72 ''; 73 example = { 74 ENABLE_SIGNUP = "1"; 75 }; 76 }; 77 78 user = lib.mkOption { 79 type = lib.types.str; 80 default = "tandoor_recipes"; 81 description = "User account under which Tandoor runs."; 82 }; 83 84 group = lib.mkOption { 85 type = lib.types.str; 86 default = "tandoor_recipes"; 87 description = "Group under which Tandoor runs."; 88 }; 89 90 package = lib.mkPackageOption pkgs "tandoor-recipes" { }; 91 92 database = { 93 createLocally = lib.mkOption { 94 type = lib.types.bool; 95 default = false; 96 description = '' 97 Configure local PostgreSQL database server for Tandoor Recipes. 98 ''; 99 }; 100 }; 101 }; 102 103 config = lib.mkIf cfg.enable { 104 users.users = lib.mkIf (cfg.user == "tandoor_recipes") { 105 tandoor_recipes = { 106 inherit (cfg) group; 107 isSystemUser = true; 108 }; 109 }; 110 111 users.groups = lib.mkIf (cfg.group == "tandoor_recipes") { 112 tandoor_recipes = { }; 113 }; 114 115 systemd.services.tandoor-recipes = { 116 description = "Tandoor Recipes server"; 117 118 requires = lib.optional cfg.database.createLocally "postgresql.target"; 119 after = lib.optional cfg.database.createLocally "postgresql.target"; 120 121 serviceConfig = { 122 ExecStart = '' 123 ${pkg.python.pkgs.gunicorn}/bin/gunicorn recipes.wsgi 124 ''; 125 Restart = "on-failure"; 126 127 User = cfg.user; 128 Group = cfg.group; 129 StateDirectory = "tandoor-recipes"; 130 WorkingDirectory = env.MEDIA_ROOT; 131 RuntimeDirectory = "tandoor-recipes"; 132 133 BindReadOnlyPaths = [ 134 "${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt" 135 builtins.storeDir 136 "-/etc/resolv.conf" 137 "-/etc/nsswitch.conf" 138 "-/etc/hosts" 139 "-/etc/localtime" 140 "-/run/postgresql" 141 ]; 142 CapabilityBoundingSet = ""; 143 LockPersonality = true; 144 MemoryDenyWriteExecute = true; 145 PrivateDevices = true; 146 PrivateUsers = true; 147 ProtectClock = true; 148 ProtectControlGroups = true; 149 ProtectHome = true; 150 ProtectHostname = true; 151 ProtectKernelLogs = true; 152 ProtectKernelModules = true; 153 ProtectKernelTunables = true; 154 RestrictAddressFamilies = [ 155 "AF_UNIX" 156 "AF_INET" 157 "AF_INET6" 158 ]; 159 RestrictNamespaces = true; 160 RestrictRealtime = true; 161 SystemCallArchitectures = "native"; 162 # gunicorn needs setuid 163 SystemCallFilter = [ 164 "@system-service" 165 "~@privileged" 166 "@resources" 167 "@setuid" 168 "@keyring" 169 ]; 170 UMask = "0066"; 171 }; 172 173 wantedBy = [ "multi-user.target" ]; 174 175 preStart = '' 176 ln -sf ${manage} tandoor-recipes-manage 177 178 # Let django migrate the DB as needed 179 ${pkg}/bin/tandoor-recipes migrate 180 ''; 181 182 environment = env // { 183 PYTHONPATH = "${pkg.python.pkgs.makePythonPath pkg.propagatedBuildInputs}:${pkg}/lib/tandoor-recipes"; 184 }; 185 }; 186 187 services.tandoor-recipes.extraConfig = lib.mkIf cfg.database.createLocally { 188 DB_ENGINE = "django.db.backends.postgresql"; 189 POSTGRES_HOST = "/run/postgresql"; 190 POSTGRES_USER = "tandoor_recipes"; 191 POSTGRES_DB = "tandoor_recipes"; 192 }; 193 194 services.postgresql = lib.mkIf cfg.database.createLocally { 195 enable = true; 196 ensureDatabases = [ "tandoor_recipes" ]; 197 ensureUsers = [ 198 { 199 name = "tandoor_recipes"; 200 ensureDBOwnership = true; 201 } 202 ]; 203 }; 204 }; 205}