virtualization.scm 45 KB

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