virtualization.scm 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Ryan Moe <ryan.moe@gmail.com>
  3. ;;; Copyright © 2018, 2020-2022 Ludovic Courtès <ludo@gnu.org>
  4. ;;; Copyright © 2020,2021 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  5. ;;; Copyright © 2021 Timotej Lazar <timotej.lazar@araneo.si>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (gnu services virtualization)
  22. #:use-module (gnu bootloader)
  23. #:use-module (gnu bootloader grub)
  24. #:use-module (gnu image)
  25. #:use-module (gnu packages admin)
  26. #:use-module (gnu packages gdb)
  27. #:use-module (gnu packages package-management)
  28. #:use-module (gnu packages ssh)
  29. #:use-module (gnu packages virtualization)
  30. #:use-module (gnu services base)
  31. #:use-module (gnu services configuration)
  32. #:use-module (gnu services dbus)
  33. #:use-module (gnu services shepherd)
  34. #:use-module (gnu services ssh)
  35. #:use-module (gnu services)
  36. #:use-module (gnu system file-systems)
  37. #:use-module (gnu system hurd)
  38. #:use-module (gnu system image)
  39. #:use-module (gnu system shadow)
  40. #:use-module (gnu system)
  41. #:use-module (guix derivations)
  42. #:use-module (guix gexp)
  43. #:use-module (guix modules)
  44. #:use-module (guix monads)
  45. #:use-module (guix packages)
  46. #:use-module (guix records)
  47. #:use-module (guix store)
  48. #:use-module (guix utils)
  49. #:use-module (srfi srfi-9)
  50. #:use-module (srfi srfi-26)
  51. #:use-module (rnrs bytevectors)
  52. #:use-module (ice-9 match)
  53. #:export (%hurd-vm-operating-system
  54. hurd-vm-configuration
  55. hurd-vm-configuration?
  56. hurd-vm-configuration-os
  57. hurd-vm-configuration-qemu
  58. hurd-vm-configuration-image
  59. hurd-vm-configuration-disk-size
  60. hurd-vm-configuration-memory-size
  61. hurd-vm-configuration-options
  62. hurd-vm-configuration-id
  63. hurd-vm-configuration-net-options
  64. hurd-vm-configuration-secrets
  65. hurd-vm-disk-image
  66. hurd-vm-port
  67. hurd-vm-net-options
  68. hurd-vm-service-type
  69. libvirt-configuration
  70. libvirt-service-type
  71. virtlog-configuration
  72. virtlog-service-type
  73. %qemu-platforms
  74. lookup-qemu-platforms
  75. qemu-platform?
  76. qemu-platform-name
  77. qemu-binfmt-configuration
  78. qemu-binfmt-configuration?
  79. qemu-binfmt-service-type
  80. qemu-guest-agent-configuration
  81. qemu-guest-agent-configuration?
  82. qemu-guest-agent-service-type))
  83. (define (uglify-field-name field-name)
  84. (let ((str (symbol->string field-name)))
  85. (string-join
  86. (string-split (string-delete #\? str) #\-)
  87. "_")))
  88. (define (quote-val val)
  89. (string-append "\"" val "\""))
  90. (define (serialize-field field-name val)
  91. (format #t "~a = ~a\n" (uglify-field-name field-name) val))
  92. (define (serialize-string field-name val)
  93. (serialize-field field-name (quote-val val)))
  94. (define (serialize-boolean field-name val)
  95. (serialize-field field-name (if val 1 0)))
  96. (define (serialize-integer field-name val)
  97. (serialize-field field-name val))
  98. (define (build-opt-list val)
  99. (string-append
  100. "["
  101. (string-join (map quote-val val) ",")
  102. "]"))
  103. (define optional-list? list?)
  104. (define optional-string? string?)
  105. (define (serialize-list field-name val)
  106. (serialize-field field-name (build-opt-list val)))
  107. (define (serialize-optional-list field-name val)
  108. (if (null? val)
  109. (format #t "# ~a = []\n" (uglify-field-name field-name))
  110. (serialize-list field-name val)))
  111. (define (serialize-optional-string field-name val)
  112. (if (string-null? val)
  113. (format #t "# ~a = \"\"\n" (uglify-field-name field-name))
  114. (serialize-string field-name val)))
  115. (define-configuration libvirt-configuration
  116. (libvirt
  117. (file-like libvirt)
  118. "Libvirt package.")
  119. (qemu
  120. (file-like qemu)
  121. "Qemu package.")
  122. (listen-tls?
  123. (boolean #t)
  124. "Flag listening for secure TLS connections on the public TCP/IP port.
  125. must set @code{listen} for this to have any effect.
  126. It is necessary to setup a CA and issue server certificates before
  127. using this capability.")
  128. (listen-tcp?
  129. (boolean #f)
  130. "Listen for unencrypted TCP connections on the public TCP/IP port.
  131. must set @code{listen} for this to have any effect.
  132. Using the TCP socket requires SASL authentication by default. Only
  133. SASL mechanisms which support data encryption are allowed. This is
  134. DIGEST_MD5 and GSSAPI (Kerberos5)")
  135. (tls-port
  136. (string "16514")
  137. "Port for accepting secure TLS connections This can be a port number,
  138. or service name")
  139. (tcp-port
  140. (string "16509")
  141. "Port for accepting insecure TCP connections This can be a port number,
  142. or service name")
  143. (listen-addr
  144. (string "0.0.0.0")
  145. "IP address or hostname used for client connections.")
  146. (mdns-adv?
  147. (boolean #f)
  148. "Flag toggling mDNS advertisement of the libvirt service.
  149. Alternatively can disable for all services on a host by
  150. stopping the Avahi daemon.")
  151. (mdns-name
  152. (string (string-append "Virtualization Host " (gethostname)))
  153. "Default mDNS advertisement name. This must be unique on the
  154. immediate broadcast network.")
  155. (unix-sock-group
  156. (string "libvirt")
  157. "UNIX domain socket group ownership. This can be used to
  158. allow a 'trusted' set of users access to management capabilities
  159. without becoming root.")
  160. (unix-sock-ro-perms
  161. (string "0777")
  162. "UNIX socket permissions for the R/O socket. This is used
  163. for monitoring VM status only.")
  164. (unix-sock-rw-perms
  165. (string "0770")
  166. "UNIX socket permissions for the R/W socket. Default allows
  167. only root. If PolicyKit is enabled on the socket, the default
  168. will change to allow everyone (eg, 0777)")
  169. (unix-sock-admin-perms
  170. (string "0777")
  171. "UNIX socket permissions for the admin socket. Default allows
  172. only owner (root), do not change it unless you are sure to whom
  173. you are exposing the access to.")
  174. (unix-sock-dir
  175. (string "/var/run/libvirt")
  176. "The directory in which sockets will be found/created.")
  177. (auth-unix-ro
  178. (string "polkit")
  179. "Authentication scheme for UNIX read-only sockets. By default
  180. socket permissions allow anyone to connect")
  181. (auth-unix-rw
  182. (string "polkit")
  183. "Authentication scheme for UNIX read-write sockets. By default
  184. socket permissions only allow root. If PolicyKit support was compiled
  185. into libvirt, the default will be to use 'polkit' auth.")
  186. (auth-tcp
  187. (string "sasl")
  188. "Authentication scheme for TCP sockets. If you don't enable SASL,
  189. then all TCP traffic is cleartext. Don't do this outside of a dev/test
  190. scenario.")
  191. (auth-tls
  192. (string "none")
  193. "Authentication scheme for TLS sockets. TLS sockets already have
  194. encryption provided by the TLS layer, and limited authentication is
  195. done by certificates.
  196. It is possible to make use of any SASL authentication mechanism as
  197. well, by using 'sasl' for this option")
  198. (access-drivers
  199. (optional-list '())
  200. "API access control scheme.
  201. By default an authenticated user is allowed access to all APIs. Access
  202. drivers can place restrictions on this.")
  203. (key-file
  204. (string "")
  205. "Server key file path. If set to an empty string, then no private key
  206. is loaded.")
  207. (cert-file
  208. (string "")
  209. "Server key file path. If set to an empty string, then no certificate
  210. is loaded.")
  211. (ca-file
  212. (string "")
  213. "Server key file path. If set to an empty string, then no CA certificate
  214. is loaded.")
  215. (crl-file
  216. (string "")
  217. "Certificate revocation list path. If set to an empty string, then no
  218. CRL is loaded.")
  219. (tls-no-sanity-cert
  220. (boolean #f)
  221. "Disable verification of our own server certificates.
  222. When libvirtd starts it performs some sanity checks against its own
  223. certificates.")
  224. (tls-no-verify-cert
  225. (boolean #f)
  226. "Disable verification of client certificates.
  227. Client certificate verification is the primary authentication mechanism.
  228. Any client which does not present a certificate signed by the CA
  229. will be rejected.")
  230. (tls-allowed-dn-list
  231. (optional-list '())
  232. "Whitelist of allowed x509 Distinguished Name.")
  233. (sasl-allowed-usernames
  234. (optional-list '())
  235. "Whitelist of allowed SASL usernames. The format for username
  236. depends on the SASL authentication mechanism.")
  237. (tls-priority
  238. (string "NORMAL")
  239. "Override the compile time default TLS priority string. The
  240. default is usually \"NORMAL\" unless overridden at build time.
  241. Only set this is it is desired for libvirt to deviate from
  242. the global default settings.")
  243. (max-clients
  244. (integer 5000)
  245. "Maximum number of concurrent client connections to allow
  246. over all sockets combined.")
  247. (max-queued-clients
  248. (integer 1000)
  249. "Maximum length of queue of connections waiting to be
  250. accepted by the daemon. Note, that some protocols supporting
  251. retransmission may obey this so that a later reattempt at
  252. connection succeeds.")
  253. (max-anonymous-clients
  254. (integer 20)
  255. "Maximum length of queue of accepted but not yet authenticated
  256. clients. Set this to zero to turn this feature off")
  257. (min-workers
  258. (integer 5)
  259. "Number of workers to start up initially.")
  260. (max-workers
  261. (integer 20)
  262. "Maximum number of worker threads.
  263. If the number of active clients exceeds @code{min-workers},
  264. then more threads are spawned, up to max_workers limit.
  265. Typically you'd want max_workers to equal maximum number
  266. of clients allowed.")
  267. (prio-workers
  268. (integer 5)
  269. "Number of priority workers. If all workers from above
  270. pool are stuck, some calls marked as high priority
  271. (notably domainDestroy) can be executed in this pool.")
  272. (max-requests
  273. (integer 20)
  274. "Total global limit on concurrent RPC calls.")
  275. (max-client-requests
  276. (integer 5)
  277. "Limit on concurrent requests from a single client
  278. connection. To avoid one client monopolizing the server
  279. this should be a small fraction of the global max_requests
  280. and max_workers parameter.")
  281. (admin-min-workers
  282. (integer 1)
  283. "Same as @code{min-workers} but for the admin interface.")
  284. (admin-max-workers
  285. (integer 5)
  286. "Same as @code{max-workers} but for the admin interface.")
  287. (admin-max-clients
  288. (integer 5)
  289. "Same as @code{max-clients} but for the admin interface.")
  290. (admin-max-queued-clients
  291. (integer 5)
  292. "Same as @code{max-queued-clients} but for the admin interface.")
  293. (admin-max-client-requests
  294. (integer 5)
  295. "Same as @code{max-client-requests} but for the admin interface.")
  296. (log-level
  297. (integer 3)
  298. "Logging level. 4 errors, 3 warnings, 2 information, 1 debug.")
  299. (log-filters
  300. (string "3:remote 4:event")
  301. "Logging filters.
  302. A filter allows selecting a different logging level for a given category
  303. of logs
  304. The format for a filter is one of:
  305. @itemize
  306. @item x:name
  307. @item x:+name
  308. @end itemize
  309. where @code{name} is a string which is matched against the category
  310. given in the @code{VIR_LOG_INIT()} at the top of each libvirt source
  311. file, e.g., \"remote\", \"qemu\", or \"util.json\" (the name in the
  312. filter can be a substring of the full category name, in order
  313. to match multiple similar categories), the optional \"+\" prefix
  314. tells libvirt to log stack trace for each message matching
  315. name, and @code{x} is the minimal level where matching messages should
  316. be logged:
  317. @itemize
  318. @item 1: DEBUG
  319. @item 2: INFO
  320. @item 3: WARNING
  321. @item 4: ERROR
  322. @end itemize
  323. Multiple filters can be defined in a single filters statement, they just
  324. need to be separated by spaces.")
  325. (log-outputs
  326. (string "3:syslog:libvirtd")
  327. "Logging outputs.
  328. An output is one of the places to save logging information
  329. The format for an output can be:
  330. @table @code
  331. @item x:stderr
  332. output goes to stderr
  333. @item x:syslog:name
  334. use syslog for the output and use the given name as the ident
  335. @item x:file:file_path
  336. output to a file, with the given filepath
  337. @item x:journald
  338. output to journald logging system
  339. @end table
  340. In all case the x prefix is the minimal level, acting as a filter
  341. @itemize
  342. @item 1: DEBUG
  343. @item 2: INFO
  344. @item 3: WARNING
  345. @item 4: ERROR
  346. @end itemize
  347. Multiple outputs can be defined, they just need to be separated by spaces.")
  348. (audit-level
  349. (integer 1)
  350. "Allows usage of the auditing subsystem to be altered
  351. @itemize
  352. @item 0: disable all auditing
  353. @item 1: enable auditing, only if enabled on host
  354. @item 2: enable auditing, and exit if disabled on host.
  355. @end itemize
  356. ")
  357. (audit-logging
  358. (boolean #f)
  359. "Send audit messages via libvirt logging infrastructure.")
  360. (host-uuid
  361. (optional-string "")
  362. "Host UUID. UUID must not have all digits be the same.")
  363. (host-uuid-source
  364. (string "smbios")
  365. "Source to read host UUID.
  366. @itemize
  367. @item @code{smbios}: fetch the UUID from @code{dmidecode -s system-uuid}
  368. @item @code{machine-id}: fetch the UUID from @code{/etc/machine-id}
  369. @end itemize
  370. If @code{dmidecode} does not provide a valid UUID a temporary UUID
  371. will be generated.")
  372. (keepalive-interval
  373. (integer 5)
  374. "A keepalive message is sent to a client after
  375. @code{keepalive_interval} seconds of inactivity to check if
  376. the client is still responding. If set to -1, libvirtd will
  377. never send keepalive requests; however clients can still send
  378. them and the daemon will send responses.")
  379. (keepalive-count
  380. (integer 5)
  381. "Maximum number of keepalive messages that are allowed to be sent
  382. to the client without getting any response before the connection is
  383. considered broken.
  384. In other words, the connection is automatically
  385. closed approximately after
  386. @code{keepalive_interval * (keepalive_count + 1)} seconds since the last
  387. message received from the client. When @code{keepalive-count} is
  388. set to 0, connections will be automatically closed after
  389. @code{keepalive-interval} seconds of inactivity without sending any
  390. keepalive messages.")
  391. (admin-keepalive-interval
  392. (integer 5)
  393. "Same as above but for admin interface.")
  394. (admin-keepalive-count
  395. (integer 5)
  396. "Same as above but for admin interface.")
  397. (ovs-timeout
  398. (integer 5)
  399. "Timeout for Open vSwitch calls.
  400. The @code{ovs-vsctl} utility is used for the configuration and
  401. its timeout option is set by default to 5 seconds to avoid
  402. potential infinite waits blocking libvirt."))
  403. (define* (libvirt-conf-file config)
  404. "Return a libvirtd config file."
  405. (plain-file "libvirtd.conf"
  406. (with-output-to-string
  407. (lambda ()
  408. (serialize-configuration config libvirt-configuration-fields)))))
  409. (define %libvirt-accounts
  410. (list (user-group (name "libvirt") (system? #t))))
  411. (define (%libvirt-activation config)
  412. (let ((sock-dir (libvirt-configuration-unix-sock-dir config)))
  413. #~(begin
  414. (use-modules (guix build utils))
  415. (mkdir-p #$sock-dir))))
  416. (define (libvirt-shepherd-service config)
  417. (let* ((config-file (libvirt-conf-file config))
  418. (libvirt (libvirt-configuration-libvirt config)))
  419. (list (shepherd-service
  420. (documentation "Run the libvirt daemon.")
  421. (provision '(libvirtd))
  422. (start #~(make-forkexec-constructor
  423. (list (string-append #$libvirt "/sbin/libvirtd")
  424. "-f" #$config-file)
  425. ;; For finding qemu and ip binaries.
  426. #:environment-variables
  427. (list (string-append
  428. "PATH=/run/current-system/profile/bin:"
  429. "/run/current-system/profile/sbin"))))
  430. (stop #~(make-kill-destructor))))))
  431. (define libvirt-service-type
  432. (service-type (name 'libvirt)
  433. (extensions
  434. (list
  435. (service-extension polkit-service-type
  436. (compose list libvirt-configuration-libvirt))
  437. (service-extension profile-service-type
  438. (lambda (config)
  439. (list
  440. (libvirt-configuration-libvirt config)
  441. (libvirt-configuration-qemu config))))
  442. (service-extension activation-service-type
  443. %libvirt-activation)
  444. (service-extension shepherd-root-service-type
  445. libvirt-shepherd-service)
  446. (service-extension account-service-type
  447. (const %libvirt-accounts))))
  448. (default-value (libvirt-configuration))))
  449. (define-record-type* <virtlog-configuration>
  450. virtlog-configuration make-virtlog-configuration
  451. virtlog-configuration?
  452. (libvirt virtlog-configuration-libvirt
  453. (default libvirt))
  454. (log-level virtlog-configuration-log-level
  455. (default 3))
  456. (log-filters virtlog-configuration-log-filters
  457. (default "3:remote 4:event"))
  458. (log-outputs virtlog-configuration-log-outputs
  459. (default "3:syslog:virtlogd"))
  460. (max-clients virtlog-configuration-max-clients
  461. (default 1024))
  462. (max-size virtlog-configuration-max-size
  463. (default 2097152)) ;; 2MB
  464. (max-backups virtlog-configuration-max-backups
  465. (default 3)))
  466. (define* (virtlogd-conf-file config)
  467. "Return a virtlogd config file."
  468. (plain-file "virtlogd.conf"
  469. (string-append
  470. "log_level = " (number->string (virtlog-configuration-log-level config)) "\n"
  471. "log_filters = \"" (virtlog-configuration-log-filters config) "\"\n"
  472. "log_outputs = \"" (virtlog-configuration-log-outputs config) "\"\n"
  473. "max_clients = " (number->string (virtlog-configuration-max-clients config)) "\n"
  474. "max_size = " (number->string (virtlog-configuration-max-size config)) "\n"
  475. "max_backups = " (number->string (virtlog-configuration-max-backups config)) "\n")))
  476. (define (virtlogd-shepherd-service config)
  477. (let* ((config-file (virtlogd-conf-file config))
  478. (libvirt (virtlog-configuration-libvirt config)))
  479. (list (shepherd-service
  480. (documentation "Run the virtlog daemon.")
  481. (provision '(virtlogd))
  482. (start #~(make-forkexec-constructor
  483. (list (string-append #$libvirt "/sbin/virtlogd")
  484. "-f" #$config-file)))
  485. (stop #~(make-kill-destructor))))))
  486. (define virtlog-service-type
  487. (service-type (name 'virtlogd)
  488. (extensions
  489. (list
  490. (service-extension shepherd-root-service-type
  491. virtlogd-shepherd-service)))
  492. (default-value (virtlog-configuration))))
  493. (define (generate-libvirt-documentation)
  494. (generate-documentation
  495. `((libvirt-configuration ,libvirt-configuration-fields))
  496. 'libvirt-configuration))
  497. ;;;
  498. ;;; Transparent QEMU emulation via binfmt_misc.
  499. ;;;
  500. ;; Platforms that QEMU can emulate.
  501. (define-record-type* <qemu-platform>
  502. qemu-platform make-qemu-platform
  503. qemu-platform?
  504. (name qemu-platform-name) ;string
  505. (family qemu-platform-family) ;string
  506. (magic qemu-platform-magic) ;bytevector
  507. (mask qemu-platform-mask) ;bytevector
  508. ;; Default flags:
  509. ;;
  510. ;; "F": fix binary. Open the qemu-user binary (statically linked) as soon
  511. ;; as binfmt_misc interpretation is handled.
  512. ;;
  513. ;; "P": preserve argv[0]. QEMU 6.0 detects whether it's started with this
  514. ;; flag and automatically does the right thing. Without this flag,
  515. ;; argv[0] is replaced by the absolute file name of the executable, an
  516. ;; observable difference that can cause discrepancies.
  517. (flags qemu-platform-flags (default "FP"))) ;string
  518. (define-syntax bv
  519. (lambda (s)
  520. "Expand the given string into a bytevector."
  521. (syntax-case s ()
  522. ((_ str)
  523. (string? (syntax->datum #'str))
  524. (let ((bv (u8-list->bytevector
  525. (map char->integer
  526. (string->list (syntax->datum #'str))))))
  527. bv)))))
  528. ;;; The platform descriptions below are taken from
  529. ;;; 'scripts/qemu-binfmt-conf.sh' in QEMU.
  530. (define %i386
  531. (qemu-platform
  532. (name "i386")
  533. (family "i386")
  534. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00"))
  535. (mask (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  536. (define %alpha
  537. (qemu-platform
  538. (name "alpha")
  539. (family "alpha")
  540. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90"))
  541. (mask (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  542. (define %arm
  543. (qemu-platform
  544. (name "arm")
  545. (family "arm")
  546. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00"))
  547. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  548. (define %armeb
  549. (qemu-platform
  550. (name "armeb")
  551. (family "arm")
  552. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28"))
  553. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  554. (define %sparc
  555. (qemu-platform
  556. (name "sparc")
  557. (family "sparc")
  558. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02"))
  559. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  560. (define %sparc32plus
  561. (qemu-platform
  562. (name "sparc32plus")
  563. (family "sparc")
  564. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12"))
  565. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  566. (define %ppc
  567. (qemu-platform
  568. (name "ppc")
  569. (family "ppc")
  570. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14"))
  571. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  572. (define %ppc64
  573. (qemu-platform
  574. (name "ppc64")
  575. (family "ppc")
  576. (magic (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15"))
  577. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  578. (define %ppc64le
  579. (qemu-platform
  580. (name "ppc64le")
  581. (family "ppcle")
  582. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00"))
  583. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00"))))
  584. (define %m68k
  585. (qemu-platform
  586. (name "m68k")
  587. (family "m68k")
  588. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04"))
  589. (mask (bv "\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  590. ;; XXX: We could use the other endianness on a MIPS host.
  591. (define %mips
  592. (qemu-platform
  593. (name "mips")
  594. (family "mips")
  595. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"))
  596. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  597. (define %mipsel
  598. (qemu-platform
  599. (name "mipsel")
  600. (family "mips")
  601. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00"))
  602. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  603. (define %mipsn32
  604. (qemu-platform
  605. (name "mipsn32")
  606. (family "mips")
  607. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"))
  608. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  609. (define %mipsn32el
  610. (qemu-platform
  611. (name "mipsn32el")
  612. (family "mips")
  613. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00"))
  614. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  615. (define %mips64
  616. (qemu-platform
  617. (name "mips64")
  618. (family "mips")
  619. (magic (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"))
  620. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  621. (define %mips64el
  622. (qemu-platform
  623. (name "mips64el")
  624. (family "mips")
  625. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00"))
  626. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  627. (define %riscv32
  628. (qemu-platform
  629. (name "riscv32")
  630. (family "riscv")
  631. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00"))
  632. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  633. (define %riscv64
  634. (qemu-platform
  635. (name "riscv64")
  636. (family "riscv")
  637. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00"))
  638. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  639. (define %sh4
  640. (qemu-platform
  641. (name "sh4")
  642. (family "sh4")
  643. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00"))
  644. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  645. (define %sh4eb
  646. (qemu-platform
  647. (name "sh4eb")
  648. (family "sh4")
  649. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a"))
  650. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  651. (define %s390x
  652. (qemu-platform
  653. (name "s390x")
  654. (family "s390x")
  655. (magic (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16"))
  656. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  657. (define %aarch64
  658. (qemu-platform
  659. (name "aarch64")
  660. (family "arm")
  661. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00"))
  662. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  663. (define %hppa
  664. (qemu-platform
  665. (name "hppa")
  666. (family "hppa")
  667. (magic (bv "\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f"))
  668. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  669. (define %qemu-platforms
  670. (list %i386 %alpha %arm %sparc32plus %ppc %ppc64 %ppc64le %m68k
  671. %mips %mipsel %mipsn32 %mipsn32el %mips64 %mips64el
  672. %riscv32 %riscv64 %sh4 %sh4eb %s390x %aarch64 %hppa))
  673. (define (lookup-qemu-platforms . names)
  674. "Return the list of QEMU platforms that match NAMES--a list of names such as
  675. \"arm\", \"hppa\", etc."
  676. (filter (lambda (platform)
  677. (member (qemu-platform-name platform) names))
  678. %qemu-platforms))
  679. (define-record-type* <qemu-binfmt-configuration>
  680. qemu-binfmt-configuration make-qemu-binfmt-configuration
  681. qemu-binfmt-configuration?
  682. (qemu qemu-binfmt-configuration-qemu
  683. (default qemu))
  684. (platforms qemu-binfmt-configuration-platforms
  685. (default '()))) ;safest default
  686. (define (qemu-platform->binfmt qemu platform)
  687. "Return a gexp that evaluates to a binfmt string for PLATFORM, using the
  688. given QEMU package."
  689. (define (bytevector->binfmt-string bv)
  690. ;; Return a binfmt-friendly string representing BV. Hex-encode every
  691. ;; character, in particular because the doc notes "that you must escape
  692. ;; any NUL bytes; parsing halts at the first one".
  693. (string-concatenate
  694. (map (lambda (n)
  695. (string-append "\\x"
  696. (string-pad (number->string n 16) 2 #\0)))
  697. (bytevector->u8-list bv))))
  698. (match platform
  699. (($ <qemu-platform> name family magic mask flags)
  700. ;; See 'Documentation/binfmt_misc.txt' in the kernel.
  701. #~(string-append ":qemu-" #$name ":M::"
  702. #$(bytevector->binfmt-string magic)
  703. ":" #$(bytevector->binfmt-string mask)
  704. ":" #$qemu:static "/bin/qemu-" #$name
  705. ":" #$flags))))
  706. (define %binfmt-mount-point
  707. (file-system-mount-point %binary-format-file-system))
  708. (define %binfmt-register-file
  709. (string-append %binfmt-mount-point "/register"))
  710. (define qemu-binfmt-shepherd-services
  711. (match-lambda
  712. (($ <qemu-binfmt-configuration> qemu platforms)
  713. (list (shepherd-service
  714. (provision '(qemu-binfmt))
  715. (documentation "Install binfmt_misc handlers for QEMU.")
  716. (requirement '(file-system-/proc/sys/fs/binfmt_misc))
  717. (start #~(lambda ()
  718. ;; Register the handlers for all of PLATFORMS.
  719. (for-each (lambda (str)
  720. (call-with-output-file
  721. #$%binfmt-register-file
  722. (lambda (port)
  723. (display str port))))
  724. (list
  725. #$@(map (cut qemu-platform->binfmt qemu
  726. <>)
  727. platforms)))
  728. #t))
  729. (stop #~(lambda (_)
  730. ;; Unregister the handlers.
  731. (for-each (lambda (name)
  732. (let ((file (string-append
  733. #$%binfmt-mount-point
  734. "/qemu-" name)))
  735. (call-with-output-file file
  736. (lambda (port)
  737. (display "-1" port)))))
  738. '#$(map qemu-platform-name platforms))
  739. #f)))))))
  740. (define qemu-binfmt-service-type
  741. ;; TODO: Make a separate binfmt_misc service out of this?
  742. (service-type (name 'qemu-binfmt)
  743. (extensions
  744. (list (service-extension file-system-service-type
  745. (const
  746. (list %binary-format-file-system)))
  747. (service-extension shepherd-root-service-type
  748. qemu-binfmt-shepherd-services)))
  749. (default-value (qemu-binfmt-configuration))
  750. (description
  751. "This service supports transparent emulation of binaries
  752. compiled for other architectures using QEMU and the @code{binfmt_misc}
  753. functionality of the kernel Linux.")))
  754. ;;;
  755. ;;; QEMU guest agent service.
  756. ;;;
  757. (define-configuration qemu-guest-agent-configuration
  758. (qemu
  759. (file-like qemu-minimal)
  760. "QEMU package.")
  761. (device
  762. (string "")
  763. "Path to device or socket used to communicate with the host. If not
  764. specified, the QEMU default path is used."))
  765. (define (qemu-guest-agent-shepherd-service config)
  766. (let ((qemu (qemu-guest-agent-configuration-qemu config))
  767. (device (qemu-guest-agent-configuration-device config)))
  768. (list
  769. (shepherd-service
  770. (provision '(qemu-guest-agent))
  771. (documentation "Run the QEMU guest agent.")
  772. (start #~(make-forkexec-constructor
  773. `(,(string-append #$qemu "/bin/qemu-ga") "--daemon"
  774. "--pidfile=/var/run/qemu-ga.pid"
  775. "--statedir=/var/run"
  776. ,@(if #$device
  777. (list (string-append "--path=" #$device))
  778. '()))
  779. #:pid-file "/var/run/qemu-ga.pid"
  780. #:log-file "/var/log/qemu-ga.log"))
  781. (stop #~(make-kill-destructor))))))
  782. (define qemu-guest-agent-service-type
  783. (service-type
  784. (name 'qemu-guest-agent)
  785. (extensions
  786. (list (service-extension shepherd-root-service-type
  787. qemu-guest-agent-shepherd-service)))
  788. (default-value (qemu-guest-agent-configuration))
  789. (description "Run the QEMU guest agent.")))
  790. ;;;
  791. ;;; Secrets for guest VMs.
  792. ;;;
  793. (define (secret-service-shepherd-services port)
  794. "Return a Shepherd service that fetches sensitive material at local PORT,
  795. over TCP. Reboot upon failure."
  796. ;; This is a Shepherd service, rather than an activation snippet, to make
  797. ;; sure it is started once 'networking' is up so it can accept incoming
  798. ;; connections.
  799. (list
  800. (shepherd-service
  801. (documentation "Fetch secrets from the host at startup time.")
  802. (provision '(secret-service-client))
  803. (requirement '(loopback networking))
  804. (modules '((gnu build secret-service)
  805. (guix build utils)))
  806. (start (with-imported-modules '((gnu build secret-service)
  807. (guix build utils))
  808. #~(lambda ()
  809. ;; Since shepherd's output port goes to /dev/log, write this
  810. ;; message to stderr so it's visible on the Mach console.
  811. (format (current-error-port)
  812. "receiving secrets from the host...~%")
  813. (force-output (current-error-port))
  814. (let ((sent (secret-service-receive-secrets #$port)))
  815. (unless sent
  816. (sleep 3)
  817. (reboot))))))
  818. (stop #~(const #f)))))
  819. (define secret-service-type
  820. (service-type
  821. (name 'secret-service)
  822. (extensions (list (service-extension shepherd-root-service-type
  823. secret-service-shepherd-services)
  824. ;; Make every Shepherd service depend on
  825. ;; 'secret-service-client'.
  826. (service-extension user-processes-service-type
  827. (const '(secret-service-client)))))
  828. (description
  829. "This service fetches secret key and other sensitive material over TCP at
  830. boot time. This service is meant to be used by virtual machines (VMs) that
  831. can only be accessed by their host.")))
  832. (define (secret-service-operating-system os)
  833. "Return an operating system based on OS that includes the secret-service,
  834. that will be listening to receive secret keys on port 1004, TCP."
  835. (operating-system
  836. (inherit os)
  837. (services
  838. ;; Turn off SSH and Guix key generation that normally happens during
  839. ;; activation: that requires entropy and thus takes time during boot, and
  840. ;; those keys are going to be overwritten by secrets received from the
  841. ;; host anyway.
  842. (cons (service secret-service-type 1004)
  843. (modify-services (operating-system-user-services os)
  844. (openssh-service-type
  845. config => (openssh-configuration
  846. (inherit config)
  847. (generate-host-keys? #f)))
  848. (guix-service-type
  849. config => (guix-configuration
  850. (generate-substitute-key? #f))))))))
  851. ;;;
  852. ;;; The Hurd in VM service: a Childhurd.
  853. ;;;
  854. (define %hurd-vm-operating-system
  855. (operating-system
  856. (inherit %hurd-default-operating-system)
  857. (host-name "childhurd")
  858. (timezone "Europe/Amsterdam")
  859. (bootloader (bootloader-configuration
  860. (bootloader grub-minimal-bootloader)
  861. (targets '("/dev/vda"))
  862. (timeout 0)))
  863. (packages (cons* gdb-minimal
  864. (operating-system-packages
  865. %hurd-default-operating-system)))
  866. (services (cons*
  867. (service openssh-service-type
  868. (openssh-configuration
  869. (openssh openssh-sans-x)
  870. (use-pam? #f)
  871. (port-number 2222)
  872. (permit-root-login #t)
  873. (allow-empty-passwords? #t)
  874. (password-authentication? #t)))
  875. ;; By default, the secret service introduces a pre-initialized
  876. ;; /etc/guix/acl file in the childhurd. Thus, clear
  877. ;; 'authorize-key?' so that it's not overridden at activation
  878. ;; time.
  879. (modify-services %base-services/hurd
  880. (guix-service-type config =>
  881. (guix-configuration
  882. (inherit config)
  883. (authorize-key? #f))))))))
  884. (define-record-type* <hurd-vm-configuration>
  885. hurd-vm-configuration make-hurd-vm-configuration
  886. hurd-vm-configuration?
  887. (os hurd-vm-configuration-os ;<operating-system>
  888. (default %hurd-vm-operating-system))
  889. (qemu hurd-vm-configuration-qemu ;file-like
  890. (default qemu-minimal))
  891. (image hurd-vm-configuration-image ;string
  892. (thunked)
  893. (default (hurd-vm-disk-image this-record)))
  894. (disk-size hurd-vm-configuration-disk-size ;number or 'guess
  895. (default 'guess))
  896. (memory-size hurd-vm-configuration-memory-size ;number
  897. (default 512))
  898. (options hurd-vm-configuration-options ;list of string
  899. (default `("--snapshot")))
  900. (id hurd-vm-configuration-id ;#f or integer [1..]
  901. (default #f))
  902. (net-options hurd-vm-configuration-net-options ;list of string
  903. (thunked)
  904. (default (hurd-vm-net-options this-record)))
  905. (secret-root hurd-vm-configuration-secret-root ;string
  906. (default "/etc/childhurd")))
  907. (define (hurd-vm-disk-image config)
  908. "Return a disk-image for the Hurd according to CONFIG. The secret-service
  909. is added to the OS specified in CONFIG."
  910. (let* ((os (secret-service-operating-system
  911. (hurd-vm-configuration-os config)))
  912. (disk-size (hurd-vm-configuration-disk-size config))
  913. (type (lookup-image-type-by-name 'hurd-qcow2))
  914. (os->image (image-type-constructor type)))
  915. (system-image
  916. (image (inherit (os->image os))
  917. (size disk-size)))))
  918. (define (hurd-vm-port config base)
  919. "Return the forwarded vm port for this childhurd config."
  920. (let ((id (or (hurd-vm-configuration-id config) 0)))
  921. (+ base (* 1000 id))))
  922. (define %hurd-vm-secrets-port 11004)
  923. (define %hurd-vm-ssh-port 10022)
  924. (define %hurd-vm-vnc-port 15900)
  925. (define (hurd-vm-net-options config)
  926. `("--device" "rtl8139,netdev=net0"
  927. "--netdev"
  928. ,(string-append "user,id=net0"
  929. ",hostfwd=tcp:127.0.0.1:"
  930. (number->string (hurd-vm-port config %hurd-vm-secrets-port))
  931. "-:1004"
  932. ",hostfwd=tcp:127.0.0.1:"
  933. (number->string (hurd-vm-port config %hurd-vm-ssh-port))
  934. "-:2222"
  935. ",hostfwd=tcp:127.0.0.1:"
  936. (number->string (hurd-vm-port config %hurd-vm-vnc-port))
  937. "-:5900")))
  938. (define (hurd-vm-shepherd-service config)
  939. "Return a <shepherd-service> for a Hurd in a Virtual Machine with CONFIG."
  940. (let ((image (hurd-vm-configuration-image config))
  941. (qemu (hurd-vm-configuration-qemu config))
  942. (memory-size (hurd-vm-configuration-memory-size config))
  943. (options (hurd-vm-configuration-options config))
  944. (id (hurd-vm-configuration-id config))
  945. (net-options (hurd-vm-configuration-net-options config))
  946. (provisions '(hurd-vm childhurd)))
  947. (define vm-command
  948. #~(append (list #$(file-append qemu "/bin/qemu-system-i386")
  949. "-m" (number->string #$memory-size)
  950. #$@net-options
  951. #$@options
  952. "--hda" #+image
  953. ;; Cause the service to be respawned if the guest
  954. ;; reboots (it can reboot for instance if it did not
  955. ;; receive valid secrets, or if it crashed.)
  956. "--no-reboot")
  957. (if (file-exists? "/dev/kvm")
  958. '("--enable-kvm")
  959. '())))
  960. (list
  961. (shepherd-service
  962. (documentation "Run the Hurd in a Virtual Machine: a Childhurd.")
  963. (provision (if id
  964. (map
  965. (cute symbol-append <>
  966. (string->symbol (number->string id)))
  967. provisions)
  968. provisions))
  969. (requirement '(loopback networking user-processes))
  970. (start
  971. (with-imported-modules
  972. (source-module-closure '((gnu build secret-service)
  973. (guix build utils)))
  974. #~(lambda ()
  975. (let ((pid (fork+exec-command #$vm-command
  976. #:user "childhurd"
  977. ;; XXX TODO: use "childhurd" after
  978. ;; updating Shepherd
  979. #:group "kvm"
  980. #:environment-variables
  981. ;; QEMU tries to write to /var/tmp
  982. ;; by default.
  983. '("TMPDIR=/tmp")))
  984. (port #$(hurd-vm-port config %hurd-vm-secrets-port))
  985. (root #$(hurd-vm-configuration-secret-root config)))
  986. (catch #t
  987. (lambda _
  988. ;; XXX: 'secret-service-send-secrets' won't complete until
  989. ;; the guest has booted and its secret service server is
  990. ;; running, which could take 20+ seconds during which PID 1
  991. ;; is stuck waiting.
  992. (if (secret-service-send-secrets port root)
  993. pid
  994. (begin
  995. (kill (- pid) SIGTERM)
  996. #f)))
  997. (lambda (key . args)
  998. (kill (- pid) SIGTERM)
  999. (apply throw key args)))))))
  1000. (modules `((gnu build secret-service)
  1001. (guix build utils)
  1002. ,@%default-modules))
  1003. (stop #~(make-kill-destructor))))))
  1004. (define %hurd-vm-accounts
  1005. (list (user-group (name "childhurd") (system? #t))
  1006. (user-account
  1007. (name "childhurd")
  1008. (group "childhurd")
  1009. (supplementary-groups '("kvm"))
  1010. (comment "Privilege separation user for the childhurd")
  1011. (home-directory "/var/empty")
  1012. (shell (file-append shadow "/sbin/nologin"))
  1013. (system? #t))))
  1014. (define (initialize-hurd-vm-substitutes)
  1015. "Initialize the Hurd VM's key pair and ACL and store it on the host."
  1016. (define run
  1017. (with-imported-modules '((guix build utils))
  1018. #~(begin
  1019. (use-modules (guix build utils)
  1020. (ice-9 match))
  1021. (define host-key
  1022. "/etc/guix/signing-key.pub")
  1023. (define host-acl
  1024. "/etc/guix/acl")
  1025. (match (command-line)
  1026. ((_ guest-config-directory)
  1027. (setenv "GUIX_CONFIGURATION_DIRECTORY"
  1028. guest-config-directory)
  1029. (invoke #+(file-append guix "/bin/guix") "archive"
  1030. "--generate-key")
  1031. (when (file-exists? host-acl)
  1032. ;; Copy the host ACL.
  1033. (copy-file host-acl
  1034. (string-append guest-config-directory
  1035. "/acl")))
  1036. (when (file-exists? host-key)
  1037. ;; Add the host key to the childhurd's ACL.
  1038. (let ((key (open-fdes host-key O_RDONLY)))
  1039. (close-fdes 0)
  1040. (dup2 key 0)
  1041. (execl #+(file-append guix "/bin/guix")
  1042. "guix" "archive" "--authorize"))))))))
  1043. (program-file "initialize-hurd-vm-substitutes" run))
  1044. (define (hurd-vm-activation config)
  1045. "Return a gexp to activate the Hurd VM according to CONFIG."
  1046. (with-imported-modules '((guix build utils))
  1047. #~(begin
  1048. (use-modules (guix build utils))
  1049. (define secret-directory
  1050. #$(hurd-vm-configuration-secret-root config))
  1051. (define ssh-directory
  1052. (string-append secret-directory "/etc/ssh"))
  1053. (define guix-directory
  1054. (string-append secret-directory "/etc/guix"))
  1055. (unless (file-exists? ssh-directory)
  1056. ;; Generate SSH host keys under SSH-DIRECTORY.
  1057. (mkdir-p ssh-directory)
  1058. (invoke #$(file-append openssh "/bin/ssh-keygen")
  1059. "-A" "-f" secret-directory))
  1060. (unless (file-exists? guix-directory)
  1061. (invoke #$(initialize-hurd-vm-substitutes)
  1062. guix-directory)))))
  1063. (define hurd-vm-service-type
  1064. (service-type
  1065. (name 'hurd-vm)
  1066. (extensions (list (service-extension shepherd-root-service-type
  1067. hurd-vm-shepherd-service)
  1068. (service-extension account-service-type
  1069. (const %hurd-vm-accounts))
  1070. (service-extension activation-service-type
  1071. hurd-vm-activation)))
  1072. (default-value (hurd-vm-configuration))
  1073. (description
  1074. "Provide a virtual machine (VM) running GNU/Hurd, also known as a
  1075. @dfn{childhurd}.")))