summaryrefslogtreecommitdiff
path: root/gnu/system/vm.scm
diff options
context:
space:
mode:
authorMathieu Othacehe <othacehe@gnu.org>2021-12-16 13:32:11 +0100
committerMathieu Othacehe <othacehe@gnu.org>2021-12-23 10:54:00 +0100
commit05a9d1f378e2e13e8f759be926ea368358afc27c (patch)
tree65d56f5e77e779ccddebc23e423021e3d9281c68 /gnu/system/vm.scm
parentda924796744bbb7b035a986fe5d28d8d613ff6af (diff)
Remove VM generation dead-code.
This code duplicates the (gnu system image) and (gnu build image) code. Using VM for image generation is not needed, not portable and really slow. Remove all the VM image generation code to make sure that only the image API is used. * gnu/build/vm.scm: Remove it. Move the qemu-command procedure to ... * gnu/build/marionette.scm: ... here. * gnu/local.mk (GNU_SYSTEM_MODULES): Adapt it. * tests/modules.scm: Ditto. * gnu/tests/install.scm: Ditto. * gnu/system/vm.scm: Adapt it and remove expression->derivation-in-linux-vm, qemu-img, system-qemu-image/shared-store and system-docker-image procedures. * doc/guix.texi (G-Expressions): Adapt it.
Diffstat (limited to 'gnu/system/vm.scm')
-rw-r--r--gnu/system/vm.scm487
1 files changed, 2 insertions, 485 deletions
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index db5c4132c01..3370df1c81a 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -35,7 +35,7 @@
35 #:use-module (guix base32) 35 #:use-module (guix base32)
36 #:use-module ((guix self) #:select (make-config.scm)) 36 #:use-module ((guix self) #:select (make-config.scm))
37 37
38 #:use-module ((gnu build vm) 38 #:use-module ((gnu build marionette)
39 #:select (qemu-command)) 39 #:select (qemu-command))
40 #:use-module (gnu packages base) 40 #:use-module (gnu packages base)
41 #:use-module (gnu packages bootloaders) 41 #:use-module (gnu packages bootloaders)
@@ -67,13 +67,8 @@
67 #:use-module (rnrs bytevectors) 67 #:use-module (rnrs bytevectors)
68 #:use-module (ice-9 match) 68 #:use-module (ice-9 match)
69 69
70 #:export (expression->derivation-in-linux-vm 70 #:export (virtualized-operating-system
71 qemu-image
72 virtualized-operating-system
73
74 system-qemu-image/shared-store
75 system-qemu-image/shared-store-script 71 system-qemu-image/shared-store-script
76 system-docker-image
77 72
78 virtual-machine 73 virtual-machine
79 virtual-machine?)) 74 virtual-machine?))
@@ -126,444 +121,6 @@
126 %default-msize-value)) 121 %default-msize-value))
127 (check? #f)))) 122 (check? #f))))
128 123
129(define not-config?
130 ;; Select (guix …) and (gnu …) modules, except (guix config).
131 (match-lambda
132 (('guix 'config) #f)
133 (('guix rest ...) #t)
134 (('gnu rest ...) #t)
135 (rest #f)))
136
137(define gcrypt-sqlite3&co
138 ;; Guile-Gcrypt, Guile-SQLite3, and their propagated inputs.
139 (append-map (lambda (package)
140 (cons package
141 (match (package-transitive-propagated-inputs package)
142 (((labels packages) ...)
143 packages))))
144 (list guile-gcrypt guile-sqlite3)))
145
146(define* (expression->derivation-in-linux-vm name exp
147 #:key
148 (system (%current-system))
149 (linux linux-libre)
150 initrd
151 (qemu qemu-minimal)
152 (env-vars '())
153 (guile-for-build
154 (%guile-for-build))
155 (file-systems
156 %linux-vm-file-systems)
157
158 (single-file-output? #f)
159 (make-disk-image? #f)
160 (references-graphs #f)
161 (memory-size 256)
162 (disk-image-format "qcow2")
163 (disk-image-size 'guess)
164
165 (substitutable? #t))
166 "Evaluate EXP in a QEMU virtual machine running LINUX with INITRD (a
167derivation). The virtual machine runs with MEMORY-SIZE MiB of memory. In the
168virtual machine, EXP has access to FILE-SYSTEMS, which, by default, includes a
1699p share of the store, the '/xchg' where EXP should put its output file(s),
170and a 9p share of /tmp.
171
172If SINGLE-FILE-OUTPUT? is true, copy a single file from '/xchg' to OUTPUT.
173Otherwise, copy the contents of /xchg to a new directory OUTPUT.
174
175When MAKE-DISK-IMAGE? is true, then create a QEMU disk image of type
176DISK-IMAGE-FORMAT (e.g., 'qcow2' or 'raw'), of DISK-IMAGE-SIZE bytes and
177return it. When DISK-IMAGE-SIZE is 'guess, estimate the image size based
178based on the size of the closure of REFERENCES-GRAPHS.
179
180When REFERENCES-GRAPHS is true, it must be a list of file name/store path
181pairs, as for `derivation'. The files containing the reference graphs are
182made available under the /xchg CIFS share.
183
184SUBSTITUTABLE? determines whether the returned derivation should be marked as
185substitutable."
186 (define user-builder
187 (program-file "builder-in-linux-vm" exp))
188
189 (define loader
190 ;; Invoke USER-BUILDER instead using 'primitive-load'. The reason for
191 ;; this is to allow USER-BUILDER to dlopen stuff by using a full-featured
192 ;; Guile, which it couldn't do using the statically-linked guile used in
193 ;; the initrd. See example at
194 ;; <https://lists.gnu.org/archive/html/guix-devel/2017-10/msg00233.html>.
195 (program-file "linux-vm-loader"
196 ;; Communicate USER-BUILDER's exit status via /xchg so that
197 ;; the host can distinguish between success, failure, and
198 ;; kernel panic.
199 #~(let ((status (system* #$user-builder)))
200 (call-with-output-file "/xchg/.exit-status"
201 (lambda (port)
202 (write status port)))
203 (sync)
204 (reboot))))
205
206 (define-syntax-rule (check predicate)
207 (let-system (system target)
208 (predicate (or target system))))
209
210 (let ((initrd (or initrd
211 (base-initrd file-systems
212 #:on-error 'backtrace
213 #:linux linux
214 #:linux-modules %base-initrd-modules
215 #:qemu-networking? #t))))
216
217 (define builder
218 ;; Code that launches the VM that evaluates EXP.
219 (with-extensions gcrypt-sqlite3&co
220 (with-imported-modules `(,@(source-module-closure
221 '((guix build utils)
222 (gnu build vm))
223 #:select? not-config?)
224
225 ;; For consumption by (gnu store database).
226 ((guix config) => ,(make-config.scm)))
227 #~(begin
228 (use-modules (guix build utils)
229 (gnu build vm))
230
231 ;; Allow non-ASCII file names--e.g., 'nss-certs'--to be decoded
232 ;; by 'estimated-partition-size' below.
233 (setenv "GUIX_LOCPATH"
234 #+(file-append glibc-utf8-locales "/lib/locale"))
235 (setlocale LC_ALL "en_US.utf8")
236
237 (let* ((native-inputs
238 '#+(list qemu (canonical-package coreutils)))
239 (linux (string-append
240 #+linux "/"
241 #+(system-linux-image-file-name system)))
242 (initrd #+initrd)
243 (loader #+loader)
244 (graphs '#$(match references-graphs
245 (((graph-files . _) ...) graph-files)
246 (_ #f)))
247 (target #$(let-system (system target)
248 (or target system)))
249 (size #$(if (eq? 'guess disk-image-size)
250 #~(+ (* 70 (expt 2 20)) ;ESP
251 (estimated-partition-size graphs))
252 disk-image-size)))
253
254 (set-path-environment-variable "PATH" '("bin") native-inputs)
255
256 (load-in-linux-vm loader
257 #:output #$output
258 #:linux linux #:initrd initrd
259 #:qemu (qemu-command target)
260 #:memory-size #$memory-size
261 #:make-disk-image? #$make-disk-image?
262 #:single-file-output? #$single-file-output?
263 #:disk-image-format #$disk-image-format
264 #:disk-image-size size
265 #:references-graphs graphs))))))
266
267 (gexp->derivation name builder
268 ;; TODO: Require the "kvm" feature.
269 #:system system
270 #:target #f ;EXP is always executed natively
271 #:env-vars env-vars
272 #:guile-for-build guile-for-build
273 #:references-graphs references-graphs
274 #:substitutable? substitutable?)))
275
276(define (has-guix-service-type? os)
277 "Return true if OS contains a service of the type GUIX-SERVICE-TYPE."
278 (not (not (find (lambda (service)
279 (eq? (service-kind service) guix-service-type))
280 (operating-system-services os)))))
281
282(define* (qemu-image #:key
283 (name "qemu-image")
284 (system (%current-system))
285 (target (%current-target-system))
286 (qemu qemu-minimal)
287 (disk-image-size 'guess)
288 (disk-image-format "qcow2")
289 (file-system-type "ext4")
290 (file-system-options '())
291 (device-nodes 'linux)
292 (extra-directives '())
293 file-system-label
294 file-system-uuid
295 os
296 bootcfg-drv
297 bootloader
298 (register-closures? (has-guix-service-type? os))
299 (inputs '())
300 copy-inputs?
301 (substitutable? #t))
302 "Return a bootable, stand-alone QEMU image of type DISK-IMAGE-FORMAT (e.g.,
303'qcow2' or 'raw'), with a root partition of type FILE-SYSTEM-TYPE.
304Optionally, FILE-SYSTEM-LABEL can be specified as the volume name for the root
305partition; likewise FILE-SYSTEM-UUID, if true, specifies the UUID of the root
306partition (a UUID object). FILE-SYSTEM-OPTIONS is an optional list of
307command-line options passed to 'mkfs.ext4' (or similar).
308
309The returned image is a full disk image that runs OS-DERIVATION,
310with a GRUB installation that uses GRUB-CONFIGURATION as its configuration
311file (GRUB-CONFIGURATION must be the name of a file in the VM.)
312
313INPUTS is a list of inputs (as for packages). When COPY-INPUTS? is true, copy
314all of INPUTS into the image being built. When REGISTER-CLOSURES? is true,
315register INPUTS in the store database of the image so that Guix can be used in
316the image. By default, REGISTER-CLOSURES? is set to true only if a service of
317type GUIX-SERVICE-TYPE is present in the services definition of the operating
318system.
319
320When DEVICE-NODES is 'linux, create Linux-device block and character devices
321under /dev. When it is 'hurd, do Hurdish things.
322
323EXTRA-DIRECTIVES is an optional list of directives to populate the root file
324system that is passed to 'populate-root-file-system'."
325 (define schema
326 (and register-closures?
327 (local-file (search-path %load-path
328 "guix/store/schema.sql"))))
329
330 (define preserve-target
331 (if target
332 (lambda (obj)
333 (with-parameters ((%current-target-system target))
334 obj))
335 identity))
336
337 (define inputs*
338 (map (match-lambda
339 ((name thing)
340 `(,name ,(preserve-target thing)))
341 ((name thing output)
342 `(,name ,(preserve-target thing) ,output)))
343 inputs))
344
345 (expression->derivation-in-linux-vm
346 name
347 (with-extensions gcrypt-sqlite3&co
348 (with-imported-modules `(,@(source-module-closure '((gnu build vm)
349 (gnu build bootloader)
350 (gnu build hurd-boot)
351 (guix store database)
352 (guix build utils))
353 #:select? not-config?)
354 ((guix config) => ,(make-config.scm)))
355 #~(begin
356 (use-modules (gnu build bootloader)
357 (gnu build vm)
358 ((gnu build hurd-boot)
359 #:select (make-hurd-device-nodes))
360 ((gnu build linux-boot)
361 #:select (make-essential-device-nodes))
362 (guix store database)
363 (guix build utils)
364 (srfi srfi-26)
365 (ice-9 binary-ports))
366
367 (sql-schema #$schema)
368
369 ;; Allow non-ASCII file names--e.g., 'nss-certs'--to be decoded.
370 (setenv "GUIX_LOCPATH"
371 #+(file-append glibc-utf8-locales "/lib/locale"))
372 (setlocale LC_ALL "en_US.utf8")
373
374 (let ((inputs
375 '#+(append (list parted e2fsprogs dosfstools)
376 (map canonical-package
377 (list sed grep coreutils findutils gawk))))
378
379 ;; This variable is unused but allows us to add INPUTS-TO-COPY
380 ;; as inputs.
381 (to-register
382 '#$(map (match-lambda
383 ((name thing) thing)
384 ((name thing output) `(,thing ,output)))
385 inputs*)))
386
387 (set-path-environment-variable "PATH" '("bin" "sbin") inputs)
388
389 (let* ((graphs '#$(match inputs
390 (((names . _) ...)
391 names)))
392 (initialize (root-partition-initializer
393 #:extra-directives '#$extra-directives
394 #:closures graphs
395 #:copy-closures? #$copy-inputs?
396 #:register-closures? #$register-closures?
397 #:system-directory #$(preserve-target os)
398
399 #:make-device-nodes
400 #$(match device-nodes
401 ('linux #~make-essential-device-nodes)
402 ('hurd #~make-hurd-device-nodes))
403
404 ;; Disable deduplication to speed things up,
405 ;; and because it doesn't help much for a
406 ;; single system generation.
407 #:deduplicate? #f))
408 (root-size #$(if (eq? 'guess disk-image-size)
409 #~(max
410 ;; Minimum 20 MiB root size
411 (* 20 (expt 2 20))
412 (estimated-partition-size
413 (map (cut string-append "/xchg/" <>)
414 graphs)))
415 (- disk-image-size
416 (* 50 (expt 2 20)))))
417 (partitions
418 (append
419 (list (partition
420 (size root-size)
421 (label #$file-system-label)
422 (uuid #$(and=> file-system-uuid
423 uuid-bytevector))
424 (file-system #$file-system-type)
425 (file-system-options '#$file-system-options)
426 (flags '(boot))
427 (initializer initialize)))
428 ;; Append a small EFI System Partition for use with UEFI
429 ;; bootloaders if we are not targeting ARM because UEFI
430 ;; support in U-Boot is experimental.
431 ;;
432 ;; FIXME: ‘target-arm?’ may be not operate on the right
433 ;; system/target values. Rewrite using ‘let-system’ when
434 ;; available.
435 (if #$(target-arm?)
436 '()
437 (list (partition
438 ;; The standalone grub image is about 10MiB, but
439 ;; leave some room for custom or multiple images.
440 (size (* 40 (expt 2 20)))
441 (label "GNU-ESP") ;cosmetic only
442 ;; Use "vfat" here since this property is used
443 ;; when mounting. The actual FAT-ness is based
444 ;; on file system size (16 in this case).
445 (file-system "vfat")
446 (flags '(esp)))))))
447 (grub-efi #$(and (not (target-arm?)) grub-efi)))
448 (initialize-hard-disk "/dev/vda"
449 #:partitions partitions
450 #:grub-efi grub-efi
451 #:bootloader-package
452 #+(bootloader-package bootloader)
453 #:bootcfg #$(preserve-target bootcfg-drv)
454 #:bootcfg-location
455 #$(bootloader-configuration-file bootloader)
456 #:bootloader-installer
457 #+(bootloader-installer bootloader)))))))
458 #:system system
459 #:make-disk-image? #t
460 #:disk-image-size disk-image-size
461 #:disk-image-format disk-image-format
462 #:references-graphs inputs*
463 #:substitutable? substitutable?))
464
465(define* (system-docker-image os
466 #:key
467 (name "guix-docker-image")
468 (memory-size 256)
469 (register-closures? (has-guix-service-type? os))
470 shared-network?)
471 "Build a docker image. OS is the desired <operating-system>. NAME is the
472base name to use for the output file. When SHARED-NETWORK? is true, assume
473that the container will share network with the host and thus doesn't need a
474DHCP client, nscd, and so on.
475
476When REGISTER-CLOSURES? is true, register the closure of OS with Guix in the
477resulting Docker image. By default, REGISTER-CLOSURES? is set to true only if
478a service of type GUIX-SERVICE-TYPE is present in the services definition of
479the operating system."
480 (define schema
481 (and register-closures?
482 (local-file (search-path %load-path
483 "guix/store/schema.sql"))))
484
485 (define boot-program
486 ;; Program that runs the boot script of OS, which in turn starts shepherd.
487 (program-file "boot-program"
488 #~(let ((system (cadr (command-line))))
489 (setenv "GUIX_NEW_SYSTEM" system)
490 (execl #$(file-append guile-3.0 "/bin/guile")
491 "guile" "--no-auto-compile"
492 (string-append system "/boot")))))
493
494
495 (let ((os (operating-system-with-gc-roots
496 (containerized-operating-system os '()
497 #:shared-network?
498 shared-network?)
499 (list boot-program)))
500 (name (string-append name ".tar.gz"))
501 (graph "system-graph"))
502 (define build
503 (with-extensions (cons guile-json-3 ;for (guix docker)
504 gcrypt-sqlite3&co) ;for (guix store database)
505 (with-imported-modules `(,@(source-module-closure
506 '((guix docker)
507 (guix store database)
508 (guix build utils)
509 (guix build store-copy)
510 (gnu build vm))
511 #:select? not-config?)
512 ((guix config) => ,(make-config.scm)))
513 #~(begin
514 (use-modules (guix docker)
515 (guix build utils)
516 (gnu build vm)
517 (srfi srfi-19)
518 (guix build store-copy)
519 (guix store database))
520
521 ;; Set the SQL schema location.
522 (sql-schema #$schema)
523
524 ;; Allow non-ASCII file names--e.g., 'nss-certs'--to be decoded.
525 (setenv "GUIX_LOCPATH"
526 #+(file-append glibc-utf8-locales "/lib/locale"))
527 (setlocale LC_ALL "en_US.utf8")
528
529 (let* (;; This initializer requires elevated privileges that are
530 ;; not normally available in the build environment (e.g.,
531 ;; it needs to create device nodes). In order to obtain
532 ;; such privileges, we run it as root in a VM.
533 (initialize (root-partition-initializer
534 #:closures '(#$graph)
535 #:register-closures? #$register-closures?
536 #:system-directory #$os
537 ;; De-duplication would fail due to
538 ;; cross-device link errors, so don't do it.
539 #:deduplicate? #f))
540 ;; Even as root in a VM, the initializer would fail due to
541 ;; lack of privileges if we use a root-directory that is on
542 ;; a file system that is shared with the host (e.g., /tmp).
543 (root-directory "/guix-system-root"))
544 (set-path-environment-variable "PATH" '("bin" "sbin") '(#+tar))
545 (mkdir root-directory)
546 (initialize root-directory)
547 (build-docker-image
548 (string-append "/xchg/" #$name) ;; The output file.
549 (cons* root-directory
550 (map store-info-item
551 (call-with-input-file
552 (string-append "/xchg/" #$graph)
553 read-reference-graph)))
554 #$os
555 #:entry-point '(#$boot-program #$os)
556 #:compressor '(#+(file-append gzip "/bin/gzip") "-9n")
557 #:creation-time (make-time time-utc 0 1)
558 #:transformations `((,root-directory -> ""))))))))
559
560 (expression->derivation-in-linux-vm
561 name build
562 #:memory-size memory-size
563 #:make-disk-image? #f
564 #:single-file-output? #t
565 #:references-graphs `((,graph ,os)))))
566
567 124
568;;; 125;;;
569;;; VMs that share file systems with the host. 126;;; VMs that share file systems with the host.
@@ -655,46 +212,6 @@ environment with the store shared with the host. MAPPINGS is a list of
655 (needed-for-boot? #t)) 212 (needed-for-boot? #t))
656 virtual-file-systems))))) 213 virtual-file-systems)))))
657 214
658(define* (system-qemu-image/shared-store
659 os
660 #:key
661 (system (%current-system))
662 (target (%current-target-system))
663 full-boot?
664 (disk-image-size (* (if full-boot? 500 30) (expt 2 20))))
665 "Return a derivation that builds a QEMU image of OS that shares its store
666with the host.
667
668When FULL-BOOT? is true, return an image that does a complete boot sequence,
669bootloaded included; thus, make a disk image that contains everything the
670bootloader refers to: OS kernel, initrd, bootloader data, etc."
671 (define root-uuid
672 ;; Use a fixed UUID to improve determinism.
673 (operating-system-uuid os 'dce))
674
675 (define bootcfg
676 (operating-system-bootcfg os))
677
678 ;; XXX: When FULL-BOOT? is true, we end up creating an image that contains
679 ;; BOOTCFG and all its dependencies, including the output of OS.
680 ;; This is more than needed (we only need the kernel, initrd, GRUB for its
681 ;; font, and the background image), but it's hard to filter that.
682 (qemu-image #:os os
683 #:system system
684 #:target target
685 #:bootcfg-drv bootcfg
686 #:bootloader (bootloader-configuration-bootloader
687 (operating-system-bootloader os))
688 #:disk-image-size disk-image-size
689 #:file-system-uuid root-uuid
690 #:inputs (if full-boot?
691 `(("bootcfg" ,bootcfg))
692 '())
693
694 ;; XXX: Passing #t here is too slow, so let it off by default.
695 #:register-closures? #f
696 #:copy-inputs? full-boot?))
697
698(define* (common-qemu-options image shared-fs 215(define* (common-qemu-options image shared-fs
699 #:key rw-image?) 216 #:key rw-image?)
700 "Return the a string-value gexp with the common QEMU options to boot IMAGE, 217 "Return the a string-value gexp with the common QEMU options to boot IMAGE,