virtualization.scm 42 KB

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