shepherd.scm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2013, 2014, 2015, 2016, 2018 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
  4. ;;; Copyright © 2018 Carlo Zancanaro <carlo@zancanaro.id.au>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  8. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  9. ;;; under the terms of the GNU General Public License as published by
  10. ;;; the Free Software Foundation; either version 3 of the License, or (at
  11. ;;; your option) any later version.
  12. ;;;
  13. ;;; GNU Guix is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;;; GNU General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU General Public License
  19. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (gnu services shepherd)
  21. #:use-module (guix ui)
  22. #:use-module (guix sets)
  23. #:use-module (guix gexp)
  24. #:use-module (guix store)
  25. #:use-module (guix records)
  26. #:use-module (guix derivations) ;imported-modules, etc.
  27. #:use-module (gnu services)
  28. #:use-module (gnu services herd)
  29. #:use-module (gnu packages admin)
  30. #:use-module (ice-9 match)
  31. #:use-module (ice-9 vlist)
  32. #:use-module (srfi srfi-1)
  33. #:use-module (srfi srfi-26)
  34. #:use-module (srfi srfi-34)
  35. #:use-module (srfi srfi-35)
  36. #:export (shepherd-root-service-type
  37. %shepherd-root-service
  38. shepherd-service-type
  39. shepherd-service
  40. shepherd-service?
  41. shepherd-service-documentation
  42. shepherd-service-provision
  43. shepherd-service-canonical-name
  44. shepherd-service-requirement
  45. shepherd-service-respawn?
  46. shepherd-service-start
  47. shepherd-service-stop
  48. shepherd-service-auto-start?
  49. shepherd-service-modules
  50. shepherd-action
  51. shepherd-action?
  52. shepherd-action-name
  53. shepherd-action-documentation
  54. shepherd-action-procedure
  55. %default-modules
  56. shepherd-service-file
  57. %containerized-shepherd-service
  58. shepherd-service-lookup-procedure
  59. shepherd-service-back-edges
  60. shepherd-service-upgrade))
  61. ;;; Commentary:
  62. ;;;
  63. ;;; Instantiating system services as a shepherd configuration file.
  64. ;;;
  65. ;;; Code:
  66. (define (shepherd-boot-gexp services)
  67. #~(begin
  68. ;; Keep track of the booted system.
  69. (false-if-exception (delete-file "/run/booted-system"))
  70. (symlink (readlink "/run/current-system")
  71. "/run/booted-system")
  72. ;; Close any remaining open file descriptors to be on the safe
  73. ;; side. This must be the very last thing we do, because
  74. ;; Guile has internal FDs such as 'sleep_pipe' that need to be
  75. ;; alive.
  76. (let loop ((fd 3))
  77. (when (< fd 1024)
  78. (false-if-exception (close-fdes fd))
  79. (loop (+ 1 fd))))
  80. ;; Start shepherd.
  81. (execl #$(file-append shepherd "/bin/shepherd")
  82. "shepherd" "--config"
  83. #$(shepherd-configuration-file services))))
  84. (define shepherd-root-service-type
  85. (service-type
  86. (name 'shepherd-root)
  87. ;; Extending the root shepherd service (aka. PID 1) happens by
  88. ;; concatenating the list of services provided by the extensions.
  89. (compose concatenate)
  90. (extend append)
  91. (extensions (list (service-extension boot-service-type
  92. shepherd-boot-gexp)
  93. (service-extension profile-service-type
  94. (const (list shepherd)))))))
  95. (define %shepherd-root-service
  96. ;; The root shepherd service, aka. PID 1. Its parameter is a list of
  97. ;; <shepherd-service> objects.
  98. (service shepherd-root-service-type '()))
  99. (define-syntax shepherd-service-type
  100. (syntax-rules ()
  101. "Return a <service-type> denoting a simple shepherd service--i.e., the type
  102. for a service that extends SHEPHERD-ROOT-SERVICE-TYPE and nothing else. When
  103. DEFAULT is given, use it as the service's default value."
  104. ((_ service-name proc default)
  105. (service-type
  106. (name service-name)
  107. (extensions
  108. (list (service-extension shepherd-root-service-type
  109. (compose list proc))))
  110. (default-value default)))
  111. ((_ service-name proc)
  112. (service-type
  113. (name service-name)
  114. (extensions
  115. (list (service-extension shepherd-root-service-type
  116. (compose list proc))))))))
  117. (define %default-imported-modules
  118. ;; Default set of modules imported for a service's consumption.
  119. '((guix build utils)
  120. (guix build syscalls)))
  121. (define %default-modules
  122. ;; Default set of modules visible in a service's file.
  123. `((shepherd service)
  124. (oop goops)
  125. (guix build utils)
  126. (guix build syscalls)))
  127. (define-record-type* <shepherd-service>
  128. shepherd-service make-shepherd-service
  129. shepherd-service?
  130. (documentation shepherd-service-documentation ;string
  131. (default "[No documentation.]"))
  132. (provision shepherd-service-provision) ;list of symbols
  133. (requirement shepherd-service-requirement ;list of symbols
  134. (default '()))
  135. (respawn? shepherd-service-respawn? ;Boolean
  136. (default #t))
  137. (start shepherd-service-start) ;g-expression (procedure)
  138. (stop shepherd-service-stop ;g-expression (procedure)
  139. (default #~(const #f)))
  140. (actions shepherd-service-actions ;list of <shepherd-action>
  141. (default '()))
  142. (auto-start? shepherd-service-auto-start? ;Boolean
  143. (default #t))
  144. (modules shepherd-service-modules ;list of module names
  145. (default %default-modules)))
  146. (define-record-type* <shepherd-action>
  147. shepherd-action make-shepherd-action
  148. shepherd-action?
  149. (name shepherd-action-name) ;symbol
  150. (procedure shepherd-action-procedure) ;gexp
  151. (documentation shepherd-action-documentation)) ;string
  152. (define (shepherd-service-canonical-name service)
  153. "Return the 'canonical name' of SERVICE."
  154. (first (shepherd-service-provision service)))
  155. (define (assert-valid-graph services)
  156. "Raise an error if SERVICES does not define a valid shepherd service graph,
  157. for instance if a service requires a nonexistent service, or if more than one
  158. service uses a given name.
  159. These are constraints that shepherd's 'register-service' verifies but we'd
  160. better verify them here statically than wait until PID 1 halts with an
  161. assertion failure."
  162. (define provisions
  163. ;; The set of provisions (symbols). Bail out if a symbol is given more
  164. ;; than once.
  165. (fold (lambda (service set)
  166. (define (assert-unique symbol)
  167. (when (set-contains? set symbol)
  168. (raise (condition
  169. (&message
  170. (message
  171. (format #f (G_ "service '~a' provided more than once")
  172. symbol)))))))
  173. (for-each assert-unique (shepherd-service-provision service))
  174. (fold set-insert set (shepherd-service-provision service)))
  175. (setq 'shepherd)
  176. services))
  177. (define (assert-satisfied-requirements service)
  178. ;; Bail out if the requirements of SERVICE aren't satisfied.
  179. (for-each (lambda (requirement)
  180. (unless (set-contains? provisions requirement)
  181. (raise (condition
  182. (&message
  183. (message
  184. (format #f (G_ "service '~a' requires '~a', \
  185. which is not provided by any service")
  186. (match (shepherd-service-provision service)
  187. ((head . _) head)
  188. (_ service))
  189. requirement)))))))
  190. (shepherd-service-requirement service)))
  191. (for-each assert-satisfied-requirements services))
  192. (define (shepherd-service-file-name service)
  193. "Return the file name where the initialization code for SERVICE is to be
  194. stored."
  195. (let ((provisions (string-join (map symbol->string
  196. (shepherd-service-provision service)))))
  197. (string-append "shepherd-"
  198. (string-map (match-lambda
  199. (#\/ #\-)
  200. (#\ #\-)
  201. (chr chr))
  202. provisions)
  203. ".scm")))
  204. (define (shepherd-service-file service)
  205. "Return a file defining SERVICE."
  206. (scheme-file (shepherd-service-file-name service)
  207. (with-imported-modules %default-imported-modules
  208. #~(begin
  209. (use-modules #$@(shepherd-service-modules service))
  210. (make <service>
  211. #:docstring '#$(shepherd-service-documentation service)
  212. #:provides '#$(shepherd-service-provision service)
  213. #:requires '#$(shepherd-service-requirement service)
  214. #:respawn? '#$(shepherd-service-respawn? service)
  215. #:start #$(shepherd-service-start service)
  216. #:stop #$(shepherd-service-stop service)
  217. #:actions
  218. (make-actions
  219. #$@(map (match-lambda
  220. (($ <shepherd-action> name proc doc)
  221. #~(#$name #$doc #$proc)))
  222. (shepherd-service-actions service))))))))
  223. (define (shepherd-configuration-file services)
  224. "Return the shepherd configuration file for SERVICES."
  225. (assert-valid-graph services)
  226. (let ((files (map shepherd-service-file services)))
  227. (define config
  228. #~(begin
  229. (use-modules (srfi srfi-34)
  230. (system repl error-handling))
  231. ;; Arrange to spawn a REPL if something goes wrong. This is better
  232. ;; than a kernel panic.
  233. (call-with-error-handling
  234. (lambda ()
  235. (apply register-services (map primitive-load '#$files))
  236. ;; guix-daemon 0.6 aborts if 'PATH' is undefined, so work around
  237. ;; it.
  238. (setenv "PATH" "/run/current-system/profile/bin")
  239. (format #t "starting services...~%")
  240. (for-each (lambda (service)
  241. ;; In the Shepherd 0.3 the 'start' method can raise
  242. ;; '&action-runtime-error' if it fails, so protect
  243. ;; against it. (XXX: 'action-runtime-error?' is not
  244. ;; exported is 0.3, hence 'service-error?'.)
  245. (guard (c ((service-error? c)
  246. (format (current-error-port)
  247. "failed to start service '~a'~%"
  248. service)))
  249. (start service)))
  250. '#$(append-map shepherd-service-provision
  251. (filter shepherd-service-auto-start?
  252. services)))
  253. ;; Hang up stdin. At this point, we assume that 'start' methods
  254. ;; that required user interaction on the console (e.g.,
  255. ;; 'cryptsetup open' invocations, post-fsck emergency REPL) have
  256. ;; completed. User interaction becomes impossible after this
  257. ;; call; this avoids situations where services wrongfully lead
  258. ;; PID 1 to read from stdin (the console), which users may not
  259. ;; have access to (see <https://bugs.gnu.org/23697>).
  260. (redirect-port (open-input-file "/dev/null")
  261. (current-input-port))))))
  262. (scheme-file "shepherd.conf" config)))
  263. (define* (shepherd-service-lookup-procedure services
  264. #:optional
  265. (provision
  266. shepherd-service-provision))
  267. "Return a procedure that, when passed a symbol, return the item among
  268. SERVICES that provides this symbol. PROVISION must be a one-argument
  269. procedure that takes a service and returns the list of symbols it provides."
  270. (let ((services (fold (lambda (service result)
  271. (fold (cut vhash-consq <> service <>)
  272. result
  273. (provision service)))
  274. vlist-null
  275. services)))
  276. (lambda (name)
  277. (match (vhash-assq name services)
  278. ((_ . service) service)
  279. (#f #f)))))
  280. (define* (shepherd-service-back-edges services
  281. #:key
  282. (provision shepherd-service-provision)
  283. (requirement shepherd-service-requirement))
  284. "Return a procedure that, when given a <shepherd-service> from SERVICES,
  285. returns the list of <shepherd-service> that depend on it.
  286. Use PROVISION and REQUIREMENT as one-argument procedures that return the
  287. symbols provided/required by a service."
  288. (define provision->service
  289. (shepherd-service-lookup-procedure services provision))
  290. (define edges
  291. (fold (lambda (service edges)
  292. (fold (lambda (requirement edges)
  293. (vhash-consq (provision->service requirement) service
  294. edges))
  295. edges
  296. (requirement service)))
  297. vlist-null
  298. services))
  299. (lambda (service)
  300. (vhash-foldq* cons '() service edges)))
  301. (define %containerized-shepherd-service
  302. ;; XXX: This service works around a bug in the Shepherd 0.5.0: shepherd
  303. ;; calls reboot(2) (via 'disable-reboot-on-ctrl-alt-del') when it starts,
  304. ;; but in a container that fails with EINVAL. This was fixed in Shepherd
  305. ;; commit 92e806bac1abaeeaf5d60f0ab50d1ae85ba6a62f.
  306. (simple-service 'containerized-shepherd
  307. shepherd-root-service-type
  308. (list (shepherd-service
  309. (provision '(containerized-shepherd))
  310. (start #~(lambda ()
  311. (set! (@@ (shepherd)
  312. disable-reboot-on-ctrl-alt-del)
  313. (const #t))
  314. #t))))))
  315. (define (shepherd-service-upgrade live target)
  316. "Return two values: the subset of LIVE (a list of <live-service>) that needs
  317. to be unloaded, and the subset of TARGET (a list of <shepherd-service>) that
  318. need to be restarted to complete their upgrade."
  319. (define (essential? service)
  320. (memq (first (live-service-provision service))
  321. '(root shepherd)))
  322. (define lookup-target
  323. (shepherd-service-lookup-procedure target
  324. shepherd-service-provision))
  325. (define lookup-live
  326. (shepherd-service-lookup-procedure live
  327. live-service-provision))
  328. (define (running? service)
  329. (and=> (lookup-live (shepherd-service-canonical-name service))
  330. live-service-running))
  331. (define live-service-dependents
  332. (shepherd-service-back-edges live
  333. #:provision live-service-provision
  334. #:requirement live-service-requirement))
  335. (define (obsolete? service)
  336. (match (lookup-target (first (live-service-provision service)))
  337. (#f (every obsolete? (live-service-dependents service)))
  338. (_ #f)))
  339. (define to-restart
  340. ;; Restart services that are currently running.
  341. (filter running? target))
  342. (define to-unload
  343. ;; Unload services that are no longer required.
  344. (remove essential? (filter obsolete? live)))
  345. (values to-unload to-restart))
  346. ;;; shepherd.scm ends here