diff options
| author | Mathieu Othacehe <othacehe@gnu.org> | 2020-08-13 14:16:12 +0200 |
|---|---|---|
| committer | Mathieu Othacehe <othacehe@gnu.org> | 2020-09-02 17:05:23 +0200 |
| commit | 8ce6f4dc2879919c12bc76a2f4b01200af97e019 (patch) | |
| tree | bcdfea85d25af8ae24622310a035688ac8257dcc /gnu/installer/final.scm | |
| parent | 5316dfc0f125b658e4a2acf7f00f49501663d943 (diff) | |
installer: Run the installation inside a container.
When the store overlay is mounted, other processes such as kmscon, udev
and guix-daemon may open files from the store, preventing the
underlying install support from being umounted. See:
https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html.
To avoid this situation, mount the store overlay inside a container,
and run the installation from within that container.
* gnu/build/shepherd.scm (fork+exec-command/container): New procedure.
* gnu/services/base.scm (guix-shepherd-service): Support an optional PID
argument passed to the "start" method. If that argument is passed, ensure that
guix-daemon enters the given PID MNT namespace by using
fork+exec-command/container procedure.
* gnu/installer/final.scm (umount-cow-store): Remove it,
(install-system): run the installation from within a container.
* gnu/installer/newt/final.scm (run-install-shell): Remove the display hack.
Diffstat (limited to 'gnu/installer/final.scm')
| -rw-r--r-- | gnu/installer/final.scm | 124 |
1 files changed, 61 insertions, 63 deletions
diff --git a/gnu/installer/final.scm b/gnu/installer/final.scm index 685aa81d89b..11143b2adbe 100644 --- a/gnu/installer/final.scm +++ b/gnu/installer/final.scm | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #:use-module (guix build syscalls) | 26 | #:use-module (guix build syscalls) |
| 27 | #:use-module (guix build utils) | 27 | #:use-module (guix build utils) |
| 28 | #:use-module (gnu build accounts) | 28 | #:use-module (gnu build accounts) |
| 29 | #:use-module (gnu build install) | ||
| 30 | #:use-module (gnu build linux-container) | ||
| 29 | #:use-module ((gnu system shadow) #:prefix sys:) | 31 | #:use-module ((gnu system shadow) #:prefix sys:) |
| 30 | #:use-module (rnrs io ports) | 32 | #:use-module (rnrs io ports) |
| 31 | #:use-module (srfi srfi-1) | 33 | #:use-module (srfi srfi-1) |
| @@ -133,49 +135,18 @@ USERS." | |||
| 133 | (_ #f)))))) | 135 | (_ #f)))))) |
| 134 | pids))) | 136 | pids))) |
| 135 | 137 | ||
| 136 | (define (umount-cow-store) | ||
| 137 | "Remove the store overlay and the bind-mount on /tmp created by the | ||
| 138 | cow-store service. This procedure is very fragile and a better approach would | ||
| 139 | be much appreciated." | ||
| 140 | (catch #t | ||
| 141 | (lambda () | ||
| 142 | (let ((tmp-dir "/remove")) | ||
| 143 | (syslog "Unmounting cow-store.~%") | ||
| 144 | |||
| 145 | (mkdir-p tmp-dir) | ||
| 146 | (mount (%store-directory) tmp-dir "" MS_MOVE) | ||
| 147 | |||
| 148 | ;; The guix-daemon has possibly opened files from the cow-store, | ||
| 149 | ;; restart it. | ||
| 150 | (restart-service 'guix-daemon) | ||
| 151 | |||
| 152 | (syslog "Killing cow users.") | ||
| 153 | |||
| 154 | ;; Kill all processes started while the cow-store was active (logins | ||
| 155 | ;; on other TTYs for instance). | ||
| 156 | (kill-cow-users tmp-dir) | ||
| 157 | |||
| 158 | ;; Try to umount the store overlay. Some process such as udevd | ||
| 159 | ;; workers might still be active, so do some retries. | ||
| 160 | (let loop ((try 5)) | ||
| 161 | (syslog "Umount try ~a~%" (- 5 try)) | ||
| 162 | (sleep 1) | ||
| 163 | (let ((umounted? (false-if-exception (umount tmp-dir)))) | ||
| 164 | (if (and (not umounted?) (> try 0)) | ||
| 165 | (loop (- try 1)) | ||
| 166 | (if umounted? | ||
| 167 | (syslog "Umounted ~a successfully.~%" tmp-dir) | ||
| 168 | (syslog "Failed to umount ~a.~%" tmp-dir))))) | ||
| 169 | |||
| 170 | (umount "/tmp"))) | ||
| 171 | (lambda args | ||
| 172 | (syslog "~a~%" args)))) | ||
| 173 | |||
| 174 | (define* (install-system locale #:key (users '())) | 138 | (define* (install-system locale #:key (users '())) |
| 175 | "Create /etc/shadow and /etc/passwd on the installation target for USERS. | 139 | "Create /etc/shadow and /etc/passwd on the installation target for USERS. |
| 176 | Start COW-STORE service on target directory and launch guix install command in | 140 | Start COW-STORE service on target directory and launch guix install command in |
| 177 | a subshell. LOCALE must be the locale name under which that command will run, | 141 | a subshell. LOCALE must be the locale name under which that command will run, |
| 178 | or #f. Return #t on success and #f on failure." | 142 | or #f. Return #t on success and #f on failure." |
| 143 | (define backing-directory | ||
| 144 | ;; Sub-directory used as the backing store for copy-on-write. | ||
| 145 | "/tmp/guix-inst") | ||
| 146 | |||
| 147 | (define (assert-exit x) | ||
| 148 | (primitive-exit (if x 0 1))) | ||
| 149 | |||
| 179 | (let* ((options (catch 'system-error | 150 | (let* ((options (catch 'system-error |
| 180 | (lambda () | 151 | (lambda () |
| 181 | ;; If this file exists, it can provide | 152 | ;; If this file exists, it can provide |
| @@ -188,7 +159,11 @@ or #f. Return #t on success and #f on failure." | |||
| 188 | "--fallback") | 159 | "--fallback") |
| 189 | options | 160 | options |
| 190 | (list (%installer-configuration-file) | 161 | (list (%installer-configuration-file) |
| 191 | (%installer-target-dir))))) | 162 | (%installer-target-dir)))) |
| 163 | (database-dir "/var/guix/db") | ||
| 164 | (database-file (string-append database-dir "/db.sqlite")) | ||
| 165 | (saved-database (string-append database-dir "/db.save")) | ||
| 166 | (ret #f)) | ||
| 192 | (mkdir-p (%installer-target-dir)) | 167 | (mkdir-p (%installer-target-dir)) |
| 193 | 168 | ||
| 194 | ;; We want to initialize user passwords but we don't want to store them in | 169 | ;; We want to initialize user passwords but we don't want to store them in |
| @@ -198,27 +173,50 @@ or #f. Return #t on success and #f on failure." | |||
| 198 | ;; passwords that we've put in there. | 173 | ;; passwords that we've put in there. |
| 199 | (create-user-database users (%installer-target-dir)) | 174 | (create-user-database users (%installer-target-dir)) |
| 200 | 175 | ||
| 201 | (dynamic-wind | 176 | ;; When the store overlay is mounted, other processes such as kmscon, udev |
| 202 | (lambda () | 177 | ;; and guix-daemon may open files from the store, preventing the |
| 203 | (start-service 'cow-store (list (%installer-target-dir)))) | 178 | ;; underlying install support from being umounted. See: |
| 204 | (lambda () | 179 | ;; https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html. |
| 205 | ;; If there are any connected clients, assume that we are running | 180 | ;; |
| 206 | ;; installation tests. In that case, dump the standard and error | 181 | ;; To avoid this situation, mount the store overlay inside a container, |
| 207 | ;; outputs to syslog. | 182 | ;; and run the installation from within that container. |
| 208 | (if (not (null? (current-clients))) | 183 | (zero? |
| 209 | (with-output-to-file "/dev/console" | 184 | (call-with-container '() |
| 210 | (lambda () | 185 | (lambda () |
| 211 | (with-error-to-file "/dev/console" | 186 | (dynamic-wind |
| 212 | (lambda () | 187 | (lambda () |
| 213 | (setvbuf (current-output-port) 'none) | 188 | ;; Save the database, so that it can be restored once the |
| 214 | (setvbuf (current-error-port) 'none) | 189 | ;; cow-store is umounted. |
| 215 | (run-command install-command #:locale locale))))) | 190 | (copy-file database-file saved-database) |
| 216 | (run-command install-command #:locale locale))) | 191 | (mount-cow-store (%installer-target-dir) backing-directory)) |
| 217 | (lambda () | 192 | (lambda () |
| 218 | (stop-service 'cow-store) | 193 | ;; We need to drag the guix-daemon to the container MNT |
| 219 | ;; Remove the store overlay created at cow-store service start. | 194 | ;; namespace, so that it can operate on the cow-store. |
| 220 | ;; Failing to do that will result in further umount calls to fail | 195 | (stop-service 'guix-daemon) |
| 221 | ;; because the target device is seen as busy. See: | 196 | (start-service 'guix-daemon (list (number->string (getpid)))) |
| 222 | ;; https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html. | 197 | |
| 223 | (umount-cow-store) | 198 | (setvbuf (current-output-port) 'none) |
| 224 | #f)))) | 199 | (setvbuf (current-error-port) 'none) |
| 200 | |||
| 201 | ;; If there are any connected clients, assume that we are running | ||
| 202 | ;; installation tests. In that case, dump the standard and error | ||
| 203 | ;; outputs to syslog. | ||
| 204 | (set! ret | ||
| 205 | (if (not (null? (current-clients))) | ||
| 206 | (with-output-to-file "/dev/console" | ||
| 207 | (lambda () | ||
| 208 | (with-error-to-file "/dev/console" | ||
| 209 | (lambda () | ||
| 210 | (run-command install-command | ||
| 211 | #:locale locale))))) | ||
| 212 | (run-command install-command #:locale locale)))) | ||
| 213 | (lambda () | ||
| 214 | ;; Restart guix-daemon so that it does no keep the MNT namespace | ||
| 215 | ;; alive. | ||
| 216 | (restart-service 'guix-daemon) | ||
| 217 | (copy-file saved-database database-file) | ||
| 218 | |||
| 219 | ;; Finally umount the cow-store and exit the container. | ||
| 220 | (unmount-cow-store (%installer-target-dir) backing-directory) | ||
| 221 | (assert-exit ret)))) | ||
| 222 | #:namespaces '(mnt))))) | ||
