gnu: Add java-sonatype-aether-util.
[jackhill/guix/guix.git] / gnu / services / web.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2015 David Thompson <davet@gnu.org>
3 ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
4 ;;; Copyright © 2016 Nikita <nikita@n0.is>
5 ;;; Copyright © 2016, 2017, 2018 Julien Lepiller <julien@lepiller.eu>
6 ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
7 ;;; Copyright © 2017 nee <nee-git@hidamari.blue>
8 ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
9 ;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr>
10 ;;; Copyright © 2017, 2018, 2019 Christopher Baines <mail@cbaines.net>
11 ;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
12 ;;; Copyright © 2019, 2020 Florian Pelz <pelzflorian@pelzflorian.de>
13 ;;; Copyright © 2020 Ricardo Wurmus <rekado@elephly.net>
14 ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
15 ;;;
16 ;;; This file is part of GNU Guix.
17 ;;;
18 ;;; GNU Guix is free software; you can redistribute it and/or modify it
19 ;;; under the terms of the GNU General Public License as published by
20 ;;; the Free Software Foundation; either version 3 of the License, or (at
21 ;;; your option) any later version.
22 ;;;
23 ;;; GNU Guix is distributed in the hope that it will be useful, but
24 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 ;;; GNU General Public License for more details.
27 ;;;
28 ;;; You should have received a copy of the GNU General Public License
29 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
30
31 (define-module (gnu services web)
32 #:use-module (gnu services)
33 #:use-module (gnu services shepherd)
34 #:use-module (gnu services admin)
35 #:use-module (gnu services getmail)
36 #:use-module (gnu services mail)
37 #:use-module (gnu system pam)
38 #:use-module (gnu system shadow)
39 #:use-module (gnu packages admin)
40 #:use-module (gnu packages base)
41 #:use-module (gnu packages databases)
42 #:use-module (gnu packages web)
43 #:use-module (gnu packages patchutils)
44 #:use-module (gnu packages php)
45 #:use-module (gnu packages python)
46 #:use-module (gnu packages gnupg)
47 #:use-module (gnu packages guile)
48 #:use-module (gnu packages logging)
49 #:use-module (gnu packages mail)
50 #:use-module (guix packages)
51 #:use-module (guix records)
52 #:use-module (guix modules)
53 #:use-module (guix utils)
54 #:use-module (guix gexp)
55 #:use-module ((guix store) #:select (text-file))
56 #:use-module ((guix utils) #:select (version-major))
57 #:use-module ((guix packages) #:select (package-version))
58 #:use-module (srfi srfi-1)
59 #:use-module (srfi srfi-9)
60 #:use-module (ice-9 match)
61 #:use-module (ice-9 format)
62 #:export (httpd-configuration
63 httpd-configuration?
64 httpd-configuration-package
65 httpd-configuration-pid-file
66 httpd-configuration-config
67
68 httpd-virtualhost
69 httpd-virtualhost?
70 httpd-virtualhost-addresses-and-ports
71 httpd-virtualhost-contents
72
73 httpd-config-file
74 httpd-config-file?
75 httpd-config-file-modules
76 httpd-config-file-server-root
77 httpd-config-file-server-name
78 httpd-config-file-listen
79 httpd-config-file-pid-file
80 httpd-config-file-error-log
81 httpd-config-file-user
82 httpd-config-file-group
83
84 httpd-module
85 httpd-module?
86 %default-httpd-modules
87
88 httpd-service-type
89
90 nginx-configuration
91 nginx-configuration?
92 nginx-configuartion-nginx
93 nginx-configuration-log-directory
94 nginx-configuration-run-directory
95 nginx-configuration-server-blocks
96 nginx-configuration-upstream-blocks
97 nginx-configuration-server-names-hash-bucket-size
98 nginx-configuration-server-names-hash-bucket-max-size
99 nginx-configuration-modules
100 nginx-configuration-global-directives
101 nginx-configuration-extra-content
102 nginx-configuration-file
103
104 nginx-server-configuration
105 nginx-server-configuration?
106 nginx-server-configuration-listen
107 nginx-server-configuration-server-name
108 nginx-server-configuration-root
109 nginx-server-configuration-locations
110 nginx-server-configuration-index
111 nginx-server-configuration-ssl-certificate
112 nginx-server-configuration-ssl-certificate-key
113 nginx-server-configuration-server-tokens?
114 nginx-server-configuration-raw-content
115
116 nginx-upstream-configuration
117 nginx-upstream-configuration?
118 nginx-upstream-configuration-name
119 nginx-upstream-configuration-servers
120
121 nginx-location-configuration
122 nginx-location-configuration?
123 nginx-location-configuration-uri
124 nginx-location-configuration-body
125
126 nginx-named-location-configuration
127 nginx-named-location-configuration?
128 nginx-named-location-configuration-name
129 nginx-named-location-configuration-body
130
131 nginx-service
132 nginx-service-type
133
134 fcgiwrap-configuration
135 fcgiwrap-configuration?
136 fcgiwrap-service-type
137
138 php-fpm-configuration
139 make-php-fpm-configuration
140 php-fpm-configuration?
141 php-fpm-configuration-php
142 php-fpm-configuration-socket
143 php-fpm-configuration-user
144 php-fpm-configuration-group
145 php-fpm-configuration-socket-user
146 php-fpm-configuration-socket-group
147 php-fpm-configuration-pid-file
148 php-fpm-configuration-log-file
149 php-fpm-configuration-process-manager
150 php-fpm-configuration-display-errors
151 php-fpm-configuration-timezone
152 php-fpm-configuration-workers-log-file
153 php-fpm-configuration-file
154
155 php-fpm-dynamic-process-manager-configuration
156 make-php-fpm-dynamic-process-manager-configuration
157 php-fpm-dynamic-process-manager-configuration?
158 php-fpm-dynamic-process-manager-configuration-max-children
159 php-fpm-dynamic-process-manager-configuration-start-servers
160 php-fpm-dynamic-process-manager-configuration-min-spare-servers
161 php-fpm-dynamic-process-manager-configuration-max-spare-servers
162
163 php-fpm-static-process-manager-configuration
164 make-php-fpm-static-process-manager-configuration
165 php-fpm-static-process-manager-configuration?
166 php-fpm-static-process-manager-configuration-max-children
167
168 php-fpm-on-demand-process-manager-configuration
169 make-php-fpm-on-demand-process-manager-configuration
170 php-fpm-on-demand-process-manager-configuration?
171 php-fpm-on-demand-process-manager-configuration-max-children
172 php-fpm-on-demand-process-manager-configuration-process-idle-timeout
173
174 php-fpm-service-type
175 nginx-php-location
176
177 cat-avatar-generator-service
178
179 hpcguix-web-configuration
180 hpcguix-web-configuration?
181 hpcguix-web-service-type
182
183 tailon-configuration-file
184 tailon-configuration-file?
185 tailon-configuration-file-files
186 tailon-configuration-file-bind
187 tailon-configuration-file-relative-root
188 tailon-configuration-file-allow-transfers?
189 tailon-configuration-file-follow-names?
190 tailon-configuration-file-tail-lines
191 tailon-configuration-file-allowed-commands
192 tailon-configuration-file-debug?
193 tailon-configuration-file-http-auth
194 tailon-configuration-file-users
195
196 tailon-configuration
197 tailon-configuration?
198 tailon-configuration-config-file
199 tailon-configuration-package
200
201 tailon-service-type
202
203 varnish-configuration
204 varnish-configuration?
205 varnish-configuration-package
206 varnish-configuration-name
207 varnish-configuration-backend
208 varnish-configuration-vcl
209 varnish-configuration-listen
210 varnish-configuration-storage
211 varnish-configuration-parameters
212 varnish-configuration-extra-options
213
214 varnish-service-type
215
216 patchwork-database-configuration
217 patchwork-database-configuration?
218 patchwork-database-configuration-engine
219 patchwork-database-configuration-name
220 patchwork-database-configuration-user
221 patchwork-database-configuration-password
222 patchwork-database-configuration-host
223 patchwork-database-configuration-port
224
225 patchwork-settings-module
226 patchwork-settings-module?
227 patchwork-settings-module-database-configuration
228 patchwork-settings-module-secret-key
229 patchwork-settings-module-allowed-hosts
230 patchwork-settings-module-default-from-email
231 patchwork-settings-module-static-url
232 patchwork-settings-module-admins
233 patchwork-settings-module-debug?
234 patchwork-settings-module-enable-rest-api?
235 patchwork-settings-module-enable-xmlrpc?
236 patchwork-settings-module-force-https-links?
237 patchwork-settings-module-extra-settings
238
239 patchwork-configuration
240 patchwork-configuration?
241 patchwork-configuration-patchwork
242 patchwork-configuration-settings-module
243 patchwork-configuration-domain
244
245 patchwork-virtualhost
246 patchwork-service-type
247
248 mumi-configuration
249 mumi-configuration?
250 mumi-configuration-mumi
251 mumi-configuration-mailer?
252 mumi-configuration-sender
253 mumi-configuration-smtp
254
255 mumi-service-type))
256
257 ;;; Commentary:
258 ;;;
259 ;;; Web services.
260 ;;;
261 ;;; Code:
262
263 (define-record-type* <httpd-module>
264 httpd-module make-httpd-module
265 httpd-module?
266 (name httpd-load-module-name)
267 (file httpd-load-module-file))
268
269 ;; Default modules for the httpd-service-type, taken from etc/httpd/httpd.conf
270 ;; file in the httpd package.
271 (define %default-httpd-modules
272 (map (match-lambda
273 ((name file)
274 (httpd-module
275 (name name)
276 (file file))))
277 '(("authn_file_module" "modules/mod_authn_file.so")
278 ("authn_core_module" "modules/mod_authn_core.so")
279 ("authz_host_module" "modules/mod_authz_host.so")
280 ("authz_groupfile_module" "modules/mod_authz_groupfile.so")
281 ("authz_user_module" "modules/mod_authz_user.so")
282 ("authz_core_module" "modules/mod_authz_core.so")
283 ("access_compat_module" "modules/mod_access_compat.so")
284 ("auth_basic_module" "modules/mod_auth_basic.so")
285 ("reqtimeout_module" "modules/mod_reqtimeout.so")
286 ("filter_module" "modules/mod_filter.so")
287 ("mime_module" "modules/mod_mime.so")
288 ("log_config_module" "modules/mod_log_config.so")
289 ("env_module" "modules/mod_env.so")
290 ("headers_module" "modules/mod_headers.so")
291 ("setenvif_module" "modules/mod_setenvif.so")
292 ("version_module" "modules/mod_version.so")
293 ("unixd_module" "modules/mod_unixd.so")
294 ("status_module" "modules/mod_status.so")
295 ("autoindex_module" "modules/mod_autoindex.so")
296 ("dir_module" "modules/mod_dir.so")
297 ("alias_module" "modules/mod_alias.so"))))
298
299 (define-record-type* <httpd-config-file>
300 httpd-config-file make-httpd-config-file
301 httpd-config-file?
302 (modules httpd-config-file-modules
303 (default %default-httpd-modules))
304 (server-root httpd-config-file-server-root
305 (default httpd))
306 (server-name httpd-config-file-server-name
307 (default #f))
308 (document-root httpd-config-file-document-root
309 (default "/srv/http"))
310 (listen httpd-config-file-listen
311 (default '("80")))
312 (pid-file httpd-config-file-pid-file
313 (default "/var/run/httpd"))
314 (error-log httpd-config-file-error-log
315 (default "/var/log/httpd/error_log"))
316 (user httpd-config-file-user
317 (default "httpd"))
318 (group httpd-config-file-group
319 (default "httpd"))
320 (extra-config httpd-config-file-extra-config
321 (default
322 (list "TypesConfig etc/httpd/mime.types"))))
323
324 (define-gexp-compiler (httpd-config-file-compiler
325 (file <httpd-config-file>) system target)
326 (match file
327 (($ <httpd-config-file> load-modules server-root server-name
328 document-root listen pid-file error-log
329 user group extra-config)
330 (gexp->derivation
331 "httpd.conf"
332 #~(call-with-output-file (ungexp output "out")
333 (lambda (port)
334 (display
335 (string-append
336 (ungexp-splicing
337 `(,@(append-map
338 (match-lambda
339 (($ <httpd-module> name module)
340 `("LoadModule " ,name " " ,module "\n")))
341 load-modules)
342 ,@`("ServerRoot " ,server-root "\n")
343 ,@(if server-name
344 `("ServerName " ,server-name "\n")
345 '())
346 ,@`("DocumentRoot " ,document-root "\n")
347 ,@(append-map
348 (lambda (listen-value)
349 `("Listen " ,listen-value "\n"))
350 listen)
351 ,@(if pid-file
352 `("Pidfile " ,pid-file "\n")
353 '())
354 ,@(if error-log
355 `("ErrorLog " ,error-log "\n")
356 '())
357 ,@(if user
358 `("User " ,user "\n")
359 '())
360 ,@(if group
361 `("Group " ,group "\n")
362 '())
363 "\n\n"
364 ,@extra-config)))
365 port)))
366 #:local-build? #t))))
367
368 (define-record-type <httpd-virtualhost>
369 (httpd-virtualhost addresses-and-ports contents)
370 httpd-virtualhost?
371 (addresses-and-ports httpd-virtualhost-addresses-and-ports)
372 (contents httpd-virtualhost-contents))
373
374 (define-record-type* <httpd-configuration>
375 httpd-configuration make-httpd-configuration
376 httpd-configuration?
377 (package httpd-configuration-package
378 (default httpd))
379 (pid-file httpd-configuration-pid-file
380 (default "/var/run/httpd"))
381 (config httpd-configuration-config
382 (default (httpd-config-file))))
383
384 (define %httpd-accounts
385 (list (user-group (name "httpd") (system? #t))
386 (user-account
387 (name "httpd")
388 (group "httpd")
389 (system? #t)
390 (comment "Apache HTTPD server user")
391 (home-directory "/var/empty")
392 (shell (file-append shadow "/sbin/nologin")))))
393
394 (define httpd-shepherd-services
395 (match-lambda
396 (($ <httpd-configuration> package pid-file config)
397 (list (shepherd-service
398 (provision '(httpd))
399 (documentation "The Apache HTTP Server")
400 (requirement '(networking))
401 (start #~(make-forkexec-constructor
402 `(#$(file-append package "/bin/httpd")
403 #$@(if config
404 (list "-f" config)
405 '()))
406 #:pid-file #$pid-file))
407 (stop #~(make-kill-destructor)))))))
408
409 (define httpd-activation
410 (match-lambda
411 (($ <httpd-configuration> package pid-file config)
412 (match-record
413 config
414 <httpd-config-file>
415 (error-log document-root)
416 #~(begin
417 (use-modules (guix build utils))
418
419 (mkdir-p #$(dirname error-log))
420 (mkdir-p #$document-root))))))
421
422 (define (httpd-process-extensions original-config extension-configs)
423 (let ((config (httpd-configuration-config
424 original-config)))
425 (if (httpd-config-file? config)
426 (httpd-configuration
427 (inherit original-config)
428 (config
429 (httpd-config-file
430 (inherit config)
431 (extra-config
432 (append (httpd-config-file-extra-config config)
433 (append-map
434 (match-lambda
435 (($ <httpd-virtualhost>
436 addresses-and-ports
437 contents)
438 `(,(string-append
439 "\n<VirtualHost " addresses-and-ports ">\n")
440 ,@contents
441 "\n</VirtualHost>\n"))
442 ((? string? x)
443 `("\n" ,x "\n"))
444 ((? list? x)
445 `("\n" ,@x "\n")))
446 extension-configs)))))))))
447
448 (define httpd-service-type
449 (service-type (name 'httpd)
450 (extensions
451 (list (service-extension shepherd-root-service-type
452 httpd-shepherd-services)
453 (service-extension activation-service-type
454 httpd-activation)
455 (service-extension account-service-type
456 (const %httpd-accounts))))
457 (compose concatenate)
458 (extend httpd-process-extensions)
459 (default-value
460 (httpd-configuration))))
461
462 (define-record-type* <nginx-server-configuration>
463 nginx-server-configuration make-nginx-server-configuration
464 nginx-server-configuration?
465 (listen nginx-server-configuration-listen
466 (default '("80" "443 ssl")))
467 (server-name nginx-server-configuration-server-name
468 (default (list 'default)))
469 (root nginx-server-configuration-root
470 (default "/srv/http"))
471 (locations nginx-server-configuration-locations
472 (default '()))
473 (index nginx-server-configuration-index
474 (default (list "index.html")))
475 (try-files nginx-server-configuration-try-files
476 (default '()))
477 (ssl-certificate nginx-server-configuration-ssl-certificate
478 (default #f))
479 (ssl-certificate-key nginx-server-configuration-ssl-certificate-key
480 (default #f))
481 (server-tokens? nginx-server-configuration-server-tokens?
482 (default #f))
483 (raw-content nginx-server-configuration-raw-content
484 (default '())))
485
486 (define-record-type* <nginx-upstream-configuration>
487 nginx-upstream-configuration make-nginx-upstream-configuration
488 nginx-upstream-configuration?
489 (name nginx-upstream-configuration-name)
490 (servers nginx-upstream-configuration-servers))
491
492 (define-record-type* <nginx-location-configuration>
493 nginx-location-configuration make-nginx-location-configuration
494 nginx-location-configuration?
495 (uri nginx-location-configuration-uri
496 (default #f))
497 (body nginx-location-configuration-body))
498
499 (define-record-type* <nginx-named-location-configuration>
500 nginx-named-location-configuration make-nginx-named-location-configuration
501 nginx-named-location-configuration?
502 (name nginx-named-location-configuration-name
503 (default #f))
504 (body nginx-named-location-configuration-body))
505
506 (define-record-type* <nginx-configuration>
507 nginx-configuration make-nginx-configuration
508 nginx-configuration?
509 (nginx nginx-configuration-nginx ;<package>
510 (default nginx))
511 (log-directory nginx-configuration-log-directory ;string
512 (default "/var/log/nginx"))
513 (run-directory nginx-configuration-run-directory ;string
514 (default "/var/run/nginx"))
515 (server-blocks nginx-configuration-server-blocks
516 (default '())) ;list of <nginx-server-configuration>
517 (upstream-blocks nginx-configuration-upstream-blocks
518 (default '())) ;list of <nginx-upstream-configuration>
519 (server-names-hash-bucket-size nginx-configuration-server-names-hash-bucket-size
520 (default #f))
521 (server-names-hash-bucket-max-size nginx-configuration-server-names-hash-bucket-max-size
522 (default #f))
523 (modules nginx-configuration-modules (default '()))
524 (global-directives nginx-configuration-global-directives
525 (default '((events . ()))))
526 (extra-content nginx-configuration-extra-content
527 (default ""))
528 (file nginx-configuration-file ;#f | string | file-like
529 (default #f)))
530
531 (define (config-domain-strings names)
532 "Return a string denoting the nginx config representation of NAMES, a list
533 of domain names."
534 (map (match-lambda
535 ('default "_ ")
536 ((? string? str) (list str " ")))
537 names))
538
539 (define (config-index-strings names)
540 "Return a string denoting the nginx config representation of NAMES, a list
541 of index files."
542 (map (match-lambda
543 ((? string? str) (list str " ")))
544 names))
545
546 (define (emit-load-module module)
547 (list "load_module " module ";\n"))
548
549 (define emit-global-directive
550 (match-lambda
551 ((key . (? list? alist))
552 (format #f "~a { ~{~a~}}~%" key (map emit-global-directive alist)))
553 ((key . value)
554 (format #f "~a ~a;~%" key value))))
555
556 (define emit-nginx-location-config
557 (match-lambda
558 (($ <nginx-location-configuration> uri body)
559 (list
560 " location " uri " {\n"
561 (map (lambda (x) (list " " x "\n")) body)
562 " }\n"))
563 (($ <nginx-named-location-configuration> name body)
564 (list
565 " location @" name " {\n"
566 (map (lambda (x) (list " " x "\n")) body)
567 " }\n"))))
568
569 (define (emit-nginx-server-config server)
570 (let ((listen (nginx-server-configuration-listen server))
571 (server-name (nginx-server-configuration-server-name server))
572 (ssl-certificate (nginx-server-configuration-ssl-certificate server))
573 (ssl-certificate-key
574 (nginx-server-configuration-ssl-certificate-key server))
575 (root (nginx-server-configuration-root server))
576 (index (nginx-server-configuration-index server))
577 (try-files (nginx-server-configuration-try-files server))
578 (server-tokens? (nginx-server-configuration-server-tokens? server))
579 (locations (nginx-server-configuration-locations server))
580 (raw-content (nginx-server-configuration-raw-content server)))
581 (define-syntax-parameter <> (syntax-rules ()))
582 (define-syntax-rule (and/l x tail ...)
583 (let ((x* x))
584 (if x*
585 (syntax-parameterize ((<> (identifier-syntax x*)))
586 (list tail ...))
587 '())))
588 (list
589 " server {\n"
590 (map (lambda (directive) (list " listen " directive ";\n")) listen)
591 " server_name " (config-domain-strings server-name) ";\n"
592 (and/l ssl-certificate " ssl_certificate " <> ";\n")
593 (and/l ssl-certificate-key " ssl_certificate_key " <> ";\n")
594 " root " root ";\n"
595 " index " (config-index-strings index) ";\n"
596 (if (not (nil? try-files))
597 (and/l (config-index-strings try-files) " try_files " <> ";\n")
598 "")
599 " server_tokens " (if server-tokens? "on" "off") ";\n"
600 "\n"
601 (map emit-nginx-location-config locations)
602 "\n"
603 (map (lambda (x) (list " " x "\n")) raw-content)
604 " }\n")))
605
606 (define (emit-nginx-upstream-config upstream)
607 (list
608 " upstream " (nginx-upstream-configuration-name upstream) " {\n"
609 (map (lambda (server)
610 (simple-format #f " server ~A;\n" server))
611 (nginx-upstream-configuration-servers upstream))
612 " }\n"))
613
614 (define (flatten . lst)
615 "Return a list that recursively concatenates all sub-lists of LST."
616 (define (flatten1 head out)
617 (if (list? head)
618 (fold-right flatten1 out head)
619 (cons head out)))
620 (fold-right flatten1 '() lst))
621
622 (define (default-nginx-config config)
623 (match-record config
624 <nginx-configuration>
625 (nginx log-directory run-directory
626 server-blocks upstream-blocks
627 server-names-hash-bucket-size
628 server-names-hash-bucket-max-size
629 modules
630 global-directives
631 extra-content)
632 (apply mixed-text-file "nginx.conf"
633 (flatten
634 "user nginx nginx;\n"
635 "pid " run-directory "/pid;\n"
636 "error_log " log-directory "/error.log info;\n"
637 (map emit-load-module modules)
638 (map emit-global-directive global-directives)
639 "http {\n"
640 " client_body_temp_path " run-directory "/client_body_temp;\n"
641 " proxy_temp_path " run-directory "/proxy_temp;\n"
642 " fastcgi_temp_path " run-directory "/fastcgi_temp;\n"
643 " uwsgi_temp_path " run-directory "/uwsgi_temp;\n"
644 " scgi_temp_path " run-directory "/scgi_temp;\n"
645 " access_log " log-directory "/access.log;\n"
646 " include " nginx "/share/nginx/conf/mime.types;\n"
647 (if server-names-hash-bucket-size
648 (string-append
649 " server_names_hash_bucket_size "
650 (number->string server-names-hash-bucket-size)
651 ";\n")
652 "")
653 (if server-names-hash-bucket-max-size
654 (string-append
655 " server_names_hash_bucket_max_size "
656 (number->string server-names-hash-bucket-max-size)
657 ";\n")
658 "")
659 "\n"
660 (map emit-nginx-upstream-config upstream-blocks)
661 (map emit-nginx-server-config server-blocks)
662 extra-content
663 "\n}\n"))))
664
665 (define %nginx-accounts
666 (list (user-group (name "nginx") (system? #t))
667 (user-account
668 (name "nginx")
669 (group "nginx")
670 (system? #t)
671 (comment "nginx server user")
672 (home-directory "/var/empty")
673 (shell (file-append shadow "/sbin/nologin")))))
674
675 (define (nginx-activation config)
676 (match-record config
677 <nginx-configuration>
678 (nginx log-directory run-directory file)
679 #~(begin
680 (use-modules (guix build utils))
681
682 (format #t "creating nginx log directory '~a'~%" #$log-directory)
683 (mkdir-p #$log-directory)
684 (format #t "creating nginx run directory '~a'~%" #$run-directory)
685 (mkdir-p #$run-directory)
686 (format #t "creating nginx temp directories '~a/{client_body,proxy,fastcgi,uwsgi,scgi}_temp'~%" #$run-directory)
687 (mkdir-p (string-append #$run-directory "/client_body_temp"))
688 (mkdir-p (string-append #$run-directory "/proxy_temp"))
689 (mkdir-p (string-append #$run-directory "/fastcgi_temp"))
690 (mkdir-p (string-append #$run-directory "/uwsgi_temp"))
691 (mkdir-p (string-append #$run-directory "/scgi_temp"))
692 ;; Start-up logs. Once configuration is loaded, nginx switches to
693 ;; log-directory.
694 (mkdir-p (string-append #$run-directory "/logs"))
695 ;; Check configuration file syntax.
696 (system* (string-append #$nginx "/sbin/nginx")
697 "-c" #$(or file
698 (default-nginx-config config))
699 "-p" #$run-directory
700 "-t"))))
701
702 (define (nginx-shepherd-service config)
703 (match-record config
704 <nginx-configuration>
705 (nginx file run-directory)
706 (let* ((nginx-binary (file-append nginx "/sbin/nginx"))
707 (pid-file (in-vicinity run-directory "pid"))
708 (nginx-action
709 (lambda args
710 #~(lambda _
711 (invoke #$nginx-binary "-c"
712 #$(or file
713 (default-nginx-config config))
714 #$@args)
715 (match '#$args
716 (("-s" . _) #f)
717 (_
718 ;; When FILE is true, we cannot be sure that PID-FILE will
719 ;; be created, so assume it won't show up. When FILE is
720 ;; false, read PID-FILE.
721 #$(if file
722 #~#t
723 #~(read-pid-file #$pid-file))))))))
724
725 ;; TODO: Add 'reload' action.
726 (list (shepherd-service
727 (provision '(nginx))
728 (documentation "Run the nginx daemon.")
729 (requirement '(user-processes loopback))
730 (modules `((ice-9 match)
731 ,@%default-modules))
732 (start (nginx-action "-p" run-directory))
733 (stop (nginx-action "-s" "stop")))))))
734
735 (define nginx-service-type
736 (service-type (name 'nginx)
737 (extensions
738 (list (service-extension shepherd-root-service-type
739 nginx-shepherd-service)
740 (service-extension activation-service-type
741 nginx-activation)
742 (service-extension account-service-type
743 (const %nginx-accounts))))
744 (compose concatenate)
745 (extend (lambda (config servers)
746 (nginx-configuration
747 (inherit config)
748 (server-blocks
749 (append (nginx-configuration-server-blocks config)
750 servers)))))
751 (default-value (nginx-configuration))
752 (description "Run the nginx Web server.")))
753
754 (define-record-type* <fcgiwrap-configuration> fcgiwrap-configuration
755 make-fcgiwrap-configuration
756 fcgiwrap-configuration?
757 (package fcgiwrap-configuration-package ;<package>
758 (default fcgiwrap))
759 (socket fcgiwrap-configuration-socket
760 (default "tcp:127.0.0.1:9000"))
761 (user fcgiwrap-configuration-user
762 (default "fcgiwrap"))
763 (group fcgiwrap-configuration-group
764 (default "fcgiwrap")))
765
766 (define fcgiwrap-accounts
767 (match-lambda
768 (($ <fcgiwrap-configuration> package socket user group)
769 (filter identity
770 (list
771 (and (equal? group "fcgiwrap")
772 (user-group
773 (name "fcgiwrap")
774 (system? #t)))
775 (and (equal? user "fcgiwrap")
776 (user-account
777 (name "fcgiwrap")
778 (group group)
779 (system? #t)
780 (comment "Fcgiwrap Daemon")
781 (home-directory "/var/empty")
782 (shell (file-append shadow "/sbin/nologin")))))))))
783
784 (define fcgiwrap-shepherd-service
785 (match-lambda
786 (($ <fcgiwrap-configuration> package socket user group)
787 (list (shepherd-service
788 (provision '(fcgiwrap))
789 (documentation "Run the fcgiwrap daemon.")
790 (requirement '(networking))
791 (start #~(make-forkexec-constructor
792 '(#$(file-append package "/sbin/fcgiwrap")
793 "-s" #$socket)
794 #:user #$user #:group #$group))
795 (stop #~(make-kill-destructor)))))))
796
797 (define fcgiwrap-service-type
798 (service-type (name 'fcgiwrap)
799 (extensions
800 (list (service-extension shepherd-root-service-type
801 fcgiwrap-shepherd-service)
802 (service-extension account-service-type
803 fcgiwrap-accounts)))
804 (default-value (fcgiwrap-configuration))))
805
806 (define-record-type* <php-fpm-configuration> php-fpm-configuration
807 make-php-fpm-configuration
808 php-fpm-configuration?
809 (php php-fpm-configuration-php ;<package>
810 (default php))
811 (socket php-fpm-configuration-socket
812 (default (string-append "/var/run/php"
813 (version-major (package-version php))
814 "-fpm.sock")))
815 (user php-fpm-configuration-user
816 (default "php-fpm"))
817 (group php-fpm-configuration-group
818 (default "php-fpm"))
819 (socket-user php-fpm-configuration-socket-user
820 (default "php-fpm"))
821 (socket-group php-fpm-configuration-socket-group
822 (default "nginx"))
823 (pid-file php-fpm-configuration-pid-file
824 (default (string-append "/var/run/php"
825 (version-major (package-version php))
826 "-fpm.pid")))
827 (log-file php-fpm-configuration-log-file
828 (default (string-append "/var/log/php"
829 (version-major (package-version php))
830 "-fpm.log")))
831 (process-manager php-fpm-configuration-process-manager
832 (default (php-fpm-dynamic-process-manager-configuration)))
833 (display-errors php-fpm-configuration-display-errors
834 (default #f))
835 (timezone php-fpm-configuration-timezone
836 (default #f))
837 (workers-log-file php-fpm-configuration-workers-log-file
838 (default (string-append "/var/log/php"
839 (version-major (package-version php))
840 "-fpm.www.log")))
841 (file php-fpm-configuration-file ;#f | file-like
842 (default #f)))
843
844 (define-record-type* <php-fpm-dynamic-process-manager-configuration>
845 php-fpm-dynamic-process-manager-configuration
846 make-php-fpm-dynamic-process-manager-configuration
847 php-fpm-dynamic-process-manager-configuration?
848 (max-children php-fpm-dynamic-process-manager-configuration-max-children
849 (default 5))
850 (start-servers php-fpm-dynamic-process-manager-configuration-start-servers
851 (default 2))
852 (min-spare-servers php-fpm-dynamic-process-manager-configuration-min-spare-servers
853 (default 1))
854 (max-spare-servers php-fpm-dynamic-process-manager-configuration-max-spare-servers
855 (default 3)))
856
857 (define-record-type* <php-fpm-static-process-manager-configuration>
858 php-fpm-static-process-manager-configuration
859 make-php-fpm-static-process-manager-configuration
860 php-fpm-static-process-manager-configuration?
861 (max-children php-fpm-static-process-manager-configuration-max-children
862 (default 5)))
863
864 (define-record-type* <php-fpm-on-demand-process-manager-configuration>
865 php-fpm-on-demand-process-manager-configuration
866 make-php-fpm-on-demand-process-manager-configuration
867 php-fpm-on-demand-process-manager-configuration?
868 (max-children php-fpm-on-demand-process-manager-configuration-max-children
869 (default 5))
870 (process-idle-timeout php-fpm-on-demand-process-manager-configuration-process-idle-timeout
871 (default 10)))
872
873 (define php-fpm-accounts
874 (match-lambda
875 (($ <php-fpm-configuration> php socket user group socket-user socket-group _ _ _ _ _ _)
876 (list
877 (user-group (name "php-fpm") (system? #t))
878 (user-group
879 (name group)
880 (system? #t))
881 (user-account
882 (name user)
883 (group group)
884 (supplementary-groups '("php-fpm"))
885 (system? #t)
886 (comment "php-fpm daemon user")
887 (home-directory "/var/empty")
888 (shell (file-append shadow "/sbin/nologin")))))))
889
890 (define (default-php-fpm-config socket user group socket-user socket-group
891 pid-file log-file pm display-errors timezone workers-log-file)
892 (apply mixed-text-file "php-fpm.conf"
893 (flatten
894 "[global]\n"
895 "pid =" pid-file "\n"
896 "error_log =" log-file "\n"
897 "[www]\n"
898 "user =" user "\n"
899 "group =" group "\n"
900 "listen =" socket "\n"
901 "listen.owner =" socket-user "\n"
902 "listen.group =" socket-group "\n"
903
904 (if timezone
905 (string-append "php_admin_value[date.timezone] = \"" timezone "\"\n")
906 "")
907
908 (match pm
909 (($ <php-fpm-dynamic-process-manager-configuration>
910 pm.max-children
911 pm.start-servers
912 pm.min-spare-servers
913 pm.max-spare-servers)
914 (list
915 "pm = dynamic\n"
916 "pm.max_children =" (number->string pm.max-children) "\n"
917 "pm.start_servers =" (number->string pm.start-servers) "\n"
918 "pm.min_spare_servers =" (number->string pm.min-spare-servers) "\n"
919 "pm.max_spare_servers =" (number->string pm.max-spare-servers) "\n"))
920
921 (($ <php-fpm-static-process-manager-configuration>
922 pm.max-children)
923 (list
924 "pm = static\n"
925 "pm.max_children =" (number->string pm.max-children) "\n"))
926
927 (($ <php-fpm-on-demand-process-manager-configuration>
928 pm.max-children
929 pm.process-idle-timeout)
930 (list
931 "pm = ondemand\n"
932 "pm.max_children =" (number->string pm.max-children) "\n"
933 "pm.process_idle_timeout =" (number->string pm.process-idle-timeout) "s\n")))
934
935
936 "php_flag[display_errors] = " (if display-errors "on" "off") "\n"
937
938 (if workers-log-file
939 (list "catch_workers_output = yes\n"
940 "php_admin_value[error_log] =" workers-log-file "\n"
941 "php_admin_flag[log_errors] = on\n")
942 (list "catch_workers_output = no\n")))))
943
944 (define php-fpm-shepherd-service
945 (match-lambda
946 (($ <php-fpm-configuration> php socket user group socket-user socket-group
947 pid-file log-file pm display-errors
948 timezone workers-log-file file)
949 (list (shepherd-service
950 (provision '(php-fpm))
951 (documentation "Run the php-fpm daemon.")
952 (requirement '(networking))
953 (start #~(make-forkexec-constructor
954 '(#$(file-append php "/sbin/php-fpm")
955 "--fpm-config"
956 #$(or file
957 (default-php-fpm-config socket user group
958 socket-user socket-group pid-file log-file
959 pm display-errors timezone workers-log-file)))
960 #:pid-file #$pid-file))
961 (stop #~(make-kill-destructor)))))))
962
963 (define (php-fpm-activation config)
964 #~(begin
965 (use-modules (guix build utils))
966 (let* ((user (getpwnam #$(php-fpm-configuration-user config)))
967 (touch (lambda (file-name)
968 (call-with-output-file file-name (const #t))))
969 (workers-log-file
970 #$(php-fpm-configuration-workers-log-file config))
971 (init-log-file
972 (lambda (file-name)
973 (when workers-log-file
974 (when (not (file-exists? file-name))
975 (touch file-name))
976 (chown file-name (passwd:uid user) (passwd:gid user))
977 (chmod file-name #o660)))))
978 (init-log-file #$(php-fpm-configuration-log-file config))
979 (init-log-file workers-log-file))))
980
981
982 (define php-fpm-service-type
983 (service-type
984 (name 'php-fpm)
985 (description
986 "Run @command{php-fpm} to provide a fastcgi socket for calling php through
987 a webserver.")
988 (extensions
989 (list (service-extension shepherd-root-service-type
990 php-fpm-shepherd-service)
991 (service-extension activation-service-type
992 php-fpm-activation)
993 (service-extension account-service-type
994 php-fpm-accounts)))
995 (default-value (php-fpm-configuration))))
996
997 (define* (nginx-php-location
998 #:key
999 (nginx-package nginx)
1000 (socket (string-append "/var/run/php"
1001 (version-major (package-version php))
1002 "-fpm.sock")))
1003 "Return a nginx-location-configuration that makes nginx run .php files."
1004 (nginx-location-configuration
1005 (uri "~ \\.php$")
1006 (body (list
1007 "fastcgi_split_path_info ^(.+\\.php)(/.+)$;"
1008 (string-append "fastcgi_pass unix:" socket ";")
1009 "fastcgi_index index.php;"
1010 (list "include " nginx-package "/share/nginx/conf/fastcgi.conf;")))))
1011
1012 (define* (cat-avatar-generator-service
1013 #:key
1014 (cache-dir "/var/cache/cat-avatar-generator")
1015 (package cat-avatar-generator)
1016 (configuration (nginx-server-configuration)))
1017 (simple-service
1018 'cat-http-server nginx-service-type
1019 (list (nginx-server-configuration
1020 (inherit configuration)
1021 (locations
1022 (cons
1023 (let ((base (nginx-php-location)))
1024 (nginx-location-configuration
1025 (inherit base)
1026 (body (list (string-append "fastcgi_param CACHE_DIR \""
1027 cache-dir "\";")
1028 (nginx-location-configuration-body base)))))
1029 (nginx-server-configuration-locations configuration)))
1030 (root #~(string-append #$package
1031 "/share/web/cat-avatar-generator"))))))
1032
1033 \f
1034 (define-record-type* <hpcguix-web-configuration>
1035 hpcguix-web-configuration make-hpcguix-web-configuration
1036 hpcguix-web-configuration?
1037
1038 (package hpcguix-web-package (default hpcguix-web)) ;<package>
1039
1040 ;; Specs is gexp of hpcguix-web configuration file
1041 (specs hpcguix-web-configuration-specs))
1042
1043 (define %hpcguix-web-accounts
1044 (list (user-group
1045 (name "hpcguix-web")
1046 (system? #t))
1047 (user-account
1048 (name "hpcguix-web")
1049 (group "hpcguix-web")
1050 (system? #t)
1051 (comment "hpcguix-web")
1052 (home-directory "/var/empty")
1053 (shell (file-append shadow "/sbin/nologin")))))
1054
1055 (define %hpcguix-web-activation
1056 (with-imported-modules '((guix build utils))
1057 #~(begin
1058 (use-modules (guix build utils)
1059 (ice-9 ftw))
1060
1061 (let ((home-dir "/var/cache/guix/web")
1062 (user (getpwnam "hpcguix-web")))
1063 (mkdir-p home-dir)
1064 (chown home-dir (passwd:uid user) (passwd:gid user))
1065 (chmod home-dir #o755)
1066
1067 ;; Remove stale 'packages.json.lock' file (and other lock files, if
1068 ;; any) since that would prevent 'packages.json' from being updated.
1069 (for-each (lambda (lock)
1070 (delete-file (string-append home-dir "/" lock)))
1071 (scandir home-dir
1072 (lambda (file)
1073 (string-suffix? ".lock" file))))))))
1074
1075 (define %hpcguix-web-log-file
1076 "/var/log/hpcguix-web.log")
1077
1078 (define %hpcguix-web-log-rotations
1079 (list (log-rotation
1080 (files (list %hpcguix-web-log-file))
1081 (frequency 'weekly))))
1082
1083 (define (hpcguix-web-shepherd-service config)
1084 (let ((specs (hpcguix-web-configuration-specs config))
1085 (hpcguix-web (hpcguix-web-package config)))
1086 (with-imported-modules (source-module-closure
1087 '((gnu build shepherd)))
1088 (shepherd-service
1089 (documentation "hpcguix-web daemon")
1090 (provision '(hpcguix-web))
1091 (requirement '(networking))
1092 (start #~(make-forkexec-constructor
1093 (list #$(file-append hpcguix-web "/bin/run")
1094 (string-append "--config="
1095 #$(scheme-file "hpcguix-web.scm" specs)))
1096 #:user "hpcguix-web"
1097 #:group "hpcguix-web"
1098 #:environment-variables
1099 (list "XDG_CACHE_HOME=/var/cache"
1100 "SSL_CERT_DIR=/etc/ssl/certs")
1101 #:log-file #$%hpcguix-web-log-file))
1102 (stop #~(make-kill-destructor))))))
1103
1104 (define hpcguix-web-service-type
1105 (service-type
1106 (name 'hpcguix-web)
1107 (description "Run the hpcguix-web server.")
1108 (extensions
1109 (list (service-extension account-service-type
1110 (const %hpcguix-web-accounts))
1111 (service-extension activation-service-type
1112 (const %hpcguix-web-activation))
1113 (service-extension rottlog-service-type
1114 (const %hpcguix-web-log-rotations))
1115 (service-extension shepherd-root-service-type
1116 (compose list hpcguix-web-shepherd-service))))))
1117
1118 \f
1119 ;;;
1120 ;;; Tailon
1121 ;;;
1122
1123 (define-record-type* <tailon-configuration-file>
1124 tailon-configuration-file make-tailon-configuration-file
1125 tailon-configuration-file?
1126 (files tailon-configuration-file-files
1127 (default '("/var/log")))
1128 (bind tailon-configuration-file-bind
1129 (default "localhost:8080"))
1130 (relative-root tailon-configuration-file-relative-root
1131 (default #f))
1132 (allow-transfers? tailon-configuration-file-allow-transfers?
1133 (default #t))
1134 (follow-names? tailon-configuration-file-follow-names?
1135 (default #t))
1136 (tail-lines tailon-configuration-file-tail-lines
1137 (default 200))
1138 (allowed-commands tailon-configuration-file-allowed-commands
1139 (default '("tail" "grep" "awk")))
1140 (debug? tailon-configuration-file-debug?
1141 (default #f))
1142 (wrap-lines tailon-configuration-file-wrap-lines
1143 (default #t))
1144 (http-auth tailon-configuration-file-http-auth
1145 (default #f))
1146 (users tailon-configuration-file-users
1147 (default #f)))
1148
1149 (define (tailon-configuration-files-string files)
1150 (string-append
1151 "\n"
1152 (string-join
1153 (map
1154 (lambda (x)
1155 (string-append
1156 " - "
1157 (cond
1158 ((string? x)
1159 (simple-format #f "'~A'" x))
1160 ((list? x)
1161 (string-join
1162 (cons (simple-format #f "'~A':" (car x))
1163 (map
1164 (lambda (x) (simple-format #f " - '~A'" x))
1165 (cdr x)))
1166 "\n"))
1167 (else (error x)))))
1168 files)
1169 "\n")))
1170
1171 (define-gexp-compiler (tailon-configuration-file-compiler
1172 (file <tailon-configuration-file>) system target)
1173 (match file
1174 (($ <tailon-configuration-file> files bind relative-root
1175 allow-transfers? follow-names?
1176 tail-lines allowed-commands debug?
1177 wrap-lines http-auth users)
1178 (text-file
1179 "tailon-config.yaml"
1180 (string-concatenate
1181 (filter-map
1182 (match-lambda
1183 ((key . #f) #f)
1184 ((key . value) (string-append key ": " value "\n")))
1185
1186 `(("files" . ,(tailon-configuration-files-string files))
1187 ("bind" . ,bind)
1188 ("relative-root" . ,relative-root)
1189 ("allow-transfers" . ,(if allow-transfers? "true" "false"))
1190 ("follow-names" . ,(if follow-names? "true" "false"))
1191 ("tail-lines" . ,(number->string tail-lines))
1192 ("commands" . ,(string-append "["
1193 (string-join allowed-commands ", ")
1194 "]"))
1195 ("debug" . ,(if debug? "true" #f))
1196 ("wrap-lines" . ,(if wrap-lines "true" "false"))
1197 ("http-auth" . ,http-auth)
1198 ("users" . ,(if users
1199 (string-concatenate
1200 (cons "\n"
1201 (map (match-lambda
1202 ((user . pass)
1203 (string-append
1204 " " user ":" pass)))
1205 users)))
1206 #f)))))))))
1207
1208 (define-record-type* <tailon-configuration>
1209 tailon-configuration make-tailon-configuration
1210 tailon-configuration?
1211 (config-file tailon-configuration-config-file
1212 (default (tailon-configuration-file)))
1213 (package tailon-configuration-package
1214 (default tailon)))
1215
1216 (define tailon-shepherd-service
1217 (match-lambda
1218 (($ <tailon-configuration> config-file package)
1219 (list (shepherd-service
1220 (provision '(tailon))
1221 (documentation "Run the tailon daemon.")
1222 (start #~(make-forkexec-constructor
1223 `(,(string-append #$package "/bin/tailon")
1224 "-c" ,#$config-file)
1225 #:user "tailon"
1226 #:group "tailon"))
1227 (stop #~(make-kill-destructor)))))))
1228
1229 (define %tailon-accounts
1230 (list (user-group (name "tailon") (system? #t))
1231 (user-account
1232 (name "tailon")
1233 (group "tailon")
1234 (system? #t)
1235 (comment "tailon")
1236 (home-directory "/var/empty")
1237 (shell (file-append shadow "/sbin/nologin")))))
1238
1239 (define tailon-service-type
1240 (service-type
1241 (name 'tailon)
1242 (description
1243 "Run Tailon, a Web application for monitoring, viewing, and searching log
1244 files.")
1245 (extensions
1246 (list (service-extension shepherd-root-service-type
1247 tailon-shepherd-service)
1248 (service-extension account-service-type
1249 (const %tailon-accounts))))
1250 (compose concatenate)
1251 (extend (lambda (parameter files)
1252 (tailon-configuration
1253 (inherit parameter)
1254 (config-file
1255 (let ((old-config-file
1256 (tailon-configuration-config-file parameter)))
1257 (tailon-configuration-file
1258 (inherit old-config-file)
1259 (files (append (tailon-configuration-file-files old-config-file)
1260 files))))))))
1261 (default-value (tailon-configuration))))
1262
1263 \f
1264 ;;;
1265 ;;; Varnish
1266 ;;;
1267
1268 (define-record-type* <varnish-configuration>
1269 varnish-configuration make-varnish-configuration
1270 varnish-configuration?
1271 (package varnish-configuration-package ;<package>
1272 (default varnish))
1273 (name varnish-configuration-name ;string
1274 (default "default"))
1275 (backend varnish-configuration-backend ;string
1276 (default "localhost:8080"))
1277 (vcl varnish-configuration-vcl ;#f | <file-like>
1278 (default #f))
1279 (listen varnish-configuration-listen ;list of strings
1280 (default '("localhost:80")))
1281 (storage varnish-configuration-storage ;list of strings
1282 (default '("malloc,128m")))
1283 (parameters varnish-configuration-parameters ;list of string pairs
1284 (default '()))
1285 (extra-options varnish-configuration-extra-options ;list of strings
1286 (default '())))
1287
1288 (define %varnish-accounts
1289 (list (user-group
1290 (name "varnish")
1291 (system? #t))
1292 (user-account
1293 (name "varnish")
1294 (group "varnish")
1295 (system? #t)
1296 (comment "Varnish Cache User")
1297 (home-directory "/var/varnish")
1298 (shell (file-append shadow "/sbin/nologin")))))
1299
1300 (define varnish-shepherd-service
1301 (match-lambda
1302 (($ <varnish-configuration> package name backend vcl listen storage
1303 parameters extra-options)
1304 (list (shepherd-service
1305 (provision (list (symbol-append 'varnish- (string->symbol name))))
1306 (documentation (string-append "The Varnish Web Accelerator"
1307 " (" name ")"))
1308 (requirement '(networking))
1309 (start #~(make-forkexec-constructor
1310 (list #$(file-append package "/sbin/varnishd")
1311 "-n" #$name
1312 #$@(if vcl
1313 #~("-f" #$vcl)
1314 #~("-b" #$backend))
1315 #$@(append-map (lambda (a) (list "-a" a)) listen)
1316 #$@(append-map (lambda (s) (list "-s" s)) storage)
1317 #$@(append-map (lambda (p)
1318 (list "-p" (format #f "~a=~a"
1319 (car p) (cdr p))))
1320 parameters)
1321 #$@extra-options)
1322 ;; Varnish will drop privileges to the "varnish" user when
1323 ;; it exists. Not passing #:user here allows the service
1324 ;; to bind to ports < 1024.
1325 #:pid-file (if (string-prefix? "/" #$name)
1326 (string-append #$name "/_.pid")
1327 (string-append "/var/varnish/" #$name "/_.pid"))))
1328 (stop #~(make-kill-destructor)))))))
1329
1330 (define varnish-service-type
1331 (service-type
1332 (name 'varnish)
1333 (description "Run the Varnish cache server.")
1334 (extensions
1335 (list (service-extension account-service-type
1336 (const %varnish-accounts))
1337 (service-extension shepherd-root-service-type
1338 varnish-shepherd-service)))
1339 (default-value
1340 (varnish-configuration))))
1341
1342 \f
1343 ;;;
1344 ;;; Patchwork
1345 ;;;
1346
1347 (define-record-type* <patchwork-database-configuration>
1348 patchwork-database-configuration make-patchwork-database-configuration
1349 patchwork-database-configuration?
1350 (engine patchwork-database-configuration-engine
1351 (default "django.db.backends.postgresql_psycopg2"))
1352 (name patchwork-database-configuration-name
1353 (default "patchwork"))
1354 (user patchwork-database-configuration-user
1355 (default "httpd"))
1356 (password patchwork-database-configuration-password
1357 (default ""))
1358 (host patchwork-database-configuration-host
1359 (default ""))
1360 (port patchwork-database-configuration-port
1361 (default "")))
1362
1363 (define-record-type* <patchwork-settings-module>
1364 patchwork-settings-module make-patchwork-settings-module
1365 patchwork-settings-module?
1366 (database-configuration patchwork-settings-module-database-configuration
1367 (default (patchwork-database-configuration)))
1368 (secret-key-file patchwork-settings-module-secret-key-file
1369 (default "/etc/patchwork/django-secret-key"))
1370 (allowed-hosts patchwork-settings-module-allowed-hosts)
1371 (default-from-email patchwork-settings-module-default-from-email)
1372 (static-url patchwork-settings-module-static-url
1373 (default "/static/"))
1374 (admins patchwork-settings-module-admins
1375 (default '()))
1376 (debug? patchwork-settings-module-debug?
1377 (default #f))
1378 (enable-rest-api? patchwork-settings-module-enable-rest-api?
1379 (default #t))
1380 (enable-xmlrpc? patchwork-settings-module-enable-xmlrpc?
1381 (default #t))
1382 (force-https-links? patchwork-settings-module-force-https-links?
1383 (default #t))
1384 (extra-settings patchwork-settings-module-extra-settings
1385 (default "")))
1386
1387 (define-record-type* <patchwork-configuration>
1388 patchwork-configuration make-patchwork-configuration
1389 patchwork-configuration?
1390 (patchwork patchwork-configuration-patchwork
1391 (default patchwork))
1392 (domain patchwork-configuration-domain)
1393 (settings-module patchwork-configuration-settings-module)
1394 (static-path patchwork-configuration-static-url
1395 (default "/static/"))
1396 (getmail-retriever-config getmail-retriever-config))
1397
1398 ;; Django uses a Python module for configuration, so this compiler generates a
1399 ;; Python module from the configuration record.
1400 (define-gexp-compiler (patchwork-settings-module-compiler
1401 (file <patchwork-settings-module>) system target)
1402 (match file
1403 (($ <patchwork-settings-module> database-configuration secret-key-file
1404 allowed-hosts default-from-email
1405 static-url admins debug? enable-rest-api?
1406 enable-xmlrpc? force-https-links?
1407 extra-configuration)
1408 (gexp->derivation
1409 "patchwork-settings"
1410 (with-imported-modules '((guix build utils))
1411 #~(let ((output #$output))
1412 (define (create-__init__.py filename)
1413 (call-with-output-file filename
1414 (lambda (port) (display "" port))))
1415
1416 (use-modules (guix build utils)
1417 (srfi srfi-1))
1418
1419 (mkdir-p (string-append output "/guix/patchwork"))
1420 (create-__init__.py
1421 (string-append output "/guix/__init__.py"))
1422 (create-__init__.py
1423 (string-append output "/guix/patchwork/__init__.py"))
1424
1425 (call-with-output-file
1426 (string-append output "/guix/patchwork/settings.py")
1427 (lambda (port)
1428 (display
1429 (string-append "from patchwork.settings.base import *
1430
1431 # Configuration from Guix
1432 with open('" #$secret-key-file "') as f:
1433 SECRET_KEY = f.read().strip()
1434
1435 ALLOWED_HOSTS = [
1436 " #$(string-concatenate
1437 (map (lambda (allowed-host)
1438 (string-append " '" allowed-host "'\n"))
1439 allowed-hosts))
1440 "]
1441
1442 DEFAULT_FROM_EMAIL = '" #$default-from-email "'
1443 SERVER_EMAIL = DEFAULT_FROM_EMAIL
1444 NOTIFICATION_FROM_EMAIL = DEFAULT_FROM_EMAIL
1445
1446 ADMINS = [
1447 " #$(string-concatenate
1448 (map (match-lambda
1449 ((name email-address)
1450 (string-append
1451 "('" name "','" email-address "'),")))
1452 admins))
1453 "]
1454
1455 DEBUG = " #$(if debug? "True" "False") "
1456
1457 ENABLE_REST_API = " #$(if enable-rest-api? "True" "False") "
1458 ENABLE_XMLRPC = " #$(if enable-xmlrpc? "True" "False") "
1459
1460 FORCE_HTTPS_LINKS = " #$(if force-https-links? "True" "False") "
1461
1462 DATABASES = {
1463 'default': {
1464 " #$(match database-configuration
1465 (($ <patchwork-database-configuration>
1466 engine name user password host port)
1467 (string-append
1468 " 'ENGINE': '" engine "',\n"
1469 " 'NAME': '" name "',\n"
1470 " 'USER': '" user "',\n"
1471 " 'PASSWORD': '" password "',\n"
1472 " 'HOST': '" host "',\n"
1473 " 'PORT': '" port "',\n"))) "
1474 },
1475 }
1476
1477 " #$(if debug?
1478 #~(string-append "STATIC_ROOT = '"
1479 #$(file-append patchwork "/share/patchwork/htdocs")
1480 "'")
1481 #~(string-append "STATIC_URL = '" #$static-url "'")) "
1482
1483 STATICFILES_STORAGE = (
1484 'django.contrib.staticfiles.storage.StaticFilesStorage'
1485 )
1486
1487 # Guix Extra Configuration
1488 " #$extra-configuration "
1489 ") port)))
1490 #t))
1491 #:local-build? #t))))
1492
1493 (define patchwork-virtualhost
1494 (match-lambda
1495 (($ <patchwork-configuration> patchwork domain
1496 settings-module static-path
1497 getmail-retriever-config)
1498 (define wsgi.py
1499 (file-append patchwork
1500 (string-append
1501 "/lib/python"
1502 (version-major+minor
1503 (package-version python))
1504 "/site-packages/patchwork/wsgi.py")))
1505
1506 (httpd-virtualhost
1507 "*:8080"
1508 `("ServerAdmin admin@example.com`
1509 ServerName " ,domain "
1510
1511 LogFormat \"%v %h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\" customformat
1512 LogLevel info
1513 CustomLog \"/var/log/httpd/" ,domain "-access_log\" customformat
1514
1515 ErrorLog /var/log/httpd/error.log
1516
1517 WSGIScriptAlias / " ,wsgi.py "
1518 WSGIDaemonProcess " ,(package-name patchwork) " user=httpd group=httpd processes=1 threads=2 display-name=%{GROUP} lang='en_US.UTF-8' locale='en_US.UTF-8' python-path=" ,settings-module "
1519 WSGIProcessGroup " ,(package-name patchwork) "
1520 WSGIPassAuthorization On
1521
1522 <Files " ,wsgi.py ">
1523 Require all granted
1524 </Files>
1525
1526 " ,@(if static-path
1527 `("Alias " ,static-path " " ,patchwork "/share/patchwork/htdocs/")
1528 '())
1529 "
1530 <Directory \"/srv/http/" ,domain "/\">
1531 AllowOverride None
1532 Options MultiViews Indexes SymlinksIfOwnerMatch IncludesNoExec
1533 Require method GET POST OPTIONS
1534 </Directory>")))))
1535
1536 (define (patchwork-httpd-configuration patchwork-configuration)
1537 (list "WSGISocketPrefix /var/run/mod_wsgi"
1538 (list "LoadModule wsgi_module "
1539 (file-append mod-wsgi "/modules/mod_wsgi.so"))
1540 (patchwork-virtualhost patchwork-configuration)))
1541
1542 (define (patchwork-django-admin-gexp patchwork settings-module)
1543 #~(lambda command
1544 (let ((pid (primitive-fork))
1545 (user (getpwnam "httpd")))
1546 (if (eq? pid 0)
1547 (dynamic-wind
1548 (const #t)
1549 (lambda ()
1550 (setgid (passwd:gid user))
1551 (setuid (passwd:uid user))
1552
1553 (setenv "DJANGO_SETTINGS_MODULE" "guix.patchwork.settings")
1554 (setenv "PYTHONPATH" #$settings-module)
1555 (primitive-exit
1556 (if (zero?
1557 (apply system*
1558 #$(file-append patchwork "/bin/patchwork-admin")
1559 command))
1560 0
1561 1)))
1562 (lambda ()
1563 (primitive-exit 1)))
1564 (zero? (cdr (waitpid pid)))))))
1565
1566 (define (patchwork-django-admin-action patchwork settings-module)
1567 (shepherd-action
1568 (name 'django-admin)
1569 (documentation
1570 "Run a django admin command for patchwork")
1571 (procedure (patchwork-django-admin-gexp patchwork settings-module))))
1572
1573 (define patchwork-shepherd-services
1574 (match-lambda
1575 (($ <patchwork-configuration> patchwork domain
1576 settings-module static-path
1577 getmail-retriever-config)
1578 (define secret-key-file-creation-gexp
1579 (if (patchwork-settings-module? settings-module)
1580 (with-extensions (list guile-gcrypt)
1581 #~(let ((secret-key-file
1582 #$(patchwork-settings-module-secret-key-file
1583 settings-module)))
1584 (use-modules (guix build utils)
1585 (gcrypt random))
1586
1587 (unless (file-exists? secret-key-file)
1588 (mkdir-p (dirname secret-key-file))
1589 (call-with-output-file secret-key-file
1590 (lambda (port)
1591 (display (random-token 30 'very-strong) port)))
1592 (let* ((pw (getpwnam "httpd"))
1593 (uid (passwd:uid pw))
1594 (gid (passwd:gid pw)))
1595 (chown secret-key-file uid gid)
1596 (chmod secret-key-file #o400)))))
1597 #~()))
1598
1599 (list (shepherd-service
1600 (requirement '(postgres))
1601 (provision (list (string->symbol
1602 (string-append (package-name patchwork)
1603 "-setup"))))
1604 (start
1605 #~(lambda ()
1606 (define run-django-admin-command
1607 #$(patchwork-django-admin-gexp patchwork
1608 settings-module))
1609
1610 #$secret-key-file-creation-gexp
1611
1612 (run-django-admin-command "migrate")))
1613 (stop #~(const #f))
1614 (actions
1615 (list (patchwork-django-admin-action patchwork
1616 settings-module)))
1617 (respawn? #f)
1618 (documentation "Setup Patchwork."))))))
1619
1620 (define patchwork-getmail-configs
1621 (match-lambda
1622 (($ <patchwork-configuration> patchwork domain
1623 settings-module static-path
1624 getmail-retriever-config)
1625 (list
1626 (getmail-configuration
1627 (name (string->symbol (package-name patchwork)))
1628 (user "httpd")
1629 (directory (string-append
1630 "/var/lib/getmail/" (package-name patchwork)))
1631 (rcfile
1632 (getmail-configuration-file
1633 (retriever getmail-retriever-config)
1634 (destination
1635 (getmail-destination-configuration
1636 (type "MDA_external")
1637 (path (file-append patchwork "/bin/patchwork-admin"))
1638 (extra-parameters
1639 '((arguments . ("parsemail"))))))
1640 (options
1641 (getmail-options-configuration
1642 (read-all #f)
1643 (delivered-to #f)
1644 (received #f)))))
1645 (idle (assq-ref
1646 (getmail-retriever-configuration-extra-parameters
1647 getmail-retriever-config)
1648 'mailboxes))
1649 (environment-variables
1650 (list "DJANGO_SETTINGS_MODULE=guix.patchwork.settings"
1651 #~(string-append "PYTHONPATH=" #$settings-module))))))))
1652
1653 (define patchwork-service-type
1654 (service-type
1655 (name 'patchwork-setup)
1656 (extensions
1657 (list (service-extension httpd-service-type
1658 patchwork-httpd-configuration)
1659 (service-extension shepherd-root-service-type
1660 patchwork-shepherd-services)
1661 (service-extension getmail-service-type
1662 patchwork-getmail-configs)))
1663 (description
1664 "Patchwork patch tracking system.")))
1665
1666 \f
1667 ;;;
1668 ;;; Mumi.
1669 ;;;
1670
1671 (define-record-type* <mumi-configuration>
1672 mumi-configuration make-mumi-configuration
1673 mumi-configuration?
1674 (mumi mumi-configuration-mumi (default mumi))
1675 (mailer? mumi-configuration-mailer? (default #t))
1676 (sender mumi-configuration-sender (default #f))
1677 (smtp mumi-configuration-smtp (default #f)))
1678
1679 (define %mumi-activation
1680 (with-imported-modules '((guix build utils))
1681 #~(begin
1682 (use-modules (guix build utils))
1683
1684 (mkdir-p "/var/mumi/db")
1685 (mkdir-p "/var/mumi/mails")
1686 (let* ((pw (getpwnam "mumi"))
1687 (uid (passwd:uid pw))
1688 (gid (passwd:gid pw)))
1689 (chown "/var/mumi" uid gid)
1690 (chown "/var/mumi/mails" uid gid)
1691 (chown "/var/mumi/db" uid gid)))))
1692
1693 (define %mumi-accounts
1694 (list (user-group (name "mumi") (system? #t))
1695 (user-account
1696 (name "mumi")
1697 (group "mumi")
1698 (system? #t)
1699 (comment "Mumi web server")
1700 (home-directory "/var/empty")
1701 (shell (file-append shadow "/sbin/nologin")))))
1702
1703 (define (mumi-shepherd-services config)
1704 (define environment
1705 #~(list "LC_ALL=en_US.utf8"
1706 (string-append "GUIX_LOCPATH=" #$glibc-utf8-locales
1707 "/lib/locale")))
1708
1709 (match config
1710 (($ <mumi-configuration> mumi mailer? sender smtp)
1711 (list (shepherd-service
1712 (provision '(mumi))
1713 (documentation "Mumi bug-tracking web interface.")
1714 (requirement '(networking))
1715 (start #~(make-forkexec-constructor
1716 `(#$(file-append mumi "/bin/mumi") "web"
1717 ,@(if #$mailer? '() '("--disable-mailer")))
1718 #:environment-variables #$environment
1719 #:user "mumi" #:group "mumi"
1720 #:log-file "/var/log/mumi.log"))
1721 (stop #~(make-kill-destructor)))
1722 (shepherd-service
1723 (provision '(mumi-worker))
1724 (documentation "Mumi bug-tracking web interface database worker.")
1725 (requirement '(networking))
1726 (start #~(make-forkexec-constructor
1727 '(#$(file-append mumi "/bin/mumi") "worker")
1728 #:environment-variables #$environment
1729 #:user "mumi" #:group "mumi"
1730 #:log-file "/var/log/mumi.worker.log"))
1731 (stop #~(make-kill-destructor)))
1732 (shepherd-service
1733 (provision '(mumi-mailer))
1734 (documentation "Mumi bug-tracking web interface mailer.")
1735 (requirement '(networking))
1736 (start #~(make-forkexec-constructor
1737 `(#$(file-append mumi "/bin/mumi") "mailer"
1738 ,@(if #$sender
1739 (list (string-append "--sender=" #$sender))
1740 '())
1741 ,@(if #$smtp
1742 (list (string-append "--smtp=" #$smtp))
1743 '()))
1744 #:environment-variables #$environment
1745 #:user "mumi" #:group "mumi"
1746 #:log-file "/var/log/mumi.mailer.log"))
1747 (stop #~(make-kill-destructor)))))))
1748
1749 (define mumi-service-type
1750 (service-type
1751 (name 'mumi)
1752 (extensions
1753 (list (service-extension activation-service-type
1754 (const %mumi-activation))
1755 (service-extension account-service-type
1756 (const %mumi-accounts))
1757 (service-extension shepherd-root-service-type
1758 mumi-shepherd-services)))
1759 (description
1760 "Run Mumi, a Web interface to the Debbugs bug-tracking server.")
1761 (default-value
1762 (mumi-configuration))))