diff options
| -rw-r--r-- | gnu/machine.scm | 27 | ||||
| -rw-r--r-- | gnu/machine/ssh.scm | 72 | ||||
| -rw-r--r-- | guix/scripts/deploy.scm | 17 |
3 files changed, 110 insertions, 6 deletions
diff --git a/gnu/machine.scm b/gnu/machine.scm index 30ae97f6ecb..05b03b21d49 100644 --- a/gnu/machine.scm +++ b/gnu/machine.scm | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #:use-module (guix records) | 24 | #:use-module (guix records) |
| 25 | #:use-module (guix store) | 25 | #:use-module (guix store) |
| 26 | #:use-module ((guix utils) #:select (source-properties->location)) | 26 | #:use-module ((guix utils) #:select (source-properties->location)) |
| 27 | #:use-module (srfi srfi-35) | ||
| 27 | #:export (environment-type | 28 | #:export (environment-type |
| 28 | environment-type? | 29 | environment-type? |
| 29 | environment-type-name | 30 | environment-type-name |
| @@ -40,7 +41,13 @@ | |||
| 40 | machine-display-name | 41 | machine-display-name |
| 41 | 42 | ||
| 42 | deploy-machine | 43 | deploy-machine |
| 43 | machine-remote-eval)) | 44 | roll-back-machine |
| 45 | machine-remote-eval | ||
| 46 | |||
| 47 | &deploy-error | ||
| 48 | deploy-error? | ||
| 49 | deploy-error-should-roll-back | ||
| 50 | deploy-error-captured-args)) | ||
| 44 | 51 | ||
| 45 | ;;; Commentary: | 52 | ;;; Commentary: |
| 46 | ;;; | 53 | ;;; |
| @@ -66,6 +73,7 @@ | |||
| 66 | ;; of the form '(machine-remote-eval machine exp)'. | 73 | ;; of the form '(machine-remote-eval machine exp)'. |
| 67 | (machine-remote-eval environment-type-machine-remote-eval) ; procedure | 74 | (machine-remote-eval environment-type-machine-remote-eval) ; procedure |
| 68 | (deploy-machine environment-type-deploy-machine) ; procedure | 75 | (deploy-machine environment-type-deploy-machine) ; procedure |
| 76 | (roll-back-machine environment-type-roll-back-machine) ; procedure | ||
| 69 | 77 | ||
| 70 | ;; Metadata. | 78 | ;; Metadata. |
| 71 | (name environment-type-name) ; symbol | 79 | (name environment-type-name) ; symbol |
| @@ -105,3 +113,20 @@ are built and deployed to MACHINE beforehand." | |||
| 105 | MACHINE, activating it on MACHINE and switching MACHINE to the new generation." | 113 | MACHINE, activating it on MACHINE and switching MACHINE to the new generation." |
| 106 | (let ((environment (machine-environment machine))) | 114 | (let ((environment (machine-environment machine))) |
| 107 | ((environment-type-deploy-machine environment) machine))) | 115 | ((environment-type-deploy-machine environment) machine))) |
| 116 | |||
| 117 | (define (roll-back-machine machine) | ||
| 118 | "Monadic procedure rolling back to the previous system generation on | ||
| 119 | MACHINE. Return the number of the generation that was current before switching | ||
| 120 | and the new generation number." | ||
| 121 | (let ((environment (machine-environment machine))) | ||
| 122 | ((environment-type-roll-back-machine environment) machine))) | ||
| 123 | |||
| 124 | |||
| 125 | ;;; | ||
| 126 | ;;; Error types. | ||
| 127 | ;;; | ||
| 128 | |||
| 129 | (define-condition-type &deploy-error &error | ||
| 130 | deploy-error? | ||
| 131 | (should-roll-back deploy-error-should-roll-back) | ||
| 132 | (captured-args deploy-error-captured-args)) | ||
diff --git a/gnu/machine/ssh.scm b/gnu/machine/ssh.scm index fb15d39e610..4b5d5fe3a2f 100644 --- a/gnu/machine/ssh.scm +++ b/gnu/machine/ssh.scm | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. |
| 18 | 18 | ||
| 19 | (define-module (gnu machine ssh) | 19 | (define-module (gnu machine ssh) |
| 20 | #:use-module (gnu bootloader) | ||
| 20 | #:use-module (gnu machine) | 21 | #:use-module (gnu machine) |
| 21 | #:autoload (gnu packages gnupg) (guile-gcrypt) | 22 | #:autoload (gnu packages gnupg) (guile-gcrypt) |
| 22 | #:use-module (gnu system) | 23 | #:use-module (gnu system) |
| @@ -34,6 +35,7 @@ | |||
| 34 | #:use-module (guix store) | 35 | #:use-module (guix store) |
| 35 | #:use-module (guix utils) | 36 | #:use-module (guix utils) |
| 36 | #:use-module (ice-9 match) | 37 | #:use-module (ice-9 match) |
| 38 | #:use-module (srfi srfi-1) | ||
| 37 | #:use-module (srfi srfi-19) | 39 | #:use-module (srfi srfi-19) |
| 38 | #:use-module (srfi srfi-26) | 40 | #:use-module (srfi srfi-26) |
| 39 | #:use-module (srfi srfi-34) | 41 | #:use-module (srfi srfi-34) |
| @@ -341,6 +343,18 @@ of MACHINE's system profile, ordered from most recent to oldest." | |||
| 341 | (boot-parameters-kernel-arguments params)))))))) | 343 | (boot-parameters-kernel-arguments params)))))))) |
| 342 | generations)))) | 344 | generations)))) |
| 343 | 345 | ||
| 346 | (define-syntax-rule (with-roll-back should-roll-back? mbody ...) | ||
| 347 | "Catch exceptions that arise when binding MBODY, a monadic expression in | ||
| 348 | %STORE-MONAD, and collect their arguments in a &deploy-error condition, with | ||
| 349 | the 'should-roll-back' field set to SHOULD-ROLL-BACK?" | ||
| 350 | (catch #t | ||
| 351 | (lambda () | ||
| 352 | mbody ...) | ||
| 353 | (lambda args | ||
| 354 | (raise (condition (&deploy-error | ||
| 355 | (should-roll-back should-roll-back?) | ||
| 356 | (captured-args args))))))) | ||
| 357 | |||
| 344 | (define (deploy-managed-host machine) | 358 | (define (deploy-managed-host machine) |
| 345 | "Internal implementation of 'deploy-machine' for MACHINE instances with an | 359 | "Internal implementation of 'deploy-machine' for MACHINE instances with an |
| 346 | environment type of 'managed-host." | 360 | environment type of 'managed-host." |
| @@ -353,9 +367,60 @@ environment type of 'managed-host." | |||
| 353 | (bootloader-configuration (operating-system-bootloader os)) | 367 | (bootloader-configuration (operating-system-bootloader os)) |
| 354 | (bootcfg (operating-system-bootcfg os menu-entries))) | 368 | (bootcfg (operating-system-bootcfg os menu-entries))) |
| 355 | (mbegin %store-monad | 369 | (mbegin %store-monad |
| 356 | (switch-to-system eval os) | 370 | (with-roll-back #f |
| 357 | (upgrade-shepherd-services eval os) | 371 | (switch-to-system eval os)) |
| 358 | (install-bootloader eval bootloader-configuration bootcfg))))) | 372 | (with-roll-back #t |
| 373 | (mbegin %store-monad | ||
| 374 | (upgrade-shepherd-services eval os) | ||
| 375 | (install-bootloader eval bootloader-configuration bootcfg))))))) | ||
| 376 | |||
| 377 | |||
| 378 | ;;; | ||
| 379 | ;;; Roll-back. | ||
| 380 | ;;; | ||
| 381 | |||
| 382 | (define (roll-back-managed-host machine) | ||
| 383 | "Internal implementation of 'roll-back-machine' for MACHINE instances with | ||
| 384 | an environment type of 'managed-host." | ||
| 385 | (define remote-exp | ||
| 386 | (with-extensions (list guile-gcrypt) | ||
| 387 | (with-imported-modules (source-module-closure '((guix config) | ||
| 388 | (guix profiles))) | ||
| 389 | #~(begin | ||
| 390 | (use-modules (guix config) | ||
| 391 | (guix profiles)) | ||
| 392 | |||
| 393 | (define %system-profile | ||
| 394 | (string-append %state-directory "/profiles/system")) | ||
| 395 | |||
| 396 | (define target-generation | ||
| 397 | (relative-generation %system-profile -1)) | ||
| 398 | |||
| 399 | (if target-generation | ||
| 400 | (switch-to-generation %system-profile target-generation) | ||
| 401 | 'error))))) | ||
| 402 | |||
| 403 | (define roll-back-failure | ||
| 404 | (condition (&message (message (G_ "could not roll-back machine"))))) | ||
| 405 | |||
| 406 | (mlet* %store-monad ((boot-parameters (machine-boot-parameters machine)) | ||
| 407 | (_ -> (if (< (length boot-parameters) 2) | ||
| 408 | (raise roll-back-failure))) | ||
| 409 | (entries -> (map boot-parameters->menu-entry | ||
| 410 | (list (second boot-parameters)))) | ||
| 411 | (old-entries -> (map boot-parameters->menu-entry | ||
| 412 | (drop boot-parameters 2))) | ||
| 413 | (bootloader -> (operating-system-bootloader | ||
| 414 | (machine-operating-system machine))) | ||
| 415 | (bootcfg (lower-object | ||
| 416 | ((bootloader-configuration-file-generator | ||
| 417 | (bootloader-configuration-bootloader | ||
| 418 | bootloader)) | ||
| 419 | bootloader entries | ||
| 420 | #:old-entries old-entries))) | ||
| 421 | (remote-result (machine-remote-eval machine remote-exp))) | ||
| 422 | (when (eqv? 'error remote-result) | ||
| 423 | (raise roll-back-failure)))) | ||
| 359 | 424 | ||
| 360 | 425 | ||
| 361 | ;;; | 426 | ;;; |
| @@ -366,6 +431,7 @@ environment type of 'managed-host." | |||
| 366 | (environment-type | 431 | (environment-type |
| 367 | (machine-remote-eval managed-host-remote-eval) | 432 | (machine-remote-eval managed-host-remote-eval) |
| 368 | (deploy-machine deploy-managed-host) | 433 | (deploy-machine deploy-managed-host) |
| 434 | (roll-back-machine roll-back-managed-host) | ||
| 369 | (name 'managed-host-environment-type) | 435 | (name 'managed-host-environment-type) |
| 370 | (description "Provisioning for machines that are accessible over SSH | 436 | (description "Provisioning for machines that are accessible over SSH |
| 371 | and have a known host-name. This entails little more than maintaining an SSH | 437 | and have a known host-name. This entails little more than maintaining an SSH |
diff --git a/guix/scripts/deploy.scm b/guix/scripts/deploy.scm index 81f2b332601..6a67985c8b5 100644 --- a/guix/scripts/deploy.scm +++ b/guix/scripts/deploy.scm | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | #:use-module (guix grafts) | 28 | #:use-module (guix grafts) |
| 29 | #:use-module (ice-9 format) | 29 | #:use-module (ice-9 format) |
| 30 | #:use-module (srfi srfi-1) | 30 | #:use-module (srfi srfi-1) |
| 31 | #:use-module (srfi srfi-34) | ||
| 32 | #:use-module (srfi srfi-35) | ||
| 31 | #:use-module (srfi srfi-37) | 33 | #:use-module (srfi srfi-37) |
| 32 | #:export (guix-deploy)) | 34 | #:export (guix-deploy)) |
| 33 | 35 | ||
| @@ -88,7 +90,18 @@ Perform the deployment specified by FILE.\n")) | |||
| 88 | (with-store store | 90 | (with-store store |
| 89 | (set-build-options-from-command-line store opts) | 91 | (set-build-options-from-command-line store opts) |
| 90 | (for-each (lambda (machine) | 92 | (for-each (lambda (machine) |
| 91 | (info (G_ "deploying to ~a...") (machine-display-name machine)) | 93 | (info (G_ "deploying to ~a...~%") |
| 94 | (machine-display-name machine)) | ||
| 92 | (parameterize ((%graft? (assq-ref opts 'graft?))) | 95 | (parameterize ((%graft? (assq-ref opts 'graft?))) |
| 93 | (run-with-store store (deploy-machine machine)))) | 96 | (guard (c ((message-condition? c) |
| 97 | (report-error (G_ "failed to deploy ~a: '~a'~%") | ||
| 98 | (machine-display-name machine) | ||
| 99 | (condition-message c))) | ||
| 100 | ((deploy-error? c) | ||
| 101 | (when (deploy-error-should-roll-back c) | ||
| 102 | (info (G_ "rolling back ~a...~%") | ||
| 103 | (machine-display-name machine)) | ||
| 104 | (run-with-store store (roll-back-machine machine))) | ||
| 105 | (apply throw (deploy-error-captured-args c)))) | ||
| 106 | (run-with-store store (deploy-machine machine))))) | ||
| 94 | machines)))) | 107 | machines)))) |
