summaryrefslogtreecommitdiff
path: root/gnu/services
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/services')
-rw-r--r--gnu/services/base.scm194
-rw-r--r--gnu/services/cuirass.scm16
-rw-r--r--gnu/services/cups.scm2
-rw-r--r--gnu/services/mail.scm2
-rw-r--r--gnu/services/messaging.scm6
-rw-r--r--gnu/services/networking.scm379
-rw-r--r--gnu/services/shepherd.scm2
-rw-r--r--gnu/services/spice.scm5
-rw-r--r--gnu/services/ssh.scm3
-rw-r--r--gnu/services/vpn.scm494
-rw-r--r--gnu/services/web.scm97
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))))