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