aboutsummaryrefslogtreecommitdiff
path: root/guix/scripts/system.scm
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2016-05-04 16:38:22 +0200
committerLudovic Courtès <ludo@gnu.org>2016-05-04 23:35:55 +0200
commit8bf92e3904cb656d4c2160fc8befebaf21a65492 (patch)
tree38b708192a69da0dd2e6722250732bbd9bf2177b /guix/scripts/system.scm
parentaf5640d1dd18328dbfec5cb11f73224efd47f1aa (diff)
downloadgnu-guix-8bf92e3904cb656d4c2160fc8befebaf21a65492.tar
gnu-guix-8bf92e3904cb656d4c2160fc8befebaf21a65492.tar.gz
services: herd: Move UI handling to 'guix system'.
This makes (gnu services herd) independent of (guix ui). * gnu/services/herd.scm (&shepherd-error, &service-not-found-error) (&action-not-found-error, &action-exception-error) (&unknown-shepherd-error): New error condition types. (report-action-error): Remove. (raise-shepherd-error): New procedure. (display-message): Do not use 'info' and '_'. (invoke-action): Use 'raise-shepherd-error' instead of 'report-action-error'. Do not use 'warning'. (current-services): Do not use 'warning'. * guix/scripts/system.scm (with-shepherd-error-handling): New macro. (report-shepherd-error, call-with-service-upgrade-info): New procedures. (upgrade-shepherd-services): Use it.
Diffstat (limited to 'guix/scripts/system.scm')
-rw-r--r--guix/scripts/system.scm142
1 files changed, 94 insertions, 48 deletions
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index e5d754a6fa..dd1e534c9b 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -236,6 +236,72 @@ BODY..., and restore them."
(with-monad %store-monad
(return #f)))))
+(define-syntax-rule (with-shepherd-error-handling body ...)
+ (warn-on-system-error
+ (guard (c ((shepherd-error? c)
+ (report-shepherd-error c)))
+ body ...)))
+
+(define (report-shepherd-error error)
+ "Report ERROR, a '&shepherd-error' error condition object."
+ (cond ((service-not-found-error? error)
+ (report-error (_ "service '~a' could not be found~%")
+ (service-not-found-error-service error)))
+ ((action-not-found-error? error)
+ (report-error (_ "service '~a' does not have an action '~a'~%")
+ (action-not-found-error-service error)
+ (action-not-found-error-action error)))
+ ((action-exception-error? error)
+ (report-error (_ "exception caught while executing '~a' \
+on service '~a':~%")
+ (action-exception-error-action error)
+ (action-exception-error-service error))
+ (print-exception (current-error-port) #f
+ (action-exception-error-key error)
+ (action-exception-error-arguments error)))
+ ((unknown-shepherd-error? error)
+ (report-error (_ "something went wrong: ~s~%")
+ (unknown-shepherd-error-sexp error)))
+ ((shepherd-error? error)
+ (report-error (_ "shepherd error~%")))
+ ((not error) ;not an error
+ #t)))
+
+(define (call-with-service-upgrade-info new-services mproc)
+ "Call MPROC, a monadic procedure in %STORE-MONAD, passing it the list of
+names of services to load (upgrade), and the list of names of services to
+unload."
+ (define (essential? service)
+ (memq service '(root shepherd)))
+
+ (define new-service-names
+ (map (compose first shepherd-service-provision)
+ new-services))
+
+ (let-values (((running stopped) (current-services)))
+ (if (and running stopped)
+ (let* ((to-load
+ ;; Only load services that are either new or currently stopped.
+ (remove (lambda (service)
+ (memq (first (shepherd-service-provision service))
+ running))
+ new-services))
+ (to-unload
+ ;; Unload services that are (1) no longer required, or (2) are
+ ;; in TO-LOAD.
+ (remove essential?
+ (append (remove (lambda (service)
+ (memq service new-service-names))
+ (append running stopped))
+ (filter (lambda (service)
+ (memq service stopped))
+ (map shepherd-service-canonical-name
+ to-load))))))
+ (mproc to-load to-unload))
+ (with-monad %store-monad
+ (warning (_ "failed to obtain list of shepherd services~%"))
+ (return #f)))))
+
(define (upgrade-shepherd-services os)
"Upgrade the Shepherd (PID 1) by unloading obsolete services and loading new
services specified in OS and not currently running.
@@ -243,59 +309,35 @@ services specified in OS and not currently running.
This is currently very conservative in that it does not stop or unload any
running service. Unloading or stopping the wrong service ('udev', say) could
bring the system down."
- (define (essential? service)
- (memq service '(root shepherd)))
-
(define new-services
(service-parameters
(fold-services (operating-system-services os)
#:target-type shepherd-root-service-type)))
- (define new-service-names
- (map (compose first shepherd-service-provision)
- new-services))
-
- ;; Arrange to simply emit a warning if we cannot connect to the shepherd.
- (warn-on-system-error
- (let-values (((running stopped) (current-services)))
- (define to-load
- ;; Only load services that are either new or currently stopped.
- (remove (lambda (service)
- (memq (first (shepherd-service-provision service))
- running))
- new-services))
- (define to-unload
- ;; Unload services that are (1) no longer required, or (2) are in
- ;; TO-LOAD.
- (remove essential?
- (append (remove (lambda (service)
- (memq service new-service-names))
- (append running stopped))
- (filter (lambda (service)
- (memq service stopped))
- (map shepherd-service-canonical-name
- to-load)))))
-
- (for-each (lambda (unload)
- (info (_ "unloading service '~a'...~%") unload)
- (unload-service unload))
- to-unload)
-
- (with-monad %store-monad
- (munless (null? to-load)
- (let ((to-load-names (map shepherd-service-canonical-name to-load))
- (to-start (filter shepherd-service-auto-start? to-load)))
- (info (_ "loading new services:~{ ~a~}...~%") to-load-names)
- (mlet %store-monad ((files (mapm %store-monad shepherd-service-file
- to-load)))
- ;; Here we assume that FILES are exactly those that were computed
- ;; as part of the derivation that built OS, which is normally the
- ;; case.
- (load-services (map derivation->output-path files))
-
- (for-each start-service
- (map shepherd-service-canonical-name to-start))
- (return #t))))))))
+ ;; Arrange to simply emit a warning if the service upgrade fails.
+ (with-shepherd-error-handling
+ (call-with-service-upgrade-info new-services
+ (lambda (to-load to-unload)
+ (for-each (lambda (unload)
+ (info (_ "unloading service '~a'...~%") unload)
+ (unload-service unload))
+ to-unload)
+
+ (with-monad %store-monad
+ (munless (null? to-load)
+ (let ((to-load-names (map shepherd-service-canonical-name to-load))
+ (to-start (filter shepherd-service-auto-start? to-load)))
+ (info (_ "loading new services:~{ ~a~}...~%") to-load-names)
+ (mlet %store-monad ((files (mapm %store-monad shepherd-service-file
+ to-load)))
+ ;; Here we assume that FILES are exactly those that were computed
+ ;; as part of the derivation that built OS, which is normally the
+ ;; case.
+ (load-services (map derivation->output-path files))
+
+ (for-each start-service
+ (map shepherd-service-canonical-name to-start))
+ (return #t)))))))))
(define* (switch-to-system os
#:optional (profile %system-profile))
@@ -839,4 +881,8 @@ argument list and OPTS is the option alist."
(parameterize ((%graft? (assoc-ref opts 'graft?)))
(process-command command args opts)))))
+;;; Local Variables:
+;;; eval: (put 'call-with-service-upgrade-info 'scheme-indent-function 1)
+;;; End:
+
;;; system.scm ends here