at 17.09-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 default = "${inginious}/lib/python2.7/site-packages/inginious/tasks"; 117 example = "/var/lib/INGInious/tasks"; 118 description = '' 119 Path to the tasks folder. 120 Defaults to the provided test tasks folder (readonly). 121 ''; 122 }; 123 124 useLTI = mkOption { 125 type = types.bool; 126 default = false; 127 description = ''Whether to start the LTI frontend in place of the webapp.''; 128 }; 129 130 superadmins = mkOption { 131 type = types.uniq (types.listOf types.str); 132 default = [ "admin" ]; 133 example = [ "john" "pepe" "emilia" ]; 134 description = ''List of user logins allowed to administrate the whole server.''; 135 }; 136 137 containers = mkOption { 138 type = types.attrsOf types.str; 139 default = { 140 default = "ingi/inginious-c-default"; 141 }; 142 example = { 143 default = "ingi/inginious-c-default"; 144 sekexe = "ingi/inginious-c-sekexe"; 145 java = "ingi/inginious-c-java"; 146 oz = "ingi/inginious-c-oz"; 147 pythia1compat = "ingi/inginious-c-pythia1compat"; 148 }; 149 description = '' 150 An attrset describing the required containers 151 These containers will be available in INGInious using their short name (key) 152 and will be automatically downloaded before INGInious starts. 153 ''; 154 }; 155 156 hostPattern = mkOption { 157 type = types.str; 158 default = "^inginious."; 159 example = "^inginious.mydomain.xyz$"; 160 description = '' 161 The domain that serves INGInious. 162 INGInious uses absolute paths which makes it difficult to relocate in its own subdir. 163 The default configuration will serve INGInious when the server is accessed with a hostname starting with "inginious.". 164 If left blank, INGInious will take the precedence over all the other lighttpd sites, which is probably not what you want. 165 ''; 166 }; 167 168 backendType = mkOption { 169 type = types.enum [ "local" "remote_manual" ]; # TODO: support backend "remote" 170 default = "local"; 171 description = '' 172 Select how INGINious accesses to grading containers. 173 The default "local" option ensures that Docker is started and provisioned. 174 Fore more information, see http://inginious.readthedocs.io/en/latest/install_doc/config_reference.html 175 Not all backends are supported. Use services.inginious.configFile for full flexibility. 176 ''; 177 }; 178 179 remoteAgents = mkOption { 180 type = types.listOf (types.attrsOf types.str); 181 default = []; 182 example = [ { host = "192.0.2.25"; port = "1345"; } ]; 183 description = ''A list of remote agents, used only when services.inginious.backendType is "remote_manual".''; 184 }; 185 }; 186 187 config = mkIf cfg.enable ( 188 mkMerge [ 189 # For a local install, we need docker. 190 (mkIf (cfg.backendType == "local") { 191 virtualisation.docker = { 192 enable = true; 193 # We need docker to listen on port 2375. 194 listenOptions = ["127.0.0.1:2375" "/var/run/docker.sock"]; 195 storageDriver = mkDefault "overlay"; 196 }; 197 198 users.extraUsers."lighttpd".extraGroups = [ "docker" ]; 199 200 # Ensure that docker has pulled the required images. 201 systemd.services.inginious-prefetch = { 202 script = let 203 images = lib.unique ( 204 [ "centos" "ingi/inginious-agent" ] 205 ++ lib.mapAttrsToList (_: image: image) cfg.containers 206 ); 207 in lib.concatMapStrings (image: '' 208 ${pkgs.docker}/bin/docker pull ${image} 209 '') images; 210 211 serviceConfig.Type = "oneshot"; 212 wants = [ "docker.service" ]; 213 after = [ "docker.service" ]; 214 wantedBy = [ "lighttpd.service" ]; 215 before = [ "lighttpd.service" ]; 216 }; 217 }) 218 219 # Common 220 { 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}