at 18.03-beta 9.6 kB view raw
1{ config, lib, pkgs, ... }: 2with lib; 3 4let 5 cfg = config.services.lighttpd.inginious; 6 inginious = pkgs.inginious; 7 execName = "inginious-${if cfg.useLTI then "lti" else "webapp"}"; 8 9 inginiousConfigFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "inginious.yaml" '' 10 # Backend; can be: 11 # - "local" (run containers on the same machine) 12 # - "remote" (connect to distant docker daemon and auto start agents) (choose this if you use boot2docker) 13 # - "remote_manual" (connect to distant and manually installed agents) 14 backend: "${cfg.backendType}" 15 16 ## TODO (maybe): Add an option for the "remote" backend in this NixOS module. 17 # List of remote docker daemon to which the backend will try 18 # to connect (backend: remote only) 19 #docker_daemons: 20 # - # Host of the docker daemon *from the webapp* 21 # remote_host: "some.remote.server" 22 # # Port of the distant docker daemon *from the webapp* 23 # remote_docker_port: "2375" 24 # # A mandatory port used by the backend and the agent that will be automatically started. 25 # # Needs to be available on the remote host, and to be open in the firewall. 26 # remote_agent_port: "63456" 27 # # Does the remote docker requires tls? Defaults to false. 28 # # Parameter can be set to true or path to the certificates 29 # #use_tls: false 30 # # Link to the docker daemon *from the host that runs the docker daemon*. Defaults to: 31 # #local_location: "unix:///var/run/docker.sock" 32 # # Path to the cgroups "mount" *from the host that runs the docker daemon*. Defaults to: 33 # #cgroups_location: "/sys/fs/cgroup" 34 # # Name that will be used to reference the agent 35 # #"agent_name": "inginious-agent" 36 37 # List of remote agents to which the backend will try 38 # to connect (backend: remote_manual only) 39 # Example: 40 #agents: 41 # - host: "192.168.59.103" 42 # port: 5001 43 agents: 44 ${lib.concatMapStrings (agent: 45 " - host: \"${agent.host}\"\n" + 46 " port: ${agent.port}\n" 47 ) cfg.remoteAgents} 48 49 # Location of the task directory 50 tasks_directory: "${cfg.tasksDirectory}" 51 52 # Super admins: list of user names that can do everything in the backend 53 superadmins: 54 ${lib.concatMapStrings (x: " - \"${x}\"\n") cfg.superadmins} 55 56 # Aliases for containers 57 # Only containers listed here can be used by tasks 58 containers: 59 ${lib.concatStrings (lib.mapAttrsToList (name: fullname: 60 " ${name}: \"${fullname}\"\n" 61 ) cfg.containers)} 62 63 # Use single minified javascript file (production) or multiple files (dev) ? 64 use_minified_js: true 65 66 ## TODO (maybe): Add NixOS options for these parameters. 67 68 # MongoDB options 69 #mongo_opt: 70 # host: localhost 71 # database: INGInious 72 73 # Disable INGInious? 74 #maintenance: false 75 76 #smtp: 77 # sendername: 'INGInious <no-reply@inginious.org>' 78 # host: 'smtp.gmail.com' 79 # port: 587 80 # username: 'configme@gmail.com' 81 # password: 'secret' 82 # starttls: True 83 84 ## NixOS extra config 85 86 ${cfg.extraConfig} 87 ''; 88in 89{ 90 options.services.lighttpd.inginious = { 91 enable = mkEnableOption "INGInious, an automated code testing and grading system."; 92 93 configFile = mkOption { 94 type = types.nullOr types.path; 95 default = null; 96 example = literalExample ''pkgs.writeText "configuration.yaml" "# custom config options ...";''; 97 description = ''The path to an INGInious configuration file.''; 98 }; 99 100 extraConfig = mkOption { 101 type = types.lines; 102 default = ""; 103 example = '' 104 # Load the dummy auth plugin. 105 plugins: 106 - plugin_module: inginious.frontend.webapp.plugins.auth.demo_auth 107 users: 108 # register the user "test" with the password "someverycomplexpassword" 109 test: someverycomplexpassword 110 ''; 111 description = ''Extra option in YaML format, to be appended to the config file.''; 112 }; 113 114 tasksDirectory = mkOption { 115 type = types.path; 116 example = "/var/lib/INGInious/tasks"; 117 description = '' 118 Path to the tasks folder. 119 Defaults to the provided test tasks folder (readonly). 120 ''; 121 }; 122 123 useLTI = mkOption { 124 type = types.bool; 125 default = false; 126 description = ''Whether to start the LTI frontend in place of the webapp.''; 127 }; 128 129 superadmins = mkOption { 130 type = types.uniq (types.listOf types.str); 131 default = [ "admin" ]; 132 example = [ "john" "pepe" "emilia" ]; 133 description = ''List of user logins allowed to administrate the whole server.''; 134 }; 135 136 containers = mkOption { 137 type = types.attrsOf types.str; 138 default = { 139 default = "ingi/inginious-c-default"; 140 }; 141 example = { 142 default = "ingi/inginious-c-default"; 143 sekexe = "ingi/inginious-c-sekexe"; 144 java = "ingi/inginious-c-java"; 145 oz = "ingi/inginious-c-oz"; 146 pythia1compat = "ingi/inginious-c-pythia1compat"; 147 }; 148 description = '' 149 An attrset describing the required containers 150 These containers will be available in INGInious using their short name (key) 151 and will be automatically downloaded before INGInious starts. 152 ''; 153 }; 154 155 hostPattern = mkOption { 156 type = types.str; 157 default = "^inginious."; 158 example = "^inginious.mydomain.xyz$"; 159 description = '' 160 The domain that serves INGInious. 161 INGInious uses absolute paths which makes it difficult to relocate in its own subdir. 162 The default configuration will serve INGInious when the server is accessed with a hostname starting with "inginious.". 163 If left blank, INGInious will take the precedence over all the other lighttpd sites, which is probably not what you want. 164 ''; 165 }; 166 167 backendType = mkOption { 168 type = types.enum [ "local" "remote_manual" ]; # TODO: support backend "remote" 169 default = "local"; 170 description = '' 171 Select how INGINious accesses to grading containers. 172 The default "local" option ensures that Docker is started and provisioned. 173 Fore more information, see http://inginious.readthedocs.io/en/latest/install_doc/config_reference.html 174 Not all backends are supported. Use services.inginious.configFile for full flexibility. 175 ''; 176 }; 177 178 remoteAgents = mkOption { 179 type = types.listOf (types.attrsOf types.str); 180 default = []; 181 example = [ { host = "192.0.2.25"; port = "1345"; } ]; 182 description = ''A list of remote agents, used only when services.inginious.backendType is "remote_manual".''; 183 }; 184 }; 185 186 config = mkIf cfg.enable ( 187 mkMerge [ 188 # For a local install, we need docker. 189 (mkIf (cfg.backendType == "local") { 190 virtualisation.docker = { 191 enable = true; 192 # We need docker to listen on port 2375. 193 listenOptions = ["127.0.0.1:2375" "/var/run/docker.sock"]; 194 storageDriver = mkDefault "overlay"; 195 }; 196 197 users.extraUsers."lighttpd".extraGroups = [ "docker" ]; 198 199 # Ensure that docker has pulled the required images. 200 systemd.services.inginious-prefetch = { 201 script = let 202 images = lib.unique ( 203 [ "centos" "ingi/inginious-agent" ] 204 ++ lib.mapAttrsToList (_: image: image) cfg.containers 205 ); 206 in lib.concatMapStrings (image: '' 207 ${pkgs.docker}/bin/docker pull ${image} 208 '') images; 209 210 serviceConfig.Type = "oneshot"; 211 wants = [ "docker.service" ]; 212 after = [ "docker.service" ]; 213 wantedBy = [ "lighttpd.service" ]; 214 before = [ "lighttpd.service" ]; 215 }; 216 }) 217 218 # Common 219 { 220 services.lighttpd.inginious.tasksDirectory = mkDefault "${inginious}/lib/python2.7/site-packages/inginious/tasks"; 221 # To access inginous tools (like inginious-test-task) 222 environment.systemPackages = [ inginious ]; 223 224 services.mongodb.enable = true; 225 226 services.lighttpd.enable = true; 227 services.lighttpd.enableModules = [ "mod_access" "mod_alias" "mod_fastcgi" "mod_redirect" "mod_rewrite" ]; 228 services.lighttpd.extraConfig = '' 229 $HTTP["host"] =~ "${cfg.hostPattern}" { 230 fastcgi.server = ( "/${execName}" => 231 (( 232 "socket" => "/run/lighttpd/inginious-fastcgi.socket", 233 "bin-path" => "${inginious}/bin/${execName} --config=${inginiousConfigFile}", 234 "max-procs" => 1, 235 "bin-environment" => ( "REAL_SCRIPT_NAME" => "" ), 236 "check-local" => "disable" 237 )) 238 ) 239 url.rewrite-once = ( 240 "^/.well-known/.*" => "$0", 241 "^/static/.*" => "$0", 242 "^/.*$" => "/${execName}$0", 243 "^/favicon.ico$" => "/static/common/favicon.ico", 244 ) 245 alias.url += ( 246 "/static/webapp/" => "${inginious}/lib/python2.7/site-packages/inginious/frontend/webapp/static/", 247 "/static/common/" => "${inginious}/lib/python2.7/site-packages/inginious/frontend/common/static/" 248 ) 249 } 250 ''; 251 252 systemd.services.lighttpd.preStart = '' 253 mkdir -p /run/lighttpd 254 chown lighttpd.lighttpd /run/lighttpd 255 ''; 256 257 systemd.services.lighttpd.wants = [ "mongodb.service" "docker.service" ]; 258 systemd.services.lighttpd.after = [ "mongodb.service" "docker.service" ]; 259 } 260 ]); 261}