services: networking: Remove unbound variable reference in 'stop'.
[jackhill/guix/guix.git] / gnu / services / herd.scm
CommitLineData
240b57f0 1;;; GNU Guix --- Functional package management for GNU
89a26478 2;;; Copyright © 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
5e03b122 3;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
240b57f0
LC
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (gnu services herd)
240b57f0 21 #:use-module (srfi srfi-1)
183605c8 22 #:use-module (srfi srfi-9)
240b57f0 23 #:use-module (srfi srfi-11)
8bf92e39
LC
24 #:use-module (srfi srfi-34)
25 #:use-module (srfi srfi-35)
240b57f0 26 #:use-module (ice-9 match)
5e03b122
MO
27 #:export (%shepherd-socket-file
28
29 shepherd-error?
8bf92e39
LC
30 service-not-found-error?
31 service-not-found-error-service
32 action-not-found-error?
33 action-not-found-error-service
34 action-not-found-error-action
35 action-exception-error?
36 action-exception-error-service
37 action-exception-error-action
38 action-exception-error-key
39 action-exception-error-arguments
40 unknown-shepherd-error?
41 unknown-shepherd-error-sexp
42
183605c8
LC
43 live-service?
44 live-service-provision
45 live-service-requirement
46 live-service-running
47
147c5aa5 48 with-shepherd-action
8bf92e39 49 current-services
240b57f0
LC
50 unload-services
51 unload-service
52 load-services
0642838b
CB
53 start-service
54 stop-service))
240b57f0
LC
55
56;;; Commentary:
57;;;
58;;; This module provides an interface to the GNU Shepherd, similar to the
59;;; 'herd' command. Essentially it implements a subset of the (shepherd comm)
60;;; module, but focusing only on the parts relevant to 'guix system
61;;; reconfigure'.
62;;;
63;;; Code:
64
65(define %shepherd-socket-file
5e03b122 66 (make-parameter "/var/run/shepherd/socket"))
240b57f0 67
5e03b122 68(define* (open-connection #:optional (file (%shepherd-socket-file)))
240b57f0
LC
69 "Open a connection to the daemon, using the Unix-domain socket at FILE, and
70return the socket."
71 ;; The protocol is sexp-based and UTF-8-encoded.
72 (with-fluids ((%default-port-encoding "UTF-8"))
73 (let ((sock (socket PF_UNIX SOCK_STREAM 0))
74 (address (make-socket-address PF_UNIX file)))
75 (catch 'system-error
76 (lambda ()
77 (connect sock address)
78 (setvbuf sock _IOFBF 1024)
79 sock)
1d6b7d58
LC
80 (lambda args
81 (close-port sock)
82 (apply throw args))))))
240b57f0
LC
83
84(define-syntax-rule (with-shepherd connection body ...)
85 "Evaluate BODY... with CONNECTION bound to an open socket to PID 1."
86 (let ((connection (open-connection)))
89a26478
LC
87 (dynamic-wind
88 (const #t)
89 (lambda ()
90 body ...)
91 (lambda ()
92 (close-port connection)))))
240b57f0 93
8bf92e39
LC
94(define-condition-type &shepherd-error &error
95 shepherd-error?)
96
97(define-condition-type &service-not-found-error &shepherd-error
98 service-not-found-error?
99 (service service-not-found-error-service))
100
101(define-condition-type &action-not-found-error &shepherd-error
102 action-not-found-error?
103 (service action-not-found-error-service)
104 (action action-not-found-error-action))
105
106(define-condition-type &action-exception-error &shepherd-error
107 action-exception-error?
108 (service action-exception-error-service)
109 (action action-exception-error-action)
110 (key action-exception-error-key)
111 (args action-exception-error-arguments))
112
113(define-condition-type &unknown-shepherd-error &shepherd-error
114 unknown-shepherd-error?
115 (sexp unknown-shepherd-error-sexp))
116
117(define (raise-shepherd-error error)
118 "Raise an error condition corresponding to ERROR, an sexp received by a
119shepherd client in reply to COMMAND, a command object. Return #t if ERROR
120does not denote an error."
240b57f0
LC
121 (match error
122 (('error ('version 0 x ...) 'service-not-found service)
8bf92e39
LC
123 (raise (condition (&service-not-found-error
124 (service service)))))
240b57f0 125 (('error ('version 0 x ...) 'action-not-found action service)
8bf92e39
LC
126 (raise (condition (&action-not-found-error
127 (service service)
128 (action action)))))
240b57f0
LC
129 (('error ('version 0 x ...) 'action-exception action service
130 key (args ...))
8bf92e39
LC
131 (raise (condition (&action-exception-error
132 (service service)
133 (action action)
134 (key key) (args args)))))
240b57f0 135 (('error . _)
8bf92e39 136 (raise (condition (&unknown-shepherd-error (sexp error)))))
240b57f0
LC
137 (#f ;not an error
138 #t)))
139
140(define (display-message message)
8bf92e39 141 (format (current-error-port) "shepherd: ~a~%" message))
240b57f0
LC
142
143(define* (invoke-action service action arguments cont)
144 "Invoke ACTION on SERVICE with ARGUMENTS. On success, call CONT with the
7d14082d
LC
145list of results (one result per instance with the name SERVICE). Otherwise
146return #f."
240b57f0
LC
147 (with-shepherd sock
148 (write `(shepherd-command (version 0)
149 (action ,action)
150 (service ,service)
151 (arguments ,arguments)
152 (directory ,(getcwd)))
153 sock)
154 (force-output sock)
155
156 (match (read sock)
dc7b3e56 157 (('reply ('version 0 _ ...) ('result result) ('error #f)
240b57f0
LC
158 ('messages messages))
159 (for-each display-message messages)
160 (cont result))
161 (('reply ('version 0 x ...) ('result y) ('error error)
162 ('messages messages))
163 (for-each display-message messages)
8bf92e39 164 (raise-shepherd-error error)
240b57f0
LC
165 #f)
166 (x
8bf92e39 167 ;; invalid reply
240b57f0
LC
168 #f))))
169
170(define-syntax-rule (with-shepherd-action service (action args ...)
171 result body ...)
147c5aa5
LC
172 "Invoke ACTION on SERVICE with the given ARGS, and evaluate BODY with RESULT
173bound to the action's result."
240b57f0
LC
174 (invoke-action service action (list args ...)
175 (lambda (result) body ...)))
176
177(define-syntax alist-let*
178 (syntax-rules ()
179 "Bind the given KEYs in EXP to the corresponding items in ALIST. ALIST
180is assumed to be a list of two-element tuples rather than a traditional list
181of pairs."
182 ((_ alist (key ...) exp ...)
183 (let ((key (and=> (assoc-ref alist 'key) car)) ...)
184 exp ...))))
185
183605c8
LC
186;; Information about live Shepherd services.
187(define-record-type <live-service>
188 (live-service provision requirement running)
189 live-service?
190 (provision live-service-provision) ;list of symbols
191 (requirement live-service-requirement) ;list of symbols
192 (running live-service-running)) ;#f | object
193
240b57f0 194(define (current-services)
183605c8
LC
195 "Return the list of currently defined Shepherd services, represented as
196<live-service> objects. Return #f if the list of services could not be
197obtained."
7d14082d
LC
198 (with-shepherd-action 'root ('status) results
199 ;; We get a list of results, one for each service with the name 'root'.
200 ;; In practice there's only one such service though.
201 (match results
202 ((services _ ...)
203 (match services
204 ((('service ('version 0 _ ...) _ ...) ...)
205 (map (lambda (service)
206 (alist-let* service (provides requires running)
207 (live-service provides requires running)))
208 services))
209 (x
210 #f))))))
240b57f0
LC
211
212(define (unload-service service)
213 "Unload SERVICE, a symbol name; return #t on success."
214 (with-shepherd-action 'root ('unload (symbol->string service)) result
7d14082d 215 (first result)))
240b57f0
LC
216
217(define (%load-file file)
218 "Load FILE in the Shepherd."
219 (with-shepherd-action 'root ('load file) result
7d14082d 220 (first result)))
240b57f0
LC
221
222(define (eval-there exp)
223 "Eval EXP in the Shepherd."
224 (with-shepherd-action 'root ('eval (object->string exp)) result
7d14082d 225 (first result)))
240b57f0
LC
226
227(define (load-services files)
228 "Load and register the services from FILES, where FILES contain code that
229returns a shepherd <service> object."
230 (eval-there `(register-services
231 ,@(map (lambda (file)
232 `(primitive-load ,file))
233 files))))
234
235(define (start-service name)
236 (with-shepherd-action name ('start) result
237 result))
238
0642838b
CB
239(define (stop-service name)
240 (with-shepherd-action name ('stop) result
241 result))
242
240b57f0
LC
243;; Local Variables:
244;; eval: (put 'alist-let* 'scheme-indent-function 2)
245;; eval: (put 'with-shepherd 'scheme-indent-function 1)
246;; eval: (put 'with-shepherd-action 'scheme-indent-function 3)
247;; End:
248
249;;; herd.scm ends here