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