install.scm 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2017 Tobias Geerinckx-Rice <me@tobias.gr>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (gnu tests install)
  20. #:use-module (gnu)
  21. #:use-module (gnu bootloader extlinux)
  22. #:use-module (gnu tests)
  23. #:use-module (gnu tests base)
  24. #:use-module (gnu system)
  25. #:use-module (gnu system install)
  26. #:use-module (gnu system vm)
  27. #:use-module ((gnu build vm) #:select (qemu-command))
  28. #:use-module (gnu packages bootloaders)
  29. #:use-module (gnu packages ocr)
  30. #:use-module (gnu packages package-management)
  31. #:use-module (gnu packages virtualization)
  32. #:use-module (guix store)
  33. #:use-module (guix monads)
  34. #:use-module (guix packages)
  35. #:use-module (guix grafts)
  36. #:use-module (guix gexp)
  37. #:use-module (guix utils)
  38. #:export (%test-installed-os
  39. %test-installed-extlinux-os
  40. %test-iso-image-installer
  41. %test-separate-store-os
  42. %test-separate-home-os
  43. %test-raid-root-os
  44. %test-encrypted-root-os
  45. %test-btrfs-root-os))
  46. ;;; Commentary:
  47. ;;;
  48. ;;; Test the installation of GuixSD using the documented approach at the
  49. ;;; command line.
  50. ;;;
  51. ;;; Code:
  52. (define-os-with-source (%minimal-os %minimal-os-source)
  53. ;; The OS we want to install.
  54. (use-modules (gnu) (gnu tests) (srfi srfi-1))
  55. (operating-system
  56. (host-name "liberigilo")
  57. (timezone "Europe/Paris")
  58. (locale "en_US.UTF-8")
  59. (bootloader (bootloader-configuration
  60. (bootloader grub-bootloader)
  61. (target "/dev/vdb")))
  62. (kernel-arguments '("console=ttyS0"))
  63. (file-systems (cons (file-system
  64. (device (file-system-label "my-root"))
  65. (mount-point "/")
  66. (type "ext4"))
  67. %base-file-systems))
  68. (users (cons (user-account
  69. (name "alice")
  70. (comment "Bob's sister")
  71. (group "users")
  72. (supplementary-groups '("wheel" "audio" "video"))
  73. (home-directory "/home/alice"))
  74. %base-user-accounts))
  75. (services (cons (service marionette-service-type
  76. (marionette-configuration
  77. (imported-modules '((gnu services herd)
  78. (guix combinators)))))
  79. %base-services))))
  80. (define (operating-system-add-packages os packages)
  81. "Append PACKAGES to OS packages list."
  82. (operating-system
  83. (inherit os)
  84. (packages (append packages (operating-system-packages os)))))
  85. (define-os-with-source (%minimal-extlinux-os
  86. %minimal-extlinux-os-source)
  87. (use-modules (gnu) (gnu tests) (gnu bootloader extlinux)
  88. (srfi srfi-1))
  89. (operating-system
  90. (host-name "liberigilo")
  91. (timezone "Europe/Paris")
  92. (locale "en_US.UTF-8")
  93. (bootloader (bootloader-configuration
  94. (bootloader extlinux-bootloader-gpt)
  95. (target "/dev/vdb")))
  96. (kernel-arguments '("console=ttyS0"))
  97. (file-systems (cons (file-system
  98. (device (file-system-label "my-root"))
  99. (mount-point "/")
  100. (type "ext4"))
  101. %base-file-systems))
  102. (services (cons (service marionette-service-type
  103. (marionette-configuration
  104. (imported-modules '((gnu services herd)
  105. (guix combinators)))))
  106. %base-services))))
  107. (define (operating-system-with-current-guix os)
  108. "Return a variant of OS that uses the current Guix."
  109. (operating-system
  110. (inherit os)
  111. (services (modify-services (operating-system-user-services os)
  112. (guix-service-type config =>
  113. (guix-configuration
  114. (inherit config)
  115. (guix (current-guix))))))))
  116. (define (operating-system-with-gc-roots os roots)
  117. "Return a variant of OS where ROOTS are registered as GC roots."
  118. (operating-system
  119. (inherit os)
  120. ;; We use this procedure for the installation OS, which already defines GC
  121. ;; roots. Add ROOTS to those.
  122. (services (cons (simple-service 'extra-root
  123. gc-root-service-type roots)
  124. (operating-system-user-services os)))))
  125. (define MiB (expt 2 20))
  126. (define %simple-installation-script
  127. ;; Shell script of a simple installation.
  128. "\
  129. . /etc/profile
  130. set -e -x
  131. guix --version
  132. export GUIX_BUILD_OPTIONS=--no-grafts
  133. guix build isc-dhcp
  134. parted --script /dev/vdb mklabel gpt \\
  135. mkpart primary ext2 1M 3M \\
  136. mkpart primary ext2 3M 1.2G \\
  137. set 1 boot on \\
  138. set 1 bios_grub on
  139. mkfs.ext4 -L my-root /dev/vdb2
  140. mount /dev/vdb2 /mnt
  141. df -h /mnt
  142. herd start cow-store /mnt
  143. mkdir /mnt/etc
  144. cp /etc/target-config.scm /mnt/etc/config.scm
  145. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  146. sync
  147. reboot\n")
  148. (define %extlinux-gpt-installation-script
  149. ;; Shell script of a simple installation.
  150. ;; As syslinux 6.0.3 does not handle 64bits ext4 partitions,
  151. ;; we make sure to pass -O '^64bit' to mkfs.
  152. "\
  153. . /etc/profile
  154. set -e -x
  155. guix --version
  156. export GUIX_BUILD_OPTIONS=--no-grafts
  157. guix build isc-dhcp
  158. parted --script /dev/vdb mklabel gpt \\
  159. mkpart ext2 1M 1.2G \\
  160. set 1 legacy_boot on
  161. mkfs.ext4 -L my-root -O '^64bit' /dev/vdb1
  162. mount /dev/vdb1 /mnt
  163. df -h /mnt
  164. herd start cow-store /mnt
  165. mkdir /mnt/etc
  166. cp /etc/target-config.scm /mnt/etc/config.scm
  167. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  168. sync
  169. reboot\n")
  170. (define* (run-install target-os target-os-source
  171. #:key
  172. (script %simple-installation-script)
  173. (packages '())
  174. (os (marionette-operating-system
  175. (operating-system
  176. ;; Since the image has no network access, use the
  177. ;; current Guix so the store items we need are in
  178. ;; the image and add packages provided.
  179. (inherit (operating-system-add-packages
  180. (operating-system-with-current-guix
  181. installation-os)
  182. packages))
  183. (kernel-arguments '("console=ttyS0")))
  184. #:imported-modules '((gnu services herd)
  185. (guix combinators))))
  186. (installation-disk-image-file-system-type "ext4")
  187. (target-size (* 2200 MiB)))
  188. "Run SCRIPT (a shell script following the GuixSD installation procedure) in
  189. OS to install TARGET-OS. Return a VM image of TARGET-SIZE bytes containing
  190. the installed system. The packages specified in PACKAGES will be appended to
  191. packages defined in installation-os."
  192. (mlet* %store-monad ((_ (set-grafting #f))
  193. (system (current-system))
  194. (target (operating-system-derivation target-os))
  195. ;; Since the installation system has no network access,
  196. ;; we cheat a little bit by adding TARGET to its GC
  197. ;; roots. This way, we know 'guix system init' will
  198. ;; succeed.
  199. (image (system-disk-image
  200. (operating-system-with-gc-roots
  201. os (list target))
  202. #:disk-image-size 'guess
  203. #:file-system-type
  204. installation-disk-image-file-system-type)))
  205. (define install
  206. (with-imported-modules '((guix build utils)
  207. (gnu build marionette))
  208. #~(begin
  209. (use-modules (guix build utils)
  210. (gnu build marionette))
  211. (set-path-environment-variable "PATH" '("bin")
  212. (list #$qemu-minimal))
  213. (system* "qemu-img" "create" "-f" "qcow2"
  214. #$output #$(number->string target-size))
  215. (define marionette
  216. (make-marionette
  217. `(,(which #$(qemu-command system))
  218. "-no-reboot"
  219. "-m" "800"
  220. #$@(cond
  221. ((string=? "ext4" installation-disk-image-file-system-type)
  222. #~("-drive"
  223. ,(string-append "file=" #$image
  224. ",if=virtio,readonly")))
  225. ((string=? "iso9660" installation-disk-image-file-system-type)
  226. #~("-cdrom" #$image))
  227. (else
  228. (error
  229. "unsupported installation-disk-image-file-system-type:"
  230. installation-disk-image-file-system-type)))
  231. "-drive"
  232. ,(string-append "file=" #$output ",if=virtio")
  233. ,@(if (file-exists? "/dev/kvm")
  234. '("-enable-kvm")
  235. '()))))
  236. (pk 'uname (marionette-eval '(uname) marionette))
  237. ;; Wait for tty1.
  238. (marionette-eval '(begin
  239. (use-modules (gnu services herd))
  240. (start 'term-tty1))
  241. marionette)
  242. (marionette-eval '(call-with-output-file "/etc/target-config.scm"
  243. (lambda (port)
  244. (write '#$target-os-source port)))
  245. marionette)
  246. (exit (marionette-eval '(zero? (system #$script))
  247. marionette)))))
  248. (gexp->derivation "installation" install)))
  249. (define* (qemu-command/writable-image image #:key (memory-size 256))
  250. "Return as a monadic value the command to run QEMU on a writable copy of
  251. IMAGE, a disk image. The QEMU VM is has access to MEMORY-SIZE MiB of RAM."
  252. (mlet %store-monad ((system (current-system)))
  253. (return #~(let ((image #$image))
  254. ;; First we need a writable copy of the image.
  255. (format #t "creating writable image from '~a'...~%" image)
  256. (unless (zero? (system* #+(file-append qemu-minimal
  257. "/bin/qemu-img")
  258. "create" "-f" "qcow2"
  259. "-o"
  260. (string-append "backing_file=" image)
  261. "disk.img"))
  262. (error "failed to create writable QEMU image" image))
  263. (chmod "disk.img" #o644)
  264. `(,(string-append #$qemu-minimal "/bin/"
  265. #$(qemu-command system))
  266. ,@(if (file-exists? "/dev/kvm")
  267. '("-enable-kvm")
  268. '())
  269. "-no-reboot" "-m" #$(number->string memory-size)
  270. "-drive" "file=disk.img,if=virtio")))))
  271. (define %test-installed-os
  272. (system-test
  273. (name "installed-os")
  274. (description
  275. "Test basic functionality of an OS installed like one would do by hand.
  276. This test is expensive in terms of CPU and storage usage since we need to
  277. build (current-guix) and then store a couple of full system images.")
  278. (value
  279. (mlet* %store-monad ((image (run-install %minimal-os %minimal-os-source))
  280. (command (qemu-command/writable-image image)))
  281. (run-basic-test %minimal-os command
  282. "installed-os")))))
  283. (define %test-installed-extlinux-os
  284. (system-test
  285. (name "installed-extlinux-os")
  286. (description
  287. "Test basic functionality of an OS booted with an extlinux bootloader. As
  288. per %test-installed-os, this test is expensive in terms of CPU and storage.")
  289. (value
  290. (mlet* %store-monad ((image (run-install %minimal-extlinux-os
  291. %minimal-extlinux-os-source
  292. #:packages
  293. (list syslinux)
  294. #:script
  295. %extlinux-gpt-installation-script))
  296. (command (qemu-command/writable-image image)))
  297. (run-basic-test %minimal-extlinux-os command
  298. "installed-extlinux-os")))))
  299. ;;;
  300. ;;; Installation through an ISO image.
  301. ;;;
  302. (define-os-with-source (%minimal-os-on-vda %minimal-os-on-vda-source)
  303. ;; The OS we want to install.
  304. (use-modules (gnu) (gnu tests) (srfi srfi-1))
  305. (operating-system
  306. (host-name "liberigilo")
  307. (timezone "Europe/Paris")
  308. (locale "en_US.UTF-8")
  309. (bootloader (bootloader-configuration
  310. (bootloader grub-bootloader)
  311. (target "/dev/vda")))
  312. (kernel-arguments '("console=ttyS0"))
  313. (file-systems (cons (file-system
  314. (device (file-system-label "my-root"))
  315. (mount-point "/")
  316. (type "ext4"))
  317. %base-file-systems))
  318. (users (cons (user-account
  319. (name "alice")
  320. (comment "Bob's sister")
  321. (group "users")
  322. (supplementary-groups '("wheel" "audio" "video"))
  323. (home-directory "/home/alice"))
  324. %base-user-accounts))
  325. (services (cons (service marionette-service-type
  326. (marionette-configuration
  327. (imported-modules '((gnu services herd)
  328. (guix combinators)))))
  329. %base-services))))
  330. (define %simple-installation-script-for-/dev/vda
  331. ;; Shell script of a simple installation.
  332. "\
  333. . /etc/profile
  334. set -e -x
  335. guix --version
  336. export GUIX_BUILD_OPTIONS=--no-grafts
  337. guix build isc-dhcp
  338. parted --script /dev/vda mklabel gpt \\
  339. mkpart primary ext2 1M 3M \\
  340. mkpart primary ext2 3M 1.2G \\
  341. set 1 boot on \\
  342. set 1 bios_grub on
  343. mkfs.ext4 -L my-root /dev/vda2
  344. mount /dev/vda2 /mnt
  345. df -h /mnt
  346. herd start cow-store /mnt
  347. mkdir /mnt/etc
  348. cp /etc/target-config.scm /mnt/etc/config.scm
  349. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  350. sync
  351. reboot\n")
  352. (define %test-iso-image-installer
  353. (system-test
  354. (name "iso-image-installer")
  355. (description
  356. "")
  357. (value
  358. (mlet* %store-monad ((image (run-install
  359. %minimal-os-on-vda
  360. %minimal-os-on-vda-source
  361. #:script
  362. %simple-installation-script-for-/dev/vda
  363. #:installation-disk-image-file-system-type
  364. "iso9660"))
  365. (command (qemu-command/writable-image image)))
  366. (run-basic-test %minimal-os-on-vda command name)))))
  367. ;;;
  368. ;;; Separate /home.
  369. ;;;
  370. (define-os-with-source (%separate-home-os %separate-home-os-source)
  371. ;; The OS we want to install.
  372. (use-modules (gnu) (gnu tests) (srfi srfi-1))
  373. (operating-system
  374. (host-name "liberigilo")
  375. (timezone "Europe/Paris")
  376. (locale "en_US.utf8")
  377. (bootloader (bootloader-configuration
  378. (bootloader grub-bootloader)
  379. (target "/dev/vdb")))
  380. (kernel-arguments '("console=ttyS0"))
  381. (file-systems (cons* (file-system
  382. (device (file-system-label "my-root"))
  383. (mount-point "/")
  384. (type "ext4"))
  385. (file-system
  386. (device "none")
  387. (mount-point "/home")
  388. (type "tmpfs"))
  389. %base-file-systems))
  390. (users (cons* (user-account
  391. (name "alice")
  392. (group "users")
  393. (home-directory "/home/alice"))
  394. (user-account
  395. (name "charlie")
  396. (group "users")
  397. (home-directory "/home/charlie"))
  398. %base-user-accounts))
  399. (services (cons (service marionette-service-type
  400. (marionette-configuration
  401. (imported-modules '((gnu services herd)
  402. (guix combinators)))))
  403. %base-services))))
  404. (define %test-separate-home-os
  405. (system-test
  406. (name "separate-home-os")
  407. (description
  408. "Test basic functionality of an installed OS with a separate /home
  409. partition. In particular, home directories must be correctly created (see
  410. <https://bugs.gnu.org/21108>).")
  411. (value
  412. (mlet* %store-monad ((image (run-install %separate-home-os
  413. %separate-home-os-source
  414. #:script
  415. %simple-installation-script))
  416. (command (qemu-command/writable-image image)))
  417. (run-basic-test %separate-home-os command "separate-home-os")))))
  418. ;;;
  419. ;;; Separate /gnu/store partition.
  420. ;;;
  421. (define-os-with-source (%separate-store-os %separate-store-os-source)
  422. ;; The OS we want to install.
  423. (use-modules (gnu) (gnu tests) (srfi srfi-1))
  424. (operating-system
  425. (host-name "liberigilo")
  426. (timezone "Europe/Paris")
  427. (locale "en_US.UTF-8")
  428. (bootloader (bootloader-configuration
  429. (bootloader grub-bootloader)
  430. (target "/dev/vdb")))
  431. (kernel-arguments '("console=ttyS0"))
  432. (file-systems (cons* (file-system
  433. (device (file-system-label "root-fs"))
  434. (mount-point "/")
  435. (type "ext4"))
  436. (file-system
  437. (device (file-system-label "store-fs"))
  438. (mount-point "/gnu")
  439. (type "ext4"))
  440. %base-file-systems))
  441. (users %base-user-accounts)
  442. (services (cons (service marionette-service-type
  443. (marionette-configuration
  444. (imported-modules '((gnu services herd)
  445. (guix combinators)))))
  446. %base-services))))
  447. (define %separate-store-installation-script
  448. ;; Installation with a separate /gnu partition.
  449. "\
  450. . /etc/profile
  451. set -e -x
  452. guix --version
  453. export GUIX_BUILD_OPTIONS=--no-grafts
  454. guix build isc-dhcp
  455. parted --script /dev/vdb mklabel gpt \\
  456. mkpart primary ext2 1M 3M \\
  457. mkpart primary ext2 3M 100M \\
  458. mkpart primary ext2 100M 1.2G \\
  459. set 1 boot on \\
  460. set 1 bios_grub on
  461. mkfs.ext4 -L root-fs /dev/vdb2
  462. mkfs.ext4 -L store-fs /dev/vdb3
  463. mount /dev/vdb2 /mnt
  464. mkdir /mnt/gnu
  465. mount /dev/vdb3 /mnt/gnu
  466. df -h /mnt
  467. herd start cow-store /mnt
  468. mkdir /mnt/etc
  469. cp /etc/target-config.scm /mnt/etc/config.scm
  470. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  471. sync
  472. reboot\n")
  473. (define %test-separate-store-os
  474. (system-test
  475. (name "separate-store-os")
  476. (description
  477. "Test basic functionality of an OS installed like one would do by hand,
  478. where /gnu lives on a separate partition.")
  479. (value
  480. (mlet* %store-monad ((image (run-install %separate-store-os
  481. %separate-store-os-source
  482. #:script
  483. %separate-store-installation-script))
  484. (command (qemu-command/writable-image image)))
  485. (run-basic-test %separate-store-os command "separate-store-os")))))
  486. ;;;
  487. ;;; RAID root device.
  488. ;;;
  489. (define-os-with-source (%raid-root-os %raid-root-os-source)
  490. ;; An OS whose root partition is a RAID partition.
  491. (use-modules (gnu) (gnu tests))
  492. (operating-system
  493. (host-name "raidified")
  494. (timezone "Europe/Paris")
  495. (locale "en_US.utf8")
  496. (bootloader (bootloader-configuration
  497. (bootloader grub-bootloader)
  498. (target "/dev/vdb")))
  499. (kernel-arguments '("console=ttyS0"))
  500. ;; Add a kernel module for RAID-0 (aka. "stripe").
  501. (initrd-modules (cons "raid0" %base-initrd-modules))
  502. (mapped-devices (list (mapped-device
  503. (source (list "/dev/vda2" "/dev/vda3"))
  504. (target "/dev/md0")
  505. (type raid-device-mapping))))
  506. (file-systems (cons (file-system
  507. (device (file-system-label "root-fs"))
  508. (mount-point "/")
  509. (type "ext4")
  510. (dependencies mapped-devices))
  511. %base-file-systems))
  512. (users %base-user-accounts)
  513. (services (cons (service marionette-service-type
  514. (marionette-configuration
  515. (imported-modules '((gnu services herd)
  516. (guix combinators)))))
  517. %base-services))))
  518. (define %raid-root-installation-script
  519. ;; Installation with a separate /gnu partition. See
  520. ;; <https://raid.wiki.kernel.org/index.php/RAID_setup> for more on RAID and
  521. ;; mdadm.
  522. "\
  523. . /etc/profile
  524. set -e -x
  525. guix --version
  526. export GUIX_BUILD_OPTIONS=--no-grafts
  527. parted --script /dev/vdb mklabel gpt \\
  528. mkpart primary ext2 1M 3M \\
  529. mkpart primary ext2 3M 600M \\
  530. mkpart primary ext2 600M 1200M \\
  531. set 1 boot on \\
  532. set 1 bios_grub on
  533. mdadm --create /dev/md0 --verbose --level=stripe --raid-devices=2 \\
  534. /dev/vdb2 /dev/vdb3
  535. mkfs.ext4 -L root-fs /dev/md0
  536. mount /dev/md0 /mnt
  537. df -h /mnt
  538. herd start cow-store /mnt
  539. mkdir /mnt/etc
  540. cp /etc/target-config.scm /mnt/etc/config.scm
  541. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  542. sync
  543. reboot\n")
  544. (define %test-raid-root-os
  545. (system-test
  546. (name "raid-root-os")
  547. (description
  548. "Test functionality of an OS installed with a RAID root partition managed
  549. by 'mdadm'.")
  550. (value
  551. (mlet* %store-monad ((image (run-install %raid-root-os
  552. %raid-root-os-source
  553. #:script
  554. %raid-root-installation-script
  555. #:target-size (* 1300 MiB)))
  556. (command (qemu-command/writable-image image)))
  557. (run-basic-test %raid-root-os
  558. `(,@command) "raid-root-os")))))
  559. ;;;
  560. ;;; LUKS-encrypted root file system.
  561. ;;;
  562. (define-os-with-source (%encrypted-root-os %encrypted-root-os-source)
  563. ;; The OS we want to install.
  564. (use-modules (gnu) (gnu tests) (srfi srfi-1))
  565. (operating-system
  566. (host-name "liberigilo")
  567. (timezone "Europe/Paris")
  568. (locale "en_US.UTF-8")
  569. (bootloader (bootloader-configuration
  570. (bootloader grub-bootloader)
  571. (target "/dev/vdb")))
  572. ;; Note: Do not pass "console=ttyS0" so we can use our passphrase prompt
  573. ;; detection logic in 'enter-luks-passphrase'.
  574. (mapped-devices (list (mapped-device
  575. (source (uuid "12345678-1234-1234-1234-123456789abc"))
  576. (target "the-root-device")
  577. (type luks-device-mapping))))
  578. (file-systems (cons (file-system
  579. (device "/dev/mapper/the-root-device")
  580. (mount-point "/")
  581. (type "ext4"))
  582. %base-file-systems))
  583. (users (cons (user-account
  584. (name "charlie")
  585. (group "users")
  586. (home-directory "/home/charlie")
  587. (supplementary-groups '("wheel" "audio" "video")))
  588. %base-user-accounts))
  589. (services (cons (service marionette-service-type
  590. (marionette-configuration
  591. (imported-modules '((gnu services herd)
  592. (guix combinators)))))
  593. %base-services))))
  594. (define %encrypted-root-installation-script
  595. ;; Shell script of a simple installation.
  596. "\
  597. . /etc/profile
  598. set -e -x
  599. guix --version
  600. export GUIX_BUILD_OPTIONS=--no-grafts
  601. ls -l /run/current-system/gc-roots
  602. parted --script /dev/vdb mklabel gpt \\
  603. mkpart primary ext2 1M 3M \\
  604. mkpart primary ext2 3M 1.2G \\
  605. set 1 boot on \\
  606. set 1 bios_grub on
  607. echo -n thepassphrase | \\
  608. cryptsetup luksFormat --uuid=12345678-1234-1234-1234-123456789abc -q /dev/vdb2 -
  609. echo -n thepassphrase | \\
  610. cryptsetup open --type luks --key-file - /dev/vdb2 the-root-device
  611. mkfs.ext4 -L my-root /dev/mapper/the-root-device
  612. mount LABEL=my-root /mnt
  613. herd start cow-store /mnt
  614. mkdir /mnt/etc
  615. cp /etc/target-config.scm /mnt/etc/config.scm
  616. guix system build /mnt/etc/config.scm
  617. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  618. sync
  619. reboot\n")
  620. (define (enter-luks-passphrase marionette)
  621. "Return a gexp to be inserted in the basic system test running on MARIONETTE
  622. to enter the LUKS passphrase."
  623. (let ((ocrad (file-append ocrad "/bin/ocrad")))
  624. #~(begin
  625. (define (passphrase-prompt? text)
  626. (string-contains (pk 'screen-text text) "Enter pass"))
  627. (define (bios-boot-screen? text)
  628. ;; Return true if TEXT corresponds to the boot screen, before GRUB's
  629. ;; menu.
  630. (string-prefix? "SeaBIOS" text))
  631. (test-assert "enter LUKS passphrase for GRUB"
  632. (begin
  633. ;; At this point we have no choice but to use OCR to determine
  634. ;; when the passphrase should be entered.
  635. (wait-for-screen-text #$marionette passphrase-prompt?
  636. #:ocrad #$ocrad)
  637. (marionette-type "thepassphrase\n" #$marionette)
  638. ;; Now wait until we leave the boot screen. This is necessary so
  639. ;; we can then be sure we match the "Enter passphrase" prompt from
  640. ;; 'cryptsetup', in the initrd.
  641. (wait-for-screen-text #$marionette (negate bios-boot-screen?)
  642. #:ocrad #$ocrad
  643. #:timeout 20)))
  644. (test-assert "enter LUKS passphrase for the initrd"
  645. (begin
  646. ;; XXX: Here we use OCR as well but we could instead use QEMU
  647. ;; '-serial stdio' and run it in an input pipe,
  648. (wait-for-screen-text #$marionette passphrase-prompt?
  649. #:ocrad #$ocrad
  650. #:timeout 60)
  651. (marionette-type "thepassphrase\n" #$marionette)
  652. ;; Take a screenshot for debugging purposes.
  653. (marionette-control (string-append "screendump " #$output
  654. "/post-initrd-passphrase.ppm")
  655. #$marionette))))))
  656. (define %test-encrypted-root-os
  657. (system-test
  658. (name "encrypted-root-os")
  659. (description
  660. "Test basic functionality of an OS installed like one would do by hand.
  661. This test is expensive in terms of CPU and storage usage since we need to
  662. build (current-guix) and then store a couple of full system images.")
  663. (value
  664. (mlet* %store-monad ((image (run-install %encrypted-root-os
  665. %encrypted-root-os-source
  666. #:script
  667. %encrypted-root-installation-script))
  668. (command (qemu-command/writable-image image)))
  669. (run-basic-test %encrypted-root-os command "encrypted-root-os"
  670. #:initialization enter-luks-passphrase)))))
  671. ;;;
  672. ;;; Btrfs root file system.
  673. ;;;
  674. (define-os-with-source (%btrfs-root-os %btrfs-root-os-source)
  675. ;; The OS we want to install.
  676. (use-modules (gnu) (gnu tests) (srfi srfi-1))
  677. (operating-system
  678. (host-name "liberigilo")
  679. (timezone "Europe/Paris")
  680. (locale "en_US.UTF-8")
  681. (bootloader (bootloader-configuration
  682. (bootloader grub-bootloader)
  683. (target "/dev/vdb")))
  684. (kernel-arguments '("console=ttyS0"))
  685. (file-systems (cons (file-system
  686. (device (file-system-label "my-root"))
  687. (mount-point "/")
  688. (type "btrfs"))
  689. %base-file-systems))
  690. (users (cons (user-account
  691. (name "charlie")
  692. (group "users")
  693. (home-directory "/home/charlie")
  694. (supplementary-groups '("wheel" "audio" "video")))
  695. %base-user-accounts))
  696. (services (cons (service marionette-service-type
  697. (marionette-configuration
  698. (imported-modules '((gnu services herd)
  699. (guix combinators)))))
  700. %base-services))))
  701. (define %btrfs-root-installation-script
  702. ;; Shell script of a simple installation.
  703. "\
  704. . /etc/profile
  705. set -e -x
  706. guix --version
  707. export GUIX_BUILD_OPTIONS=--no-grafts
  708. ls -l /run/current-system/gc-roots
  709. parted --script /dev/vdb mklabel gpt \\
  710. mkpart primary ext2 1M 3M \\
  711. mkpart primary ext2 3M 2G \\
  712. set 1 boot on \\
  713. set 1 bios_grub on
  714. mkfs.btrfs -L my-root /dev/vdb2
  715. mount /dev/vdb2 /mnt
  716. btrfs subvolume create /mnt/home
  717. herd start cow-store /mnt
  718. mkdir /mnt/etc
  719. cp /etc/target-config.scm /mnt/etc/config.scm
  720. guix system build /mnt/etc/config.scm
  721. guix system init /mnt/etc/config.scm /mnt --no-substitutes
  722. sync
  723. reboot\n")
  724. (define %test-btrfs-root-os
  725. (system-test
  726. (name "btrfs-root-os")
  727. (description
  728. "Test basic functionality of an OS installed like one would do by hand.
  729. This test is expensive in terms of CPU and storage usage since we need to
  730. build (current-guix) and then store a couple of full system images.")
  731. (value
  732. (mlet* %store-monad ((image (run-install %btrfs-root-os
  733. %btrfs-root-os-source
  734. #:script
  735. %btrfs-root-installation-script))
  736. (command (qemu-command/writable-image image)))
  737. (run-basic-test %btrfs-root-os command "btrfs-root-os")))))
  738. ;;; install.scm ends here