virtualization.scm 42 KB

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