virtualization.scm 49 KB

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