diff options
Diffstat (limited to 'gnu/services')
-rw-r--r-- | gnu/services/base.scm | 194 | ||||
-rw-r--r-- | gnu/services/cuirass.scm | 16 | ||||
-rw-r--r-- | gnu/services/cups.scm | 2 | ||||
-rw-r--r-- | gnu/services/mail.scm | 2 | ||||
-rw-r--r-- | gnu/services/messaging.scm | 6 | ||||
-rw-r--r-- | gnu/services/networking.scm | 379 | ||||
-rw-r--r-- | gnu/services/shepherd.scm | 2 | ||||
-rw-r--r-- | gnu/services/spice.scm | 5 | ||||
-rw-r--r-- | gnu/services/ssh.scm | 3 | ||||
-rw-r--r-- | gnu/services/vpn.scm | 494 | ||||
-rw-r--r-- | gnu/services/web.scm | 97 |
11 files changed, 988 insertions, 212 deletions
diff --git a/gnu/services/base.scm b/gnu/services/base.scm index 1b1ce0d5e8..57601eab85 100644 --- a/gnu/services/base.scm +++ b/gnu/services/base.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2015, 2016 Alex Kost <alezost@gmail.com> ;;; Copyright © 2015, 2016 Mark H Weaver <mhw@netris.org> ;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com> @@ -36,6 +36,7 @@ #:select (alsa-utils crda eudev e2fsprogs fuse gpm kbd lvm2 rng-tools)) #:use-module ((gnu packages base) #:select (canonical-package glibc)) + #:use-module (gnu packages bash) #:use-module (gnu packages package-management) #:use-module (gnu packages lsof) #:use-module (gnu packages terminals) @@ -99,6 +100,18 @@ %default-authorized-guix-keys guix-configuration guix-configuration? + + guix-configuration-guix + guix-configuration-build-group + guix-configuration-build-accounts + guix-configuration-authorize-key? + guix-configuration-authorized-keys + guix-configuration-use-substitutes? + guix-configuration-substitute-urls + guix-configuration-extra-options + guix-configuration-log-file + guix-configuration-lsof + guix-service guix-service-type guix-publish-configuration @@ -301,13 +314,26 @@ FILE-SYSTEM." #:select (mount-file-system)) ,@%default-modules))))))) +(define (file-system-shepherd-services file-systems) + "Return the list of Shepherd services for FILE-SYSTEMS." + (let* ((file-systems (filter file-system-mount? file-systems))) + (define sink + (shepherd-service + (provision '(file-systems)) + (requirement (cons* 'root-file-system 'user-file-systems + (map file-system->shepherd-service-name + file-systems))) + (documentation "Target for all the initially-mounted file systems") + (start #~(const #t)) + (stop #~(const #f)))) + + (cons sink (map file-system-shepherd-service file-systems)))) + (define file-system-service-type (service-type (name 'file-systems) (extensions (list (service-extension shepherd-root-service-type - (lambda (file-systems) - (filter-map file-system-shepherd-service - file-systems))) + file-system-shepherd-services) (service-extension fstab-service-type identity))) (compose concatenate) @@ -354,93 +380,89 @@ in KNOWN-MOUNT-POINTS when it is stopped." (define user-processes-service-type (shepherd-service-type 'user-processes - (match-lambda - ((requirements grace-delay) - (shepherd-service - (documentation "When stopped, terminate all user processes.") - (provision '(user-processes)) - (requirement (cons* 'root-file-system 'user-file-systems - (map file-system->shepherd-service-name - requirements))) - (start #~(const #t)) - (stop #~(lambda _ - (define (kill-except omit signal) - ;; Kill all the processes with SIGNAL except those listed - ;; in OMIT and the current process. - (let ((omit (cons (getpid) omit))) - (for-each (lambda (pid) - (unless (memv pid omit) - (false-if-exception - (kill pid signal)))) - (processes)))) - - (define omitted-pids - ;; List of PIDs that must not be killed. - (if (file-exists? #$%do-not-kill-file) - (map string->number - (call-with-input-file #$%do-not-kill-file - (compose string-tokenize - (@ (ice-9 rdelim) read-string)))) - '())) - - (define (now) - (car (gettimeofday))) - - (define (sleep* n) - ;; Really sleep N seconds. - ;; Work around <http://bugs.gnu.org/19581>. - (define start (now)) - (let loop ((elapsed 0)) - (when (> n elapsed) - (sleep (- n elapsed)) - (loop (- (now) start))))) - - (define lset= (@ (srfi srfi-1) lset=)) - - (display "sending all processes the TERM signal\n") - - (if (null? omitted-pids) - (begin - ;; Easy: terminate all of them. - (kill -1 SIGTERM) - (sleep* #$grace-delay) - (kill -1 SIGKILL)) - (begin - ;; Kill them all except OMITTED-PIDS. XXX: We would - ;; like to (kill -1 SIGSTOP) to get a fixed list of - ;; processes, like 'killall5' does, but that seems - ;; unreliable. - (kill-except omitted-pids SIGTERM) - (sleep* #$grace-delay) - (kill-except omitted-pids SIGKILL) - (delete-file #$%do-not-kill-file))) - - (let wait () - (let ((pids (processes))) - (unless (lset= = pids (cons 1 omitted-pids)) - (format #t "waiting for process termination\ + (lambda (grace-delay) + (shepherd-service + (documentation "When stopped, terminate all user processes.") + (provision '(user-processes)) + (requirement '(file-systems)) + (start #~(const #t)) + (stop #~(lambda _ + (define (kill-except omit signal) + ;; Kill all the processes with SIGNAL except those listed + ;; in OMIT and the current process. + (let ((omit (cons (getpid) omit))) + (for-each (lambda (pid) + (unless (memv pid omit) + (false-if-exception + (kill pid signal)))) + (processes)))) + + (define omitted-pids + ;; List of PIDs that must not be killed. + (if (file-exists? #$%do-not-kill-file) + (map string->number + (call-with-input-file #$%do-not-kill-file + (compose string-tokenize + (@ (ice-9 rdelim) read-string)))) + '())) + + (define (now) + (car (gettimeofday))) + + (define (sleep* n) + ;; Really sleep N seconds. + ;; Work around <http://bugs.gnu.org/19581>. + (define start (now)) + (let loop ((elapsed 0)) + (when (> n elapsed) + (sleep (- n elapsed)) + (loop (- (now) start))))) + + (define lset= (@ (srfi srfi-1) lset=)) + + (display "sending all processes the TERM signal\n") + + (if (null? omitted-pids) + (begin + ;; Easy: terminate all of them. + (kill -1 SIGTERM) + (sleep* #$grace-delay) + (kill -1 SIGKILL)) + (begin + ;; Kill them all except OMITTED-PIDS. XXX: We would + ;; like to (kill -1 SIGSTOP) to get a fixed list of + ;; processes, like 'killall5' does, but that seems + ;; unreliable. + (kill-except omitted-pids SIGTERM) + (sleep* #$grace-delay) + (kill-except omitted-pids SIGKILL) + (delete-file #$%do-not-kill-file))) + + (let wait () + (let ((pids (processes))) + (unless (lset= = pids (cons 1 omitted-pids)) + (format #t "waiting for process termination\ (processes left: ~s)~%" - pids) - (sleep* 2) - (wait)))) + pids) + (sleep* 2) + (wait)))) - (display "all processes have been terminated\n") - #f)) - (respawn? #f)))))) + (display "all processes have been terminated\n") + #f)) + (respawn? #f))))) -(define* (user-processes-service file-systems #:key (grace-delay 4)) +(define* (user-processes-service #:key (grace-delay 4)) "Return the service that is responsible for terminating all the processes so that the root file system can be re-mounted read-only, just before rebooting/halting. Processes still running GRACE-DELAY seconds after SIGTERM has been sent are terminated with SIGKILL. -The returned service will depend on 'root-file-system' and on all the shepherd -services corresponding to FILE-SYSTEMS. +The returned service will depend on 'file-systems', meaning that it is +considered started after all the auto-mount file systems have been mounted. All the services that spawn processes must depend on this one so that they are stopped before 'kill' is called." - (service user-processes-service-type - (list (filter file-system-mount? file-systems) grace-delay))) + (service user-processes-service-type grace-delay)) ;;; @@ -1525,8 +1547,10 @@ This service is not part of @var{%base-services}." (mingetty-service (mingetty-configuration (tty "tty6"))) - (static-networking-service "lo" "127.0.0.1" - #:provision '(loopback)) + (service static-networking-service-type + (list (static-networking (interface "lo") + (ip "127.0.0.1") + (provision '(loopback))))) (syslog-service) (urandom-seed-service) (guix-service) @@ -1535,6 +1559,10 @@ This service is not part of @var{%base-services}." ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is ;; used, so enable them by default. The FUSE and ALSA rules are ;; less critical, but handy. - (udev-service #:rules (list lvm2 fuse alsa-utils crda)))) + (udev-service #:rules (list lvm2 fuse alsa-utils crda)) + + (service special-files-service-type + `(("/bin/sh" ,(file-append (canonical-package bash) + "/bin/sh")))))) ;;; base.scm ends here diff --git a/gnu/services/cuirass.scm b/gnu/services/cuirass.scm index c15a846bad..237f71a09b 100644 --- a/gnu/services/cuirass.scm +++ b/gnu/services/cuirass.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org> ;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -56,12 +57,16 @@ (default 60)) (database cuirass-configuration-database ;string (file-name) (default "/var/run/cuirass/cuirass.db")) + (port cuirass-configuration-port ;integer (port) + (default 8080)) (specifications cuirass-configuration-specifications) ;gexp that evaluates to specification-alist (use-substitutes? cuirass-configuration-use-substitutes? ;boolean (default #f)) (one-shot? cuirass-configuration-one-shot? ;boolean - (default #f))) + (default #f)) + (load-path cuirass-configuration-load-path + (default '()))) (define (cuirass-shepherd-service config) "Return a <shepherd-service> for the Cuirass service with CONFIG." @@ -74,9 +79,11 @@ (group (cuirass-configuration-group config)) (interval (cuirass-configuration-interval config)) (database (cuirass-configuration-database config)) + (port (cuirass-configuration-port config)) (specs (cuirass-configuration-specifications config)) (use-substitutes? (cuirass-configuration-use-substitutes? config)) - (one-shot? (cuirass-configuration-one-shot? config))) + (one-shot? (cuirass-configuration-one-shot? config)) + (load-path (cuirass-configuration-load-path config))) (list (shepherd-service (documentation "Run Cuirass.") (provision '(cuirass)) @@ -87,9 +94,12 @@ "--specifications" #$(scheme-file "cuirass-specs.scm" specs) "--database" #$database + "--port" #$(number->string port) "--interval" #$(number->string interval) #$@(if use-substitutes? '("--use-substitutes") '()) - #$@(if one-shot? '("--one-shot") '())) + #$@(if one-shot? '("--one-shot") '()) + #$@(if (null? load-path) '() + `("--load-path" ,(string-join load-path ":")))) #:user #$user #:group #$group #:log-file #$log-file)) diff --git a/gnu/services/cups.scm b/gnu/services/cups.scm index df1843e438..70b858479a 100644 --- a/gnu/services/cups.scm +++ b/gnu/services/cups.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016 Andy Wingo <wingo@pobox.com> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -811,6 +812,7 @@ IPP specifications.") ;; Activation gexp. (with-imported-modules '((guix build utils)) #~(begin + (use-modules (guix build utils)) (define (mkdir-p/perms directory owner perms) (mkdir-p directory) (chown "/var/run/cups" (passwd:uid owner) (passwd:gid owner)) diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm index c1381405d8..30b1672d33 100644 --- a/gnu/services/mail.scm +++ b/gnu/services/mail.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 Andy Wingo <wingo@igalia.com> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -1601,6 +1602,7 @@ accept from local for any relay (($ <opensmtpd-configuration> package config-file) (let ((smtpd (file-append package "/sbin/smtpd"))) #~(begin + (use-modules (guix build utils)) ;; Create mbox and spool directories. (mkdir-p "/var/mail") (mkdir-p "/var/spool/smtpd") diff --git a/gnu/services/messaging.scm b/gnu/services/messaging.scm index 0b5aa1fae8..9f59d6eac6 100644 --- a/gnu/services/messaging.scm +++ b/gnu/services/messaging.scm @@ -40,7 +40,8 @@ mod-muc-configuration ssl-configuration - %default-modules-enabled)) + %default-modules-enabled + prosody-configuration-pidfile)) ;;; Commentary: ;;; @@ -592,7 +593,7 @@ See also @url{http://prosody.im/doc/modules/mod_muc}." (zero? (system* #$prosodyctl-bin #$@args)))))) (list (shepherd-service (documentation "Run the Prosody XMPP server") - (provision '(prosody)) + (provision '(prosody xmpp-daemon)) (requirement '(networking syslogd user-processes)) (start (prosodyctl-action "start")) (stop (prosodyctl-action "stop")))))) @@ -621,6 +622,7 @@ See also @url{http://prosody.im/doc/modules/mod_muc}." (serialize-prosody-configuration config))))) (config-file (plain-file "prosody.cfg.lua" config-str))) #~(begin + (use-modules (guix build utils)) (define %user (getpw "prosody")) (mkdir-p #$config-dir) diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index ac011f1286..18bce2a2b8 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org> ;;; Copyright © 2016 Efraim Flashner <efraim@flashner.co.il> ;;; Copyright © 2016 John Darrington <jmd@gnu.org> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -30,17 +31,26 @@ #:use-module (gnu packages linux) #:use-module (gnu packages tor) #:use-module (gnu packages messaging) + #:use-module (gnu packages networking) #:use-module (gnu packages ntp) #:use-module (gnu packages wicd) #:use-module (gnu packages gnome) #:use-module (guix gexp) #:use-module (guix records) + #:use-module (guix modules) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) #:use-module (srfi srfi-26) #:use-module (ice-9 match) #:export (%facebook-host-aliases static-networking + + static-networking? + static-networking-interface + static-networking-ip + static-networking-netmask + static-networking-gateway + static-networking-service static-networking-service-type dhcp-client-service @@ -64,9 +74,17 @@ wicd-service-type wicd-service - network-manager-service + + network-manager-configuration + network-manager-configuration? + network-manager-configuration-dns + network-manager-service-type + connman-service - wpa-supplicant-service-type)) + wpa-supplicant-service-type + + openvswitch-service-type + openvswitch-configuration)) ;;; Commentary: ;;; @@ -115,88 +133,138 @@ fe80::1%lo0 apps.facebook.com\n") (ip static-networking-ip) (netmask static-networking-netmask (default #f)) - (gateway static-networking-gateway) - (provision static-networking-provision) - (name-servers static-networking-name-servers)) + (gateway static-networking-gateway ;FIXME: doesn't belong here + (default #f)) + (provision static-networking-provision + (default #f)) + (name-servers static-networking-name-servers ;FIXME: doesn't belong here + (default '()))) -(define static-networking-service-type - (shepherd-service-type - 'static-networking - (match-lambda - (($ <static-networking> interface ip netmask gateway provision - name-servers) - (let ((loopback? (memq 'loopback provision))) - (shepherd-service +(define static-networking-shepherd-service + (match-lambda + (($ <static-networking> interface ip netmask gateway provision + name-servers) + (let ((loopback? (and provision (memq 'loopback provision)))) + (shepherd-service + + ;; Unless we're providing the loopback interface, wait for udev to be up + ;; and running so that INTERFACE is actually usable. + (requirement (if loopback? '() '(udev))) + + (documentation + "Bring up the networking interface using a static IP address.") + (provision (or provision + (list (symbol-append 'networking- + (string->symbol interface))))) + + (start #~(lambda _ + ;; Return #t if successfully started. + (let* ((addr (inet-pton AF_INET #$ip)) + (sockaddr (make-socket-address AF_INET addr 0)) + (mask (and #$netmask + (inet-pton AF_INET #$netmask))) + (maskaddr (and mask + (make-socket-address AF_INET + mask 0))) + (gateway (and #$gateway + (inet-pton AF_INET #$gateway))) + (gatewayaddr (and gateway + (make-socket-address AF_INET + gateway 0)))) + (configure-network-interface #$interface sockaddr + (logior IFF_UP + #$(if loopback? + #~IFF_LOOPBACK + 0)) + #:netmask maskaddr) + (when gateway + (let ((sock (socket AF_INET SOCK_DGRAM 0))) + (add-network-route/gateway sock gatewayaddr) + (close-port sock)))))) + (stop #~(lambda _ + ;; Return #f is successfully stopped. + (let ((sock (socket AF_INET SOCK_STREAM 0))) + (when #$gateway + (delete-network-route sock + (make-socket-address + AF_INET INADDR_ANY 0))) + (set-network-interface-flags sock #$interface 0) + (close-port sock) + #f))) + (respawn? #f)))))) + +(define (static-networking-etc-files interfaces) + "Return a /etc/resolv.conf entry for INTERFACES or the empty list." + (match (delete-duplicates + (append-map static-networking-name-servers + interfaces)) + (() + '()) + ((name-servers ...) + (let ((content (string-join + (map (cut string-append "nameserver " <>) + name-servers) + "\n" 'suffix))) + `(("resolv.conf" + ,(plain-file "resolv.conf" + (string-append "\ +# Generated by 'static-networking-service'.\n" + content)))))))) + +(define (static-networking-shepherd-services interfaces) + "Return the list of Shepherd services to bring up INTERFACES, a list of +<static-networking> objects." + (define (loopback? service) + (memq 'loopback (shepherd-service-provision service))) + + (let ((services (map static-networking-shepherd-service interfaces))) + (match (remove loopback? services) + (() + ;; There's no interface other than 'loopback', so we assume that the + ;; 'networking' service will be provided by dhclient or similar. + services) + ((non-loopback ...) + ;; Assume we're providing all the interfaces, and thus, provide a + ;; 'networking' service. + (cons (shepherd-service + (provision '(networking)) + (requirement (append-map shepherd-service-provision + services)) + (start #~(const #t)) + (stop #~(const #f)) + (documentation "Bring up all the networking interfaces.")) + services))))) - ;; Unless we're providing the loopback interface, wait for udev to be up - ;; and running so that INTERFACE is actually usable. - (requirement (if loopback? '() '(udev))) - - (documentation - "Bring up the networking interface using a static IP address.") - (provision provision) - (start #~(lambda _ - ;; Return #t if successfully started. - (let* ((addr (inet-pton AF_INET #$ip)) - (sockaddr (make-socket-address AF_INET addr 0)) - (mask (and #$netmask - (inet-pton AF_INET #$netmask))) - (maskaddr (and mask - (make-socket-address AF_INET - mask 0))) - (gateway (and #$gateway - (inet-pton AF_INET #$gateway))) - (gatewayaddr (and gateway - (make-socket-address AF_INET - gateway 0)))) - (configure-network-interface #$interface sockaddr - (logior IFF_UP - #$(if loopback? - #~IFF_LOOPBACK - 0)) - #:netmask maskaddr) - (when gateway - (let ((sock (socket AF_INET SOCK_DGRAM 0))) - (add-network-route/gateway sock gatewayaddr) - (close-port sock)))) - - #$(if (pair? name-servers) - #~(call-with-output-file "/etc/resolv.conf" - (lambda (port) - (display - "# Generated by 'static-networking-service'.\n" - port) - (for-each (lambda (server) - (format port "nameserver ~a~%" - server)) - '#$name-servers) - #t)) - #t))) - (stop #~(lambda _ - ;; Return #f is successfully stopped. - (let ((sock (socket AF_INET SOCK_STREAM 0))) - (when #$gateway - (delete-network-route sock - (make-socket-address - AF_INET INADDR_ANY 0))) - (set-network-interface-flags sock #$interface 0) - (close-port sock) - #f))) - (respawn? #f))))))) +(define static-networking-service-type + ;; The service type for statically-defined network interfaces. + (service-type (name 'static-networking) + (extensions + (list + (service-extension shepherd-root-service-type + static-networking-shepherd-services) + (service-extension etc-service-type + static-networking-etc-files))) + (compose concatenate) + (extend append))) (define* (static-networking-service interface ip #:key - netmask gateway - (provision '(networking)) + netmask gateway provision (name-servers '())) "Return a service that starts @var{interface} with address @var{ip}. If @var{netmask} is true, use it as the network mask. If @var{gateway} is true, -it must be a string specifying the default network gateway." - (service static-networking-service-type - (static-networking (interface interface) (ip ip) - (netmask netmask) (gateway gateway) - (provision provision) - (name-servers name-servers)))) +it must be a string specifying the default network gateway. + +This procedure can be called several times, one for each network +interface of interest. Behind the scenes what it does is extend +@code{static-networking-service-type} with additional network interfaces +to handle." + (simple-service 'static-network-interface + static-networking-service-type + (list (static-networking (interface interface) (ip ip) + (netmask netmask) (gateway gateway) + (provision provision) + (name-servers name-servers))))) (define dhcp-client-service-type (shepherd-service-type @@ -327,6 +395,7 @@ restrict -6 ::1\n")) "Return the activation gexp for CONFIG." (with-imported-modules '((guix build utils)) #~(begin + (use-modules (guix build utils)) (define %user (getpw "ntpd")) @@ -560,13 +629,29 @@ project's documentation} for more information." DaemonPort = " (number->string port) " " extra-settings)))) - (list (shepherd-service - (provision '(bitlbee)) - (requirement '(user-processes loopback)) - (start #~(make-forkexec-constructor - (list (string-append #$bitlbee "/sbin/bitlbee") - "-n" "-F" "-u" "bitlbee" "-c" #$conf))) - (stop #~(make-kill-destructor)))))))) + (with-imported-modules (source-module-closure + '((gnu build shepherd) + (gnu system file-systems))) + (list (shepherd-service + (provision '(bitlbee)) + + ;; Note: If networking is not up, then /etc/resolv.conf + ;; doesn't get mapped in the container, hence the dependency + ;; on 'networking'. + (requirement '(user-processes networking)) + + (modules '((gnu build shepherd) + (gnu system file-systems))) + (start #~(make-forkexec-constructor/container + (list #$(file-append bitlbee "/sbin/bitlbee") + "-n" "-F" "-u" "bitlbee" "-c" #$conf) + + #:pid-file "/var/run/bitlbee.pid" + #:mappings (list (file-system-mapping + (source "/var/lib/bitlbee") + (target source) + (writable? #t))))) + (stop #~(make-kill-destructor))))))))) (define %bitlbee-accounts ;; User group and account to run BitlBee. @@ -679,40 +764,58 @@ and @command{wicd-curses} user interfaces." ;;; NetworkManager ;;; +(define-record-type* <network-manager-configuration> + network-manager-configuration make-network-manager-configuration + network-manager-configuration? + (network-manager network-manager-configuration-network-manager + (default network-manager)) + (dns network-manager-configuration-dns + (default "default"))) + (define %network-manager-activation ;; Activation gexp for NetworkManager. #~(begin (use-modules (guix build utils)) (mkdir-p "/etc/NetworkManager/system-connections"))) -(define (network-manager-shepherd-service network-manager) - "Return a shepherd service for NETWORK-MANAGER." - (list (shepherd-service - (documentation "Run the NetworkManager.") - (provision '(networking)) - (requirement '(user-processes dbus-system wpa-supplicant loopback)) - (start #~(make-forkexec-constructor - (list (string-append #$network-manager - "/sbin/NetworkManager") - "--no-daemon"))) - (stop #~(make-kill-destructor))))) +(define network-manager-shepherd-service + (match-lambda + (($ <network-manager-configuration> network-manager dns) + (let + ((conf (plain-file "NetworkManager.conf" + (string-append " +[main] +dns=" dns " +")))) + (list (shepherd-service + (documentation "Run the NetworkManager.") + (provision '(networking)) + (requirement '(user-processes dbus-system wpa-supplicant loopback)) + (start #~(make-forkexec-constructor + (list (string-append #$network-manager + "/sbin/NetworkManager") + (string-append "--config=" #$conf) + "--no-daemon"))) + (stop #~(make-kill-destructor)))))))) (define network-manager-service-type - (service-type (name 'network-manager) - (extensions - (list (service-extension shepherd-root-service-type - network-manager-shepherd-service) - (service-extension dbus-root-service-type list) - (service-extension polkit-service-type list) - (service-extension activation-service-type - (const %network-manager-activation)) - ;; Add network-manager to the system profile. - (service-extension profile-service-type list))))) - -(define* (network-manager-service #:key (network-manager network-manager)) - "Return a service that runs NetworkManager, a network connection manager -that attempting to keep active network connectivity when available." - (service network-manager-service-type network-manager)) + (let + ((config->package + (match-lambda + (($ <network-manager-configuration> network-manager) + (list network-manager))))) + + (service-type + (name 'network-manager) + (extensions + (list (service-extension shepherd-root-service-type + network-manager-shepherd-service) + (service-extension dbus-root-service-type config->package) + (service-extension polkit-service-type config->package) + (service-extension activation-service-type + (const %network-manager-activation)) + ;; Add network-manager to the system profile. + (service-extension profile-service-type config->package)))))) ;;; @@ -786,4 +889,62 @@ configure networking." (service-extension dbus-root-service-type list) (service-extension profile-service-type list))))) + +;;; +;;; Open vSwitch +;;; + +(define-record-type* <openvswitch-configuration> + openvswitch-configuration make-openvswitch-configuration + openvswitch-configuration? + (package openvswitch-configuration-package + (default openvswitch))) + +(define openvswitch-activation + (match-lambda + (($ <openvswitch-configuration> package) + (let ((ovsdb-tool (file-append package "/bin/ovsdb-tool"))) + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + (mkdir-p "/var/run/openvswitch") + (mkdir-p "/var/lib/openvswitch") + (let ((conf.db "/var/lib/openvswitch/conf.db")) + (unless (file-exists? conf.db) + (system* #$ovsdb-tool "create" conf.db))))))))) + +(define openvswitch-shepherd-service + (match-lambda + (($ <openvswitch-configuration> package) + (let ((ovsdb-server (file-append package "/sbin/ovsdb-server")) + (ovs-vswitchd (file-append package "/sbin/ovs-vswitchd"))) + (list + (shepherd-service + (provision '(ovsdb)) + (documentation "Run the Open vSwitch database server.") + (start #~(make-forkexec-constructor + (list #$ovsdb-server "--pidfile" + "--remote=punix:/var/run/openvswitch/db.sock") + #:pid-file "/var/run/openvswitch/ovsdb-server.pid")) + (stop #~(make-kill-destructor))) + (shepherd-service + (provision '(vswitchd)) + (requirement '(ovsdb)) + (documentation "Run the Open vSwitch daemon.") + (start #~(make-forkexec-constructor + (list #$ovs-vswitchd "--pidfile") + #:pid-file "/var/run/openvswitch/ovs-vswitchd.pid")) + (stop #~(make-kill-destructor)))))))) + +(define openvswitch-service-type + (service-type + (name 'openvswitch) + (extensions + (list (service-extension activation-service-type + openvswitch-activation) + (service-extension profile-service-type + (compose list openvswitch-configuration-package)) + (service-extension shepherd-root-service-type + openvswitch-shepherd-service))))) + ;;; networking.scm ends here diff --git a/gnu/services/shepherd.scm b/gnu/services/shepherd.scm index d8d5006abf..5831220541 100644 --- a/gnu/services/shepherd.scm +++ b/gnu/services/shepherd.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -195,6 +196,7 @@ stored." (string-append "shepherd-" (string-map (match-lambda (#\/ #\-) + (#\ #\-) (chr chr)) provisions) ".scm"))) diff --git a/gnu/services/spice.scm b/gnu/services/spice.scm index bd0a538346..2f9dfd57ac 100644 --- a/gnu/services/spice.scm +++ b/gnu/services/spice.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016 David Craven <david@craven.ch> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -35,7 +36,9 @@ (define (spice-vdagent-activation config) "Return the activation gexp for CONFIG." - #~(mkdir-p "/var/run/spice-vdagentd")) + #~(begin + (use-modules (guix build utils)) + (mkdir-p "/var/run/spice-vdagentd"))) (define (spice-vdagent-shepherd-service config) "Return a <shepherd-service> for spice-vdagentd with CONFIG." diff --git a/gnu/services/ssh.scm b/gnu/services/ssh.scm index 6da612da67..58c35c9f5e 100644 --- a/gnu/services/ssh.scm +++ b/gnu/services/ssh.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2016 David Craven <david@craven.ch> ;;; Copyright © 2016 Julien Lepiller <julien@lepiller.eu> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -292,6 +293,7 @@ The other options should be self-descriptive." (define (openssh-activation config) "Return the activation GEXP for CONFIG." #~(begin + (use-modules (guix build utils)) (mkdir-p "/etc/ssh") (mkdir-p (dirname #$(openssh-configuration-pid-file config))) @@ -388,6 +390,7 @@ The other options should be self-descriptive." (define (dropbear-activation config) "Return the activation gexp for CONFIG." #~(begin + (use-modules (guix build utils)) (mkdir-p "/etc/dropbear"))) (define (dropbear-shepherd-service config) diff --git a/gnu/services/vpn.scm b/gnu/services/vpn.scm new file mode 100644 index 0000000000..844a11b3d3 --- /dev/null +++ b/gnu/services/vpn.scm @@ -0,0 +1,494 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2017 Julien Lepiller <julien@lepiller.eu> +;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (gnu services vpn) + #:use-module (gnu services) + #:use-module (gnu services configuration) + #:use-module (gnu services shepherd) + #:use-module (gnu system shadow) + #:use-module (gnu packages admin) + #:use-module (gnu packages vpn) + #:use-module (guix packages) + #:use-module (guix records) + #:use-module (guix gexp) + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + #:use-module (ice-9 regex) + #:export (openvpn-client-service + openvpn-server-service + openvpn-client-service-type + openvpn-server-service-type + openvpn-client-configuration + openvpn-server-configuration + openvpn-remote-configuration + openvpn-ccd-configuration + generate-openvpn-client-documentation + generate-openvpn-server-documentation)) + +;;; +;;; OpenVPN. +;;; + +(define (uglify-field-name name) + (match name + ('verbosity "verb") + (_ (let ((str (symbol->string name))) + (if (string-suffix? "?" str) + (substring str 0 (1- (string-length str))) + str))))) + +(define (serialize-field field-name val) + (if (eq? field-name 'pid-file) + (format #t "") + (format #t "~a ~a\n" (uglify-field-name field-name) val))) +(define serialize-string serialize-field) +(define (serialize-boolean field-name val) + (if val + (serialize-field field-name val) + (format #t ""))) + +(define (ip-mask? val) + (and (string? val) + (if (string-match "^([0-9]+\\.){3}[0-9]+ ([0-9]+\\.){3}[0-9]+$" val) + (let ((numbers (string-tokenize val char-set:digit))) + (all-lte numbers (list 255 255 255 255 255 255 255 255))) + #f))) +(define serialize-ip-mask serialize-string) + +(define-syntax define-enumerated-field-type + (lambda (x) + (define (id-append ctx . parts) + (datum->syntax ctx (apply symbol-append (map syntax->datum parts)))) + (syntax-case x () + ((_ name (option ...)) + #`(begin + (define (#,(id-append #'name #'name #'?) x) + (memq x '(option ...))) + (define (#,(id-append #'name #'serialize- #'name) field-name val) + (serialize-field field-name val))))))) + +(define-enumerated-field-type proto + (udp tcp udp6 tcp6)) +(define-enumerated-field-type dev + (tun tap)) + +(define key-usage? boolean?) +(define (serialize-key-usage field-name value) + (if value + (format #t "remote-cert-tls server\n") + #f)) + +(define bind? boolean?) +(define (serialize-bind field-name value) + (if value + #f + (format #t "nobind\n"))) + +(define resolv-retry? boolean?) +(define (serialize-resolv-retry field-name value) + (if value + (format #t "resolv-retry infinite\n") + #f)) + +(define (serialize-tls-auth role location) + (serialize-field 'tls-auth + (string-append location " " (match role + ('server "0") + ('client "1"))))) +(define (tls-auth? val) + (or (eq? val #f) + (string? val))) +(define (serialize-tls-auth-server field-name val) + (serialize-tls-auth 'server val)) +(define (serialize-tls-auth-client field-name val) + (serialize-tls-auth 'client val)) +(define tls-auth-server? tls-auth?) +(define tls-auth-client? tls-auth?) + +(define (serialize-number field-name val) + (serialize-field field-name (number->string val))) + +(define (all-lte left right) + (if (eq? left '()) + (eq? right '()) + (and (<= (string->number (car left)) (car right)) + (all-lte (cdr left) (cdr right))))) + +(define (cidr4? val) + (if (string? val) + (if (string-match "^([0-9]+\\.){3}[0-9]+/[0-9]+$" val) + (let ((numbers (string-tokenize val char-set:digit))) + (all-lte numbers (list 255 255 255 255 32))) + #f) + (eq? val #f))) + +(define (cidr6? val) + (if (string? val) + (string-match "^([0-9a-f]{0,4}:){0,8}/[0-9]{1,3}$" val) + (eq? val #f))) + +(define (serialize-cidr4 field-name val) + (if (eq? val #f) #f (serialize-field field-name val))) + +(define (serialize-cidr6 field-name val) + (if (eq? val #f) #f (serialize-field field-name val))) + +(define (ip? val) + (if (string? val) + (if (string-match "^([0-9]+\\.){3}[0-9]+$" val) + (let ((numbers (string-tokenize val char-set:digit))) + (all-lte numbers (list 255 255 255 255))) + #f) + (eq? val #f))) +(define (serialize-ip field-name val) + (if (eq? val #f) #f (serialize-field field-name val))) + +(define (keepalive? val) + (and (list? val) + (and (number? (car val)) + (number? (car (cdr val)))))) +(define (serialize-keepalive field-name val) + (format #t "~a ~a ~a\n" (uglify-field-name field-name) + (number->string (car val)) (number->string (car (cdr val))))) + +(define gateway? boolean?) +(define (serialize-gateway field-name val) + (and val + (format #t "push \"redirect-gateway\"\n"))) + + +(define-configuration openvpn-remote-configuration + (name + (string "my-server") + "Server name.") + (port + (number 1194) + "Port number the server listens to.")) + +(define-configuration openvpn-ccd-configuration + (name + (string "client") + "Client name.") + (iroute + (ip-mask #f) + "Client own network") + (ifconfig-push + (ip-mask #f) + "Client VPN IP.")) + +(define (openvpn-remote-list? val) + (and (list? val) + (or (eq? val '()) + (and (openvpn-remote-configuration? (car val)) + (openvpn-remote-list? (cdr val)))))) +(define (serialize-openvpn-remote-list field-name val) + (for-each (lambda (remote) + (format #t "remote ~a ~a\n" (openvpn-remote-configuration-name remote) + (number->string (openvpn-remote-configuration-port remote)))) + val)) + +(define (openvpn-ccd-list? val) + (and (list? val) + (or (eq? val '()) + (and (openvpn-ccd-configuration? (car val)) + (openvpn-ccd-list? (cdr val)))))) +(define (serialize-openvpn-ccd-list field-name val) + #f) + +(define (create-ccd-directory val) + "Create a ccd directory containing files for the ccd configuration option +of OpenVPN. Each file in this directory represents particular settings for a +client. Each file is named after the name of the client." + (let ((files (map (lambda (ccd) + (list (openvpn-ccd-configuration-name ccd) + (with-output-to-string + (lambda () + (serialize-configuration + ccd openvpn-ccd-configuration-fields))))) + val))) + (computed-file "ccd" + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + (use-modules (ice-9 match)) + (mkdir-p #$output) + (for-each + (lambda (ccd) + (match ccd + ((name config-string) + (call-with-output-file + (string-append #$output "/" name) + (lambda (port) (display config-string port)))))) + '#$files)))))) + +(define-syntax define-split-configuration + (lambda (x) + (syntax-case x () + ((_ name1 name2 (common-option ...) (first-option ...) (second-option ...)) + #`(begin + (define-configuration #,#'name1 + common-option ... + first-option ...) + (define-configuration #,#'name2 + common-option ... + second-option ...)))))) + +(define-split-configuration openvpn-client-configuration + openvpn-server-configuration + ((openvpn + (package openvpn) + "The OpenVPN package.") + + (pid-file + (string "/var/run/openvpn/openvpn.pid") + "The OpenVPN pid file.") + + (proto + (proto 'udp) + "The protocol (UDP or TCP) used to open a channel between clients and +servers.") + + (dev + (dev 'tun) + "The device type used to represent the VPN connection.") + + (ca + (string "/etc/openvpn/ca.crt") + "The certificate authority to check connections against.") + + (cert + (string "/etc/openvpn/client.crt") + "The certificate of the machine the daemon is running on. It should be signed +by the authority given in @code{ca}.") + + (key + (string "/etc/openvpn/client.key") + "The key of the machine the daemon is running on. It must be the whose +certificate is @code{cert}.") + + (comp-lzo? + (boolean #t) + "Whether to use the lzo compression algorithm.") + + (persist-key? + (boolean #t) + "Don't re-read key files across SIGUSR1 or --ping-restart.") + + (persist-tun? + (boolean #t) + "Don't close and reopen TUN/TAP device or run up/down scripts across +SIGUSR1 or --ping-restart restarts.") + + (verbosity + (number 3) + "Verbosity level.")) + ;; client-specific configuration + ((tls-auth + (tls-auth-client #f) + "Add an additional layer of HMAC authentication on top of the TLS control +channel to protect against DoS attacks.") + + (verify-key-usage? + (key-usage #t) + "Whether to check the server certificate has server usage extension.") + + (bind? + (bind #f) + "Bind to a specific local port number.") + + (resolv-retry? + (resolv-retry #t) + "Retry resolving server address.") + + (remote + (openvpn-remote-list '()) + "A list of remote servers to connect to.")) + ;; server-specific configuration + ((tls-auth + (tls-auth-server #f) + "Add an additional layer of HMAC authentication on top of the TLS control +channel to protect against DoS attacks.") + + (port + (number 1194) + "Specifies the port number on which the server listens.") + + (server + (ip-mask "10.8.0.0 255.255.255.0") + "An ip and mask specifying the subnet inside the virtual network.") + + (server-ipv6 + (cidr6 #f) + "A CIDR notation specifying the IPv6 subnet inside the virtual network.") + + (dh + (string "/etc/openvpn/dh2048.pem") + "The Diffie-Hellman parameters file.") + + (ifconfig-pool-persist + (string "/etc/openvpn/ipp.txt") + "The file that records client IPs.") + + (redirect-gateway? + (gateway #f) + "When true, the server will act as a gateway for its clients.") + + (client-to-client? + (boolean #f) + "When true, clients are alowed to talk to each other inside the VPN.") + + (keepalive + (keepalive '(10 120)) + "Causes ping-like messages to be sent back and forth over the link so that +each side knows when the other side has gone down. @code{keepalive} requires +a pair. The first element is the period of the ping sending, and the second +element is the timeout before considering the other side down.") + + (max-clients + (number 100) + "The maximum number of clients.") + + (status + (string "/var/run/openvpn/status") + "The status file. This file shows a small report on current connection. It +is trunkated and rewritten every minute.") + + (client-config-dir + (openvpn-ccd-list '()) + "The list of configuration for some clients."))) + +(define (openvpn-config-file role config) + (let ((config-str + (with-output-to-string + (lambda () + (serialize-configuration config + (match role + ('server + openvpn-server-configuration-fields) + ('client + openvpn-client-configuration-fields)))))) + (ccd-dir (match role + ('server (create-ccd-directory + (openvpn-server-configuration-client-config-dir + config))) + ('client #f)))) + (computed-file "openvpn.conf" + #~(begin + (use-modules (ice-9 match)) + (call-with-output-file #$output + (lambda (port) + (match '#$role + ('server (display "" port)) + ('client (display "client\n" port))) + (display #$config-str port) + (match '#$role + ('server (display + (string-append "client-config-dir " + #$ccd-dir "\n") port)) + ('client (display "" port))))))))) + +(define (openvpn-shepherd-service role) + (lambda (config) + (let* ((config-file (openvpn-config-file role config)) + (pid-file ((match role + ('server openvpn-server-configuration-pid-file) + ('client openvpn-client-configuration-pid-file)) + config)) + (openvpn ((match role + ('server openvpn-server-configuration-openvpn) + ('client openvpn-client-configuration-openvpn)) + config)) + (log-file (match role + ('server "/var/log/openvpn-server.log") + ('client "/var/log/openvpn-client.log")))) + (list (shepherd-service + (documentation (string-append "Run the OpenVPN " + (match role + ('server "server") + ('client "client")) + " daemon.")) + (provision (match role + ('server '(vpn-server)) + ('client '(vpn-client)))) + (requirement '(networking)) + (start #~(make-forkexec-constructor + (list (string-append #$openvpn "/sbin/openvpn") + "--writepid" #$pid-file "--config" #$config-file + "--daemon") + #:pid-file #$pid-file)) + (stop #~(make-kill-destructor))))))) + +(define %openvpn-accounts + (list (user-group (name "openvpn") (system? #t)) + (user-account + (name "openvpn") + (group "openvpn") + (system? #t) + (comment "Openvpn daemon user") + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin"))))) + +(define %openvpn-activation + #~(begin + (use-modules (guix build utils)) + (mkdir-p "/var/run/openvpn"))) + +(define openvpn-server-service-type + (service-type (name 'openvpn-server) + (extensions + (list (service-extension shepherd-root-service-type + (openvpn-shepherd-service 'server)) + (service-extension account-service-type + (const %openvpn-accounts)) + (service-extension activation-service-type + (const %openvpn-activation)))))) + +(define openvpn-client-service-type + (service-type (name 'openvpn-client) + (extensions + (list (service-extension shepherd-root-service-type + (openvpn-shepherd-service 'client)) + (service-extension account-service-type + (const %openvpn-accounts)) + (service-extension activation-service-type + (const %openvpn-activation)))))) + +(define* (openvpn-client-service #:key (config (openvpn-client-configuration))) + (validate-configuration config openvpn-client-configuration-fields) + (service openvpn-client-service-type config)) + +(define* (openvpn-server-service #:key (config (openvpn-server-configuration))) + (validate-configuration config openvpn-server-configuration-fields) + (service openvpn-server-service-type config)) + +(define (generate-openvpn-server-documentation) + (generate-documentation + `((openvpn-server-configuration + ,openvpn-server-configuration-fields + (ccd openvpn-ccd-configuration)) + (openvpn-ccd-configuration ,openvpn-ccd-configuration-fields)) + 'openvpn-server-configuration)) + +(define (generate-openvpn-client-documentation) + (generate-documentation + `((openvpn-client-configuration + ,openvpn-client-configuration-fields + (remote openvpn-remote-configuration)) + (openvpn-remote-configuration ,openvpn-remote-configuration-fields)) + 'openvpn-client-configuration)) diff --git a/gnu/services/web.scm b/gnu/services/web.scm index db895405a2..11408d7b0e 100644 --- a/gnu/services/web.scm +++ b/gnu/services/web.scm @@ -1,8 +1,9 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2015 David Thompson <davet@gnu.org> -;;; Copyright © 2015, 2016 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2016 ng0 <ng0@we.make.ritual.n0.is> ;;; Copyright © 2016 Julien Lepiller <julien@lepiller.eu> +;;; Copyright © 2017 Christopher Baines <mail@cbaines.net> ;;; ;;; This file is part of GNU Guix. ;;; @@ -33,6 +34,12 @@ nginx-configuration? nginx-server-configuration nginx-server-configuration? + nginx-upstream-configuration + nginx-upstream-configuration? + nginx-location-configuration + nginx-location-configuration? + nginx-named-location-configuration + nginx-named-location-configuration? nginx-service nginx-service-type)) @@ -53,6 +60,8 @@ (default (list 'default))) (root nginx-server-configuration-root (default "/srv/http")) + (locations nginx-server-configuration-locations + (default '())) (index nginx-server-configuration-index (default (list "index.html"))) (ssl-certificate nginx-server-configuration-ssl-certificate @@ -62,14 +71,41 @@ (server-tokens? nginx-server-configuration-server-tokens? (default #f))) +(define-record-type* <nginx-upstream-configuration> + nginx-upstream-configuration make-nginx-upstream-configuration + nginx-upstream-configuration? + (name nginx-upstream-configuration-name) + (servers nginx-upstream-configuration-servers)) + +(define-record-type* <nginx-location-configuration> + nginx-location-configuration make-nginx-location-configuration + nginx-location-configuration? + (uri nginx-location-configuration-uri + (default #f)) + (body nginx-location-configuration-body)) + +(define-record-type* <nginx-named-location-configuration> + nginx-named-location-configuration make-nginx-named-location-configuration + nginx-named-location-configuration? + (name nginx-named-location-configuration-name + (default #f)) + (body nginx-named-location-configuration-body)) + (define-record-type* <nginx-configuration> nginx-configuration make-nginx-configuration nginx-configuration? - (nginx nginx-configuration-nginx) ;<package> - (log-directory nginx-configuration-log-directory) ;string - (run-directory nginx-configuration-run-directory) ;string - (server-blocks nginx-configuration-server-blocks) ;list - (file nginx-configuration-file)) ;string | file-like + (nginx nginx-configuration-nginx ;<package> + (default nginx)) + (log-directory nginx-configuration-log-directory ;string + (default "/var/log/nginx")) + (run-directory nginx-configuration-run-directory ;string + (default "/var/run/nginx")) + (server-blocks nginx-configuration-server-blocks + (default '())) ;list of <nginx-server-configuration> + (upstream-blocks nginx-configuration-upstream-blocks + (default '())) ;list of <nginx-upstream-configuration> + (file nginx-configuration-file ;#f | string | file-like + (default #f))) (define (config-domain-strings names) "Return a string denoting the nginx config representation of NAMES, a list @@ -88,6 +124,19 @@ of index files." ((? string? str) (string-append str " "))) names))) +(define nginx-location-config + (match-lambda + (($ <nginx-location-configuration> uri body) + (string-append + " location " uri " {\n" + " " (string-join body "\n ") "\n" + " }\n")) + (($ <nginx-named-location-configuration> name body) + (string-append + " location @" name " {\n" + " " (string-join body "\n ") "\n" + " }\n")))) + (define (default-nginx-server-config server) (string-append " server {\n" @@ -116,11 +165,23 @@ of index files." " index " (config-index-strings (nginx-server-configuration-index server)) ";\n" " server_tokens " (if (nginx-server-configuration-server-tokens? server) "on" "off") ";\n" + "\n" + (string-join + (map nginx-location-config (nginx-server-configuration-locations server)) + "\n") + " }\n")) + +(define (nginx-upstream-config upstream) + (string-append + " upstream " (nginx-upstream-configuration-name upstream) " {\n" + (string-concatenate + (map (lambda (server) + (simple-format #f " server ~A;\n" server)) + (nginx-upstream-configuration-servers upstream))) " }\n")) -(define (default-nginx-config log-directory run-directory server-list) - (plain-file "nginx.conf" - (string-append +(define (default-nginx-config log-directory run-directory server-list upstream-list) + (mixed-text-file "nginx.conf" "user nginx nginx;\n" "pid " run-directory "/pid;\n" "error_log " log-directory "/error.log info;\n" @@ -131,12 +192,18 @@ of index files." " uwsgi_temp_path " run-directory "/uwsgi_temp;\n" " scgi_temp_path " run-directory "/scgi_temp;\n" " access_log " log-directory "/access.log;\n" + "\n" + (string-join + (filter (lambda (section) (not (null? section))) + (map nginx-upstream-config upstream-list)) + "\n") + "\n" (let ((http (map default-nginx-server-config server-list))) (do ((http http (cdr http)) (block "" (string-append (car http) "\n" block ))) ((null? http) block))) "}\n" - "events {}\n"))) + "events {}\n")) (define %nginx-accounts (list (user-group (name "nginx") (system? #t)) @@ -151,7 +218,7 @@ of index files." (define nginx-activation (match-lambda (($ <nginx-configuration> nginx log-directory run-directory server-blocks - config-file) + upstream-blocks config-file) #~(begin (use-modules (guix build utils)) @@ -169,13 +236,13 @@ of index files." (system* (string-append #$nginx "/sbin/nginx") "-c" #$(or config-file (default-nginx-config log-directory - run-directory server-blocks)) + run-directory server-blocks upstream-blocks)) "-t"))))) (define nginx-shepherd-service (match-lambda (($ <nginx-configuration> nginx log-directory run-directory server-blocks - config-file) + upstream-blocks config-file) (let* ((nginx-binary (file-append nginx "/sbin/nginx")) (nginx-action (lambda args @@ -184,7 +251,7 @@ of index files." (system* #$nginx-binary "-c" #$(or config-file (default-nginx-config log-directory - run-directory server-blocks)) + run-directory server-blocks upstream-blocks)) #$@args)))))) ;; TODO: Add 'reload' action. @@ -216,6 +283,7 @@ of index files." (log-directory "/var/log/nginx") (run-directory "/var/run/nginx") (server-list '()) + (upstream-list '()) (config-file #f)) "Return a service that runs NGINX, the nginx web server. @@ -227,4 +295,5 @@ files in LOG-DIRECTORY, and stores temporary runtime files in RUN-DIRECTORY." (log-directory log-directory) (run-directory run-directory) (server-blocks server-list) + (upstream-blocks upstream-list) (file config-file)))) |