virtualization.scm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
  3. ;;; Copyright © 2020-2023 Ludovic Courtès <ludo@gnu.org>
  4. ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  5. ;;; Copyright © 2021 Pierre Langlois <pierre.langlois@gmx.com>
  6. ;;; Copyright © 2022 Marius Bakke <marius@gnu.org>
  7. ;;;
  8. ;;; This file is part of GNU Guix.
  9. ;;;
  10. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  11. ;;; under the terms of the GNU General Public License as published by
  12. ;;; the Free Software Foundation; either version 3 of the License, or (at
  13. ;;; your option) any later version.
  14. ;;;
  15. ;;; GNU Guix is distributed in the hope that it will be useful, but
  16. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;;; GNU General Public License for more details.
  19. ;;;
  20. ;;; You should have received a copy of the GNU General Public License
  21. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  22. (define-module (gnu tests virtualization)
  23. #:use-module (gnu tests)
  24. #:use-module (gnu image)
  25. #:use-module (gnu system)
  26. #:use-module (gnu system file-systems)
  27. #:use-module (gnu system image)
  28. #:use-module (gnu system images hurd)
  29. #:use-module (gnu system vm)
  30. #:use-module (gnu services)
  31. #:use-module (gnu services dbus)
  32. #:use-module (gnu services networking)
  33. #:use-module (gnu services virtualization)
  34. #:use-module (gnu packages ssh)
  35. #:use-module (gnu packages virtualization)
  36. #:use-module (guix gexp)
  37. #:use-module (guix records)
  38. #:use-module (guix store)
  39. #:export (%test-libvirt
  40. %test-qemu-guest-agent
  41. %test-childhurd))
  42. ;;;
  43. ;;; Libvirt.
  44. ;;;
  45. (define %libvirt-os
  46. (simple-operating-system
  47. (service dhcp-client-service-type)
  48. (service dbus-root-service-type)
  49. (service polkit-service-type)
  50. (service libvirt-service-type)))
  51. (define (run-libvirt-test)
  52. "Run tests in %LIBVIRT-OS."
  53. (define os
  54. (marionette-operating-system
  55. %libvirt-os
  56. #:imported-modules '((gnu services herd)
  57. (guix combinators))))
  58. (define vm
  59. (virtual-machine
  60. (operating-system os)
  61. (port-forwardings '())))
  62. (define test
  63. (with-imported-modules '((gnu build marionette))
  64. #~(begin
  65. (use-modules (srfi srfi-11) (srfi srfi-64)
  66. (gnu build marionette))
  67. (define marionette
  68. (make-marionette (list #$vm)))
  69. (test-runner-current (system-test-runner #$output))
  70. (test-begin "libvirt")
  71. (test-assert "service running"
  72. (marionette-eval
  73. '(begin
  74. (use-modules (gnu services herd))
  75. (match (start-service 'libvirtd)
  76. (#f #f)
  77. (('service response-parts ...)
  78. (match (assq-ref response-parts 'running)
  79. ((pid) (number? pid))))))
  80. marionette))
  81. (test-eq "fetch version"
  82. 0
  83. (marionette-eval
  84. `(begin
  85. (chdir "/tmp")
  86. (system* ,(string-append #$libvirt "/bin/virsh")
  87. "-c" "qemu:///system" "version"))
  88. marionette))
  89. (test-eq "connect"
  90. 0
  91. (marionette-eval
  92. `(begin
  93. (chdir "/tmp")
  94. (system* ,(string-append #$libvirt "/bin/virsh")
  95. "-c" "qemu:///system" "connect"))
  96. marionette))
  97. (test-eq "create default network"
  98. 0
  99. (marionette-eval
  100. '(begin
  101. (chdir "/tmp")
  102. (system* #$(file-append libvirt "/bin/virsh")
  103. "-c" "qemu:///system" "net-define"
  104. #$(file-append libvirt
  105. "/etc/libvirt/qemu/networks/default.xml")))
  106. marionette))
  107. (test-eq "start default network"
  108. 0
  109. (marionette-eval
  110. '(begin
  111. (chdir "/tmp")
  112. (system* #$(file-append libvirt "/bin/virsh")
  113. "-c" "qemu:///system" "net-start" "default"))
  114. marionette))
  115. (test-end))))
  116. (gexp->derivation "libvirt-test" test))
  117. (define %test-libvirt
  118. (system-test
  119. (name "libvirt")
  120. (description "Connect to the running LIBVIRT service.")
  121. (value (run-libvirt-test))))
  122. ;;;
  123. ;;; QEMU Guest Agent service.
  124. ;;;
  125. (define %qemu-guest-agent-os
  126. (simple-operating-system
  127. (service qemu-guest-agent-service-type)))
  128. (define (run-qemu-guest-agent-test)
  129. "Run tests in %QEMU-GUEST-AGENT-OS."
  130. (define os
  131. (marionette-operating-system
  132. %qemu-guest-agent-os
  133. #:imported-modules '((gnu services herd))))
  134. (define vm
  135. (virtual-machine
  136. (operating-system os)
  137. (port-forwardings '())))
  138. (define test
  139. (with-imported-modules '((gnu build marionette))
  140. #~(begin
  141. (use-modules (gnu build marionette)
  142. (ice-9 rdelim)
  143. (srfi srfi-64))
  144. (define marionette
  145. ;; Ensure we look for the socket in the correct place below.
  146. (make-marionette (list #$vm) #:socket-directory "/tmp"))
  147. (define* (try-read port #:optional (attempts 10))
  148. ;; Try reading from a port several times before giving up.
  149. (cond ((char-ready? port)
  150. (let ((response (read-line port)))
  151. (close-port port)
  152. response))
  153. ((> attempts 1)
  154. (sleep 1)
  155. (try-read port (- attempts 1)))
  156. (else "")))
  157. (define (run command)
  158. ;; Run a QEMU guest agent command and return the response.
  159. (let ((s (socket PF_UNIX SOCK_STREAM 0)))
  160. (connect s AF_UNIX "/tmp/qemu-ga")
  161. (display command s)
  162. (try-read s)))
  163. (test-runner-current (system-test-runner #$output))
  164. (test-begin "qemu-guest-agent")
  165. (test-assert "service running"
  166. (marionette-eval
  167. '(begin
  168. (use-modules (gnu services herd))
  169. (match (start-service 'qemu-guest-agent)
  170. (#f #f)
  171. (('service response-parts ...)
  172. (match (assq-ref response-parts 'running)
  173. ((pid) (number? pid))))))
  174. marionette))
  175. (test-equal "ping guest"
  176. "{\"return\": {}}"
  177. (run "{\"execute\": \"guest-ping\"}"))
  178. (test-assert "get network interfaces"
  179. (string-contains
  180. (run "{\"execute\": \"guest-network-get-interfaces\"}")
  181. "127.0.0.1"))
  182. (test-end))))
  183. (gexp->derivation "qemu-guest-agent-test" test))
  184. (define %test-qemu-guest-agent
  185. (system-test
  186. (name "qemu-guest-agent")
  187. (description "Run commands in a virtual machine using QEMU guest agent.")
  188. (value (run-qemu-guest-agent-test))))
  189. ;;;
  190. ;;; GNU/Hurd virtual machines, aka. childhurds.
  191. ;;;
  192. ;; Copy of `hurd-vm-disk-image', using plain disk-image for test
  193. (define (hurd-vm-disk-image-raw config)
  194. (let ((os ((@@ (gnu services virtualization) secret-service-operating-system)
  195. (hurd-vm-configuration-os config)))
  196. (disk-size (hurd-vm-configuration-disk-size config)))
  197. (system-image
  198. (image
  199. (inherit hurd-disk-image)
  200. (format 'disk-image)
  201. (size disk-size)
  202. (operating-system os)))))
  203. (define %childhurd-os
  204. (simple-operating-system
  205. (service dhcp-client-service-type)
  206. (service hurd-vm-service-type
  207. (hurd-vm-configuration
  208. (image (hurd-vm-disk-image-raw this-record))))))
  209. (define (run-childhurd-test)
  210. (define os
  211. (marionette-operating-system
  212. %childhurd-os
  213. #:imported-modules '((gnu services herd)
  214. (guix combinators))))
  215. (define vm
  216. (virtual-machine
  217. (operating-system os)
  218. (memory-size (* 1024 3))))
  219. (define (run-command-over-ssh . command)
  220. ;; Program that runs COMMAND over SSH and prints the result on standard
  221. ;; output.
  222. (let ()
  223. (define run
  224. (with-extensions (list guile-ssh)
  225. #~(begin
  226. (use-modules (ssh session)
  227. (ssh auth)
  228. (ssh popen)
  229. (ice-9 match)
  230. (ice-9 textual-ports))
  231. (let ((session (make-session #:user "root"
  232. #:port 10022
  233. #:host "localhost"
  234. #:log-verbosity 'rare)))
  235. (match (connect! session)
  236. ('ok
  237. (userauth-password! session "")
  238. (display
  239. (get-string-all
  240. (open-remote-input-pipe* session #$@command))))
  241. (status
  242. (error "could not connect to childhurd over SSH"
  243. session status)))))))
  244. (program-file "run-command-over-ssh" run)))
  245. (define test
  246. (with-imported-modules '((gnu build marionette))
  247. #~(begin
  248. (use-modules (gnu build marionette)
  249. (srfi srfi-64)
  250. (ice-9 match))
  251. (define marionette
  252. (make-marionette (list #$vm)))
  253. (test-runner-current (system-test-runner #$output))
  254. (test-begin "childhurd")
  255. (test-assert "service running"
  256. (marionette-eval
  257. '(begin
  258. (use-modules (gnu services herd)
  259. (ice-9 match))
  260. (match (start-service 'childhurd)
  261. (#f #f)
  262. (('service response-parts ...)
  263. (match (assq-ref response-parts 'running)
  264. ((pid) (number? pid))))))
  265. marionette))
  266. (test-equal "childhurd SSH server replies"
  267. "SSH"
  268. ;; Check from within the guest whether its childhurd's SSH
  269. ;; server is reachable. Do that from the guest: port forwarding
  270. ;; to the host won't work because QEMU listens on 127.0.0.1.
  271. (marionette-eval
  272. '(begin
  273. (use-modules (ice-9 match)
  274. (ice-9 textual-ports))
  275. (let loop ((n 60))
  276. (if (zero? n)
  277. 'all-attempts-failed
  278. (let ((s (socket PF_INET SOCK_STREAM 0))
  279. (a (make-socket-address AF_INET
  280. INADDR_LOOPBACK
  281. 10022)))
  282. (format #t "connecting to childhurd SSH server...~%")
  283. (connect s a)
  284. (match (get-string-n s 3)
  285. ((? eof-object?)
  286. (close-port s)
  287. (sleep 1)
  288. (loop (- n 1)))
  289. (str
  290. (close-port s)
  291. str))))))
  292. marionette))
  293. (test-equal "SSH up and running"
  294. "childhurd GNU\n"
  295. ;; Connect from the guest to the chidhurd over SSH and run the
  296. ;; 'uname' command.
  297. (marionette-eval
  298. '(begin
  299. (use-modules (ice-9 popen))
  300. (get-string-all
  301. (open-input-pipe #$(run-command-over-ssh "uname" "-on"))))
  302. marionette))
  303. (test-assert "guix-daemon up and running"
  304. (let ((drv (marionette-eval
  305. '(begin
  306. (use-modules (ice-9 popen))
  307. (get-string-all
  308. (open-input-pipe
  309. #$(run-command-over-ssh "guix" "build" "coreutils"
  310. "--no-grafts" "-d"))))
  311. marionette)))
  312. ;; We cannot compare the .drv with (raw-derivation-file
  313. ;; coreutils) on the host: they may differ due to fixed-output
  314. ;; derivations and changes introduced compared to the 'guix'
  315. ;; package snapshot.
  316. (and (string-suffix? ".drv"
  317. (pk 'drv (string-trim-right drv)))
  318. drv)))
  319. (test-end))))
  320. (gexp->derivation "childhurd-test" test))
  321. (define %test-childhurd
  322. (system-test
  323. (name "childhurd")
  324. (description
  325. "Connect to the GNU/Hurd virtual machine service, aka. a childhurd, making
  326. sure that the childhurd boots and runs its SSH server.")
  327. (value (run-childhurd-test))))