summaryrefslogtreecommitdiff
path: root/gnu/machine
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2020-03-20 12:08:10 +0100
committerLudovic Courtès <ludo@gnu.org>2020-03-23 10:48:17 +0100
commitea6e2299b40c6fbd9749563c52a2d77698bd9337 (patch)
tree71e1e8f02277b8f905a82d2110d93de49dc7bba4 /gnu/machine
parent8f53d73493a2949e2db28cd7d689a690b2d9479a (diff)
machine: ssh: Make sanity checks in a single round trip.
* gnu/machine/ssh.scm (<remote-assertion>): New record type. (remote-let): New macro. (machine-check-file-system-availability): Rewrite to use 'remote-let' instead of 'mlet' and 'machine-remote-eval'. (machine-check-initrd-modules): Likewise. (machine-check-building-for-appropriate-system): Make non-monadic. (check-deployment-sanity): Rewrite to gather all the assertions as a single gexp and pass it to 'machine-remote-eval'.
Diffstat (limited to 'gnu/machine')
-rw-r--r--gnu/machine/ssh.scm142
1 files changed, 83 insertions, 59 deletions
diff --git a/gnu/machine/ssh.scm b/gnu/machine/ssh.scm
index 6374373e22a..85ecbb6d143 100644
--- a/gnu/machine/ssh.scm
+++ b/gnu/machine/ssh.scm
@@ -1,5 +1,6 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2019 Jakob L. Kreuze <zerodaysfordays@sdf.org> 2;;; Copyright © 2019 Jakob L. Kreuze <zerodaysfordays@sdf.org>
3;;; Copyright © 2020 Ludovic Courtès <ludo@gnu.org>
3;;; 4;;;
4;;; This file is part of GNU Guix. 5;;; This file is part of GNU Guix.
5;;; 6;;;
@@ -39,6 +40,7 @@
39 #:use-module (ice-9 match) 40 #:use-module (ice-9 match)
40 #:use-module (ice-9 textual-ports) 41 #:use-module (ice-9 textual-ports)
41 #:use-module (srfi srfi-1) 42 #:use-module (srfi srfi-1)
43 #:use-module (srfi srfi-9)
42 #:use-module (srfi srfi-19) 44 #:use-module (srfi srfi-19)
43 #:use-module (srfi srfi-26) 45 #:use-module (srfi srfi-26)
44 #:use-module (srfi srfi-34) 46 #:use-module (srfi srfi-34)
@@ -142,9 +144,24 @@ an environment type of 'managed-host."
142;;; Safety checks. 144;;; Safety checks.
143;;; 145;;;
144 146
147;; Assertion to be executed remotely. This abstraction exists to allow us to
148;; gather a list of expressions to be evaluated and eventually evaluate them
149;; all at once instead of one by one. (This is pretty much a monad.)
150(define-record-type <remote-assertion>
151 (remote-assertion exp proc)
152 remote-assertion?
153 (exp remote-assertion-expression)
154 (proc remote-assertion-procedure))
155
156(define-syntax-rule (remote-let ((var exp)) body ...)
157 "Return a <remote-assertion> that binds VAR to the result of evaluating EXP,
158a gexp, remotely, and evaluate BODY in that context."
159 (remote-assertion exp (lambda (var) body ...)))
160
145(define (machine-check-file-system-availability machine) 161(define (machine-check-file-system-availability machine)
146 "Raise a '&message' error condition if any of the file-systems specified in 162 "Return a list of <remote-assertion> that raise a '&message' error condition
147MACHINE's 'system' declaration do not exist on the machine." 163if any of the file-systems specified in MACHINE's 'system' declaration do not
164exist on the machine."
148 (define file-systems 165 (define file-systems
149 (filter (lambda (fs) 166 (filter (lambda (fs)
150 (and (file-system-mount? fs) 167 (and (file-system-mount? fs)
@@ -154,22 +171,18 @@ MACHINE's 'system' declaration do not exist on the machine."
154 (operating-system-file-systems (machine-operating-system machine)))) 171 (operating-system-file-systems (machine-operating-system machine))))
155 172
156 (define (check-literal-file-system fs) 173 (define (check-literal-file-system fs)
157 (define remote-exp 174 (remote-let ((errno #~(catch 'system-error
158 #~(catch 'system-error 175 (lambda ()
159 (lambda () 176 (stat #$(file-system-device fs))
160 (stat #$(file-system-device fs)) 177 #t)
161 #t) 178 (lambda args
162 (lambda args 179 (system-error-errno args)))))
163 (system-error-errno args))))
164
165 (mlet %store-monad ((errno (machine-remote-eval machine remote-exp)))
166 (when (number? errno) 180 (when (number? errno)
167 (raise (condition 181 (raise (condition
168 (&message 182 (&message
169 (message (format #f (G_ "device '~a' not found: ~a") 183 (message (format #f (G_ "device '~a' not found: ~a")
170 (file-system-device fs) 184 (file-system-device fs)
171 (strerror errno))))))) 185 (strerror errno)))))))))
172 (return #t)))
173 186
174 (define (check-labeled-file-system fs) 187 (define (check-labeled-file-system fs)
175 (define remote-exp 188 (define remote-exp
@@ -180,14 +193,13 @@ MACHINE's 'system' declaration do not exist on the machine."
180 (find-partition-by-label #$(file-system-label->string 193 (find-partition-by-label #$(file-system-label->string
181 (file-system-device fs)))))) 194 (file-system-device fs))))))
182 195
183 (mlet %store-monad ((result (machine-remote-eval machine remote-exp))) 196 (remote-let ((result remote-exp))
184 (unless result 197 (unless result
185 (raise (condition 198 (raise (condition
186 (&message 199 (&message
187 (message (format #f (G_ "no file system with label '~a'") 200 (message (format #f (G_ "no file system with label '~a'")
188 (file-system-label->string 201 (file-system-label->string
189 (file-system-device fs)))))))) 202 (file-system-device fs))))))))))
190 (return #t)))
191 203
192 (define (check-uuid-file-system fs) 204 (define (check-uuid-file-system fs)
193 (define remote-exp 205 (define remote-exp
@@ -203,31 +215,30 @@ MACHINE's 'system' declaration do not exist on the machine."
203 215
204 (find-partition-by-uuid uuid)))) 216 (find-partition-by-uuid uuid))))
205 217
206 (mlet %store-monad ((result (machine-remote-eval machine remote-exp))) 218 (remote-let ((result remote-exp))
207 (unless result 219 (unless result
208 (raise (condition 220 (raise (condition
209 (&message 221 (&message
210 (message (format #f (G_ "no file system with UUID '~a'") 222 (message (format #f (G_ "no file system with UUID '~a'")
211 (uuid->string (file-system-device fs)))))))) 223 (uuid->string (file-system-device fs))))))))))
212 (return #t))) 224
213 225 (append (map check-literal-file-system
214 (mbegin %store-monad 226 (filter (lambda (fs)
215 (mapm %store-monad check-literal-file-system 227 (string? (file-system-device fs)))
216 (filter (lambda (fs) 228 file-systems))
217 (string? (file-system-device fs))) 229 (map check-labeled-file-system
218 file-systems)) 230 (filter (lambda (fs)
219 (mapm %store-monad check-labeled-file-system 231 (file-system-label? (file-system-device fs)))
220 (filter (lambda (fs) 232 file-systems))
221 (file-system-label? (file-system-device fs))) 233 (map check-uuid-file-system
222 file-systems)) 234 (filter (lambda (fs)
223 (mapm %store-monad check-uuid-file-system 235 (uuid? (file-system-device fs)))
224 (filter (lambda (fs) 236 file-systems))))
225 (uuid? (file-system-device fs)))
226 file-systems))))
227 237
228(define (machine-check-initrd-modules machine) 238(define (machine-check-initrd-modules machine)
229 "Raise a '&message' error condition if any of the modules needed by 239 "Return a list of <remote-assertion> that raise a '&message' error condition
230'needed-for-boot' file systems in MACHINE are not available in the initrd." 240if any of the modules needed by 'needed-for-boot' file systems in MACHINE are
241not available in the initrd."
231 (define file-systems 242 (define file-systems
232 (filter file-system-needed-for-boot? 243 (filter file-system-needed-for-boot?
233 (operating-system-file-systems (machine-operating-system machine)))) 244 (operating-system-file-systems (machine-operating-system machine))))
@@ -255,20 +266,16 @@ MACHINE's 'system' declaration do not exist on the machine."
255 266
256 (missing-modules dev '#$(operating-system-initrd-modules 267 (missing-modules dev '#$(operating-system-initrd-modules
257 (machine-operating-system machine))))))) 268 (machine-operating-system machine)))))))
258 (mlet %store-monad ((missing (machine-remote-eval machine remote-exp))) 269
259 (return (list fs missing)))) 270 (remote-let ((missing remote-exp))
260 271 (unless (null? missing)
261 (mlet %store-monad ((device (mapm %store-monad missing-modules file-systems))) 272 (raise (condition
262 (for-each (match-lambda 273 (&message
263 ((fs missing) 274 (message (format #f (G_ "~a missing modules ~{ ~a~}~%")
264 (unless (null? missing) 275 (file-system-device fs)
265 (raise (condition 276 missing))))))))
266 (&message 277
267 (message (format #f (G_ "~a missing modules ~{ ~a~}~%") 278 (map missing-modules file-systems))
268 (file-system-device fs)
269 missing))))))))
270 device)
271 (return #t)))
272 279
273(define (machine-check-building-for-appropriate-system machine) 280(define (machine-check-building-for-appropriate-system machine)
274 "Raise a '&message' error condition if MACHINE is configured to be built 281 "Raise a '&message' error condition if MACHINE is configured to be built
@@ -280,21 +287,38 @@ by MACHINE."
280 (not (string= system (machine-ssh-configuration-system config)))) 287 (not (string= system (machine-ssh-configuration-system config))))
281 (raise (condition 288 (raise (condition
282 (&message 289 (&message
283 (message (format #f (G_ "incorrect target system \ 290 (message (format #f (G_ "incorrect target system\
284('~a' was given, while the system reports that it is '~a')~%") 291 ('~a' was given, while the system reports that it is '~a')~%")
285 (machine-ssh-configuration-system config) 292 (machine-ssh-configuration-system config)
286 system))))))) 293 system))))))))
287 (with-monad %store-monad (return #t)))
288 294
289(define (check-deployment-sanity machine) 295(define (check-deployment-sanity machine)
290 "Raise a '&message' error condition if it is clear that deploying MACHINE's 296 "Raise a '&message' error condition if it is clear that deploying MACHINE's
291'system' declaration would fail." 297'system' declaration would fail."
292 ;; Order is important here -- an incorrect value for 'system' will cause 298 (define assertions
293 ;; invocations of 'remote-eval' to fail. 299 (append (machine-check-file-system-availability machine)
294 (mbegin %store-monad 300 (machine-check-initrd-modules machine)))
295 (machine-check-building-for-appropriate-system machine) 301
296 (machine-check-file-system-availability machine) 302 (define aggregate-exp
297 (machine-check-initrd-modules machine))) 303 ;; Gather all the expressions so that a single round-trip is enough to
304 ;; evaluate all the ASSERTIONS remotely.
305 #~(map (lambda (file)
306 (false-if-exception (primitive-load file)))
307 '#$(map (lambda (assertion)
308 (scheme-file "remote-assertion.scm"
309 (remote-assertion-expression assertion)))
310 assertions)))
311
312 ;; First check MACHINE's system type--an incorrect value for 'system' would
313 ;; cause subsequent invocations of 'remote-eval' to fail.
314 (machine-check-building-for-appropriate-system machine)
315
316 (mlet %store-monad ((values (machine-remote-eval machine aggregate-exp)))
317 (for-each (lambda (proc value)
318 (proc value))
319 (map remote-assertion-procedure assertions)
320 values)
321 (return #t)))
298 322
299 323
300;;; 324;;;