-
Notifications
You must be signed in to change notification settings - Fork 896
Expand file tree
/
Copy pathtest-templates.sh
More file actions
executable file
·704 lines (634 loc) · 23.3 KB
/
test-templates.sh
File metadata and controls
executable file
·704 lines (634 loc) · 23.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright The Lima Authors
# SPDX-License-Identifier: Apache-2.0
set -eu -o pipefail
# will prevent msys2 converting Linux path arguments into Windows paths before passing to limactl
export MSYS2_ARG_CONV_EXCL='*'
scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=common.inc.sh
source "${scriptdir}/common.inc.sh"
# Check required prerequisites before doing anything else
for _cmd in limactl jq curl timeout diff perl; do
if ! command -v "$_cmd" &>/dev/null; then
ERROR "Required prerequisite not found: $_cmd"
exit 1
fi
done
if [ "$#" -ne 1 ]; then
ERROR "Usage: $0 FILE.yaml"
exit 1
fi
# Resolve any ../ fragments in the filename because they are invalid in relative template locators
FILE="$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
NAME="$(basename -s .yaml "$FILE")"
OS_HOST="$(uname -o)"
# On Windows $HOME of the bash runner, %USERPROFILE% of the host machine and mounting point in the guest machine
# are all different folders. This will handle path differences, when values are explicitly set.
HOME_HOST=${HOME_HOST:-$HOME}
HOME_GUEST=${HOME_GUEST:-$HOME}
FILE_HOST=$FILE
if [ "${OS_HOST}" = "Msys" ]; then
FILE_HOST="$(cygpath -w "$FILE")"
fi
INFO "Validating \"$FILE_HOST\""
limactl validate "$FILE_HOST"
LIMACTL_CREATE=(limactl --tty=false create)
CONTAINER_ENGINE="nerdctl"
declare -A CHECKS=(
["proxy-settings"]="1"
["systemd"]="1"
["mount-home"]="1"
["container-engine"]="1"
["restart"]="1"
# snapshot tests are too flaky (especially with archlinux)
["snapshot-online"]=""
["snapshot-offline"]=""
["clone"]=""
["port-forwards"]="1"
["vmnet"]=""
["disk"]=""
["user-v2"]=""
["mount-path-with-spaces"]=""
["provision-data"]=""
["provision-yq"]=""
["param-env-variables"]=""
["set-user"]=""
["preserve-env"]="1"
["static-port-forwards"]=""
["ssh-over-vsock"]=""
)
case "$NAME" in
"default")
# CI failure:
# "[hostagent] failed to confirm whether /c/Users/runneradmin [remote] is successfully mounted"
[ "${OS_HOST}" = "Msys" ] && CHECKS["mount-home"]=
[ "${OS_HOST}" = "Darwin" ] && CHECKS["ssh-over-vsock"]="1"
;;
"alpine"*)
WARNING "Alpine does not support systemd"
CHECKS["systemd"]=
CHECKS["container-engine"]=
[ "$NAME" = "alpine-iso-9p-writable" ] && CHECKS["mount-path-with-spaces"]="1"
;;
"k3s")
ERROR "File \"$FILE\" is not testable with this script"
exit 1
;;
"test-misc")
CHECKS["disk"]=1
CHECKS["snapshot-online"]="1"
CHECKS["snapshot-offline"]="1"
CHECKS["clone"]="1"
CHECKS["mount-path-with-spaces"]="1"
CHECKS["provision-data"]="1"
CHECKS["provision-yq"]="1"
CHECKS["param-env-variables"]="1"
CHECKS["set-user"]="1"
CHECKS["static-port-forwards"]="1"
;;
"docker")
CONTAINER_ENGINE="docker"
;;
"wsl2")
# TODO https://github.com/lima-vm/lima/issues/3268
CHECKS["proxy-settings"]=
;;
"archlinux")
;;
esac
if limactl ls -q "$NAME" 2>/dev/null; then
ERROR "Instance $NAME already exists"
exit 1
fi
case "$(limactl tmpl yq "$FILE_HOST" '.networks[].lima')" in
"shared")
CHECKS["vmnet"]=1
;;
"user-v2")
CHECKS["port-forwards"]=""
CHECKS["user-v2"]=1
;;
esac
if [[ -n ${CHECKS["port-forwards"]} ]]; then
tmpconfig="$HOME_HOST/lima-config-tmp"
mkdir -p "${tmpconfig}"
defer "rm -rf \"$tmpconfig\""
tmpfile="${tmpconfig}/${NAME}.yaml"
cp "$FILE" "${tmpfile}"
FILE="${tmpfile}"
FILE_HOST=$FILE
if [ "${OS_HOST}" = "Msys" ]; then
FILE_HOST="$(cygpath -w "$FILE")"
fi
INFO "Setup port forwarding rules for testing in \"${FILE}\""
"${scriptdir}/test-port-forwarding.pl" "${FILE}"
INFO "Validating \"$FILE_HOST\""
limactl validate "$FILE_HOST"
fi
INFO "Make sure template embedding copies \"$FILE_HOST\" exactly"
diff -u <(echo -n "base: $FILE_HOST" | limactl tmpl copy --embed - -) "$FILE_HOST"
function diagnose() {
NAME="$1"
set -x +e
tail "$HOME_HOST/.lima/${NAME}"/*.log
limactl shell "$NAME" systemctl --no-pager status
limactl shell "$NAME" systemctl --no-pager
mkdir -p failure-logs
cp -pf "$HOME_HOST/.lima/${NAME}"/*.log failure-logs/
limactl shell "$NAME" sudo cat /var/log/cloud-init-output.log | tee failure-logs/cloud-init-output.log
limactl shell "$NAME" sh -c "command -v journalctl >/dev/null && sudo journalctl --no-pager" >failure-logs/journal.log
set +x -e
}
export ftp_proxy=http://localhost:2121
INFO "Creating \"$NAME\" from \"$FILE_HOST\""
defer "limactl delete -f \"$NAME\""
if [[ -n ${CHECKS["disk"]} ]]; then
if [[ -z "$(limactl disk ls data --json 2>/dev/null)" ]]; then
defer "limactl disk delete data"
limactl disk create data --size 10G
fi
if ! limactl disk ls | grep -q "^swap\s"; then
defer "limactl disk delete swap"
limactl disk create swap --size 2G
fi
fi
set -x
# shellcheck disable=SC2086
"${LIMACTL_CREATE[@]}" ${LIMACTL_CREATE_ARGS:-} "$FILE_HOST"
set +x
if [[ -n ${CHECKS["mount-path-with-spaces"]} ]]; then
mkdir -p "/tmp/lima test dir with spaces"
echo "test file content" >"/tmp/lima test dir with spaces/test file"
fi
INFO "Starting \"$NAME\""
set -x
if ! limactl start "$NAME"; then
ERROR "Failed to start \"$NAME\""
diagnose "$NAME"
exit 1
fi
limactl shell "$NAME" uname -a
limactl shell "$NAME" cat /etc/os-release
set +x
INFO "Testing that host home is not wiped out"
[ -e "$HOME_HOST/.lima" ]
if [[ -n ${CHECKS["mount-path-with-spaces"]} ]]; then
INFO 'Testing that "/tmp/lima test dir with spaces" is not wiped out'
[ "$(cat "/tmp/lima test dir with spaces/test file")" = "test file content" ]
[ "$(limactl shell "$NAME" cat "/tmp/lima test dir with spaces/test file")" = "test file content" ]
fi
if [[ -n ${CHECKS["provision-data"]} ]]; then
INFO 'Testing that /etc/sysctl.d/99-inotify.conf was created successfully on provision'
limactl shell "$NAME" grep -q fs.inotify.max_user_watches /etc/sysctl.d/99-inotify.conf
fi
if [[ -n ${CHECKS["provision-yq"]} ]]; then
INFO 'Testing that /tmp/param-yq.json was created successfully on provision'
limactl shell "$NAME" grep -q '"YQ": "yq"' /tmp/param-yq.json
fi
if [[ -n ${CHECKS["param-env-variables"]} ]]; then
INFO 'Testing that PARAM env variables are exported to all types of provisioning scripts and probes'
limactl shell "$NAME" test -e /tmp/param-ansible
limactl shell "$NAME" test -e /tmp/param-boot
limactl shell "$NAME" test -e /tmp/param-dependency
limactl shell "$NAME" test -e /tmp/param-probe
limactl shell "$NAME" test -e /tmp/param-system
limactl shell "$NAME" test -e /tmp/param-user
fi
if [[ -n ${CHECKS["set-user"]} ]]; then
INFO 'Testing that user settings can be provided by lima.yaml'
limactl shell "$NAME" grep "^john:x:4711:4711:John Doe:/home/john-john:/usr/bin/bash" /etc/passwd
fi
if [[ -n ${CHECKS["proxy-settings"]} ]]; then
INFO "Testing proxy settings are imported"
got=$(limactl shell "$NAME" env | grep FTP_PROXY)
# Expected: FTP_PROXY is set in addition to ftp_proxy, localhost is replaced
# by the gateway address, and the value is set immediately without a restart
gatewayIp=$(limactl shell "$NAME" ip route show 0.0.0.0/0 dev eth0 | cut -d\ -f3)
expected="FTP_PROXY=http://${gatewayIp}:2121"
INFO "FTP_PROXY: expected=${expected} got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "proxy environment variable not set to correct value"
exit 1
fi
fi
INFO "Testing limactl copy command"
tmpdir="$(mktemp -d "${TMPDIR:-/tmp}"/lima-test-templates.XXXXXX)"
defer "rm -rf \"$tmpdir\""
tmpfile="$tmpdir/lima-hostname"
rm -f "$tmpfile"
tmpfile_host=$tmpfile
if [ "${OS_HOST}" = "Msys" ]; then
tmpfile_host="$(cygpath -w "$tmpfile")"
fi
limactl cp "$NAME":/etc/hostname "$tmpfile_host"
expected="$(limactl shell "$NAME" cat /etc/hostname)"
got="$(cat "$tmpfile")"
INFO "/etc/hostname: expected=${expected}, got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "copy command did not fetch the file"
exit 1
fi
INFO "Testing limactl copy command with scp backend"
tmpfile_scp="$tmpdir/lima-hostname-scp"
rm -f "$tmpfile_scp"
tmpfile_scp_host=$tmpfile_scp
if [ "${OS_HOST}" = "Msys" ]; then
tmpfile_scp_host="$(cygpath -w "$tmpfile_scp")"
fi
limactl cp --backend=scp "$NAME":/etc/hostname "$tmpfile_scp_host"
expected="$(limactl shell "$NAME" cat /etc/hostname)"
got="$(cat "$tmpfile_scp")"
INFO "/etc/hostname (scp): expected=${expected}, got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "copy command with scp backend did not fetch the file"
exit 1
fi
if command -v rsync >/dev/null && limactl shell "$NAME" command -v rsync >/dev/null 2>&1; then
INFO "Testing limactl copy command with rsync backend"
tmpfile_rsync="$tmpdir/lima-hostname-rsync"
rm -f "$tmpfile_rsync"
tmpfile_rsync_host=$tmpfile_rsync
if [ "${OS_HOST}" = "Msys" ]; then
tmpfile_rsync_host="$(cygpath -w "$tmpfile_rsync")"
fi
limactl cp --backend=rsync "$NAME":/etc/hostname "$tmpfile_rsync_host"
expected="$(limactl shell "$NAME" cat /etc/hostname)"
got="$(cat "$tmpfile_rsync")"
INFO "/etc/hostname (rsync): expected=${expected}, got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "copy command with rsync backend did not fetch the file"
exit 1
fi
INFO "Testing limactl copy command with rsync backend (verbose, recursive)"
testdir="$tmpdir/test-rsync-dir"
mkdir -p "$testdir"
echo "test content" >"$testdir/testfile.txt"
limactl cp --backend=rsync -r -v "$testdir" "$NAME":/tmp/
if ! limactl shell "$NAME" test -f /tmp/test-rsync-dir/testfile.txt; then
ERROR "rsync recursive copy failed"
exit 1
fi
rsync_content="$(limactl shell "$NAME" cat /tmp/test-rsync-dir/testfile.txt)"
if [ "$rsync_content" != "test content" ]; then
ERROR "rsync file content mismatch"
exit 1
fi
else
INFO "Skipping rsync backend test (rsync not available on host or guest)"
fi
INFO "Testing limactl command with escaped characters"
limactl shell "$NAME" bash -c "$(echo -e '\n\techo foo\n\techo bar')"
INFO "Testing limactl command with quotes"
limactl shell "$NAME" bash -c "echo 'foo \"bar\"'"
if [[ -n ${CHECKS["systemd"]} ]]; then
set -x
if ! limactl shell "$NAME" systemctl is-system-running --wait; then
ERROR '"systemctl is-system-running" failed'
diagnose "$NAME"
exit 1
fi
set +x
fi
if [[ -n ${CHECKS["mount-home"]} ]]; then
"${scriptdir}"/test-mount-home.sh "$NAME"
fi
if [[ -n ${CHECKS["ssh-over-vsock"]} ]]; then
if [[ "$(limactl ls "${NAME}" --yq .vmType)" == "vz" ]]; then
INFO "Testing SSH over vsock"
set -x
log_file="$HOME_HOST/.lima/${NAME}/ha.stdout.log"
# Helper function to check vsock events in the log file
# $1: event_type to check for
check_vsock_event() {
local event_type="$1"
if jq -e --arg type "$event_type" 'select(.status.vsock.type == $type)' "$log_file" >/dev/null 2>&1; then
return 0
fi
return 1
}
INFO "Testing .ssh.overVsock=true configuration"
limactl stop "${NAME}"
# Detection of the SSH server on VSOCK may fail; however, a failing log indicates that controlling detection via the environment variable works as expected.
limactl start --set '.ssh.overVsock=true' "${NAME}"
if ! check_vsock_event "started" && ! check_vsock_event "failed"; then
set +x
diagnose "${NAME}"
ERROR ".ssh.overVsock=true did not enable vsock forwarder"
exit 1
fi
INFO 'Testing .ssh.overVsock=null configuration'
limactl stop "${NAME}"
# Detection of the SSH server on VSOCK may fail; however, a failing log indicates that controlling detection via the environment variable works as expected.
limactl start --set '.ssh.overVsock=null' "${NAME}"
if ! check_vsock_event "started" && ! check_vsock_event "failed"; then
set +x
diagnose "${NAME}"
ERROR ".ssh.overVsock=null did not enable vsock forwarder"
exit 1
fi
INFO "Testing .ssh.overVsock=false configuration"
limactl stop "${NAME}"
limactl start --set '.ssh.overVsock=false' "${NAME}"
if ! check_vsock_event "skipped"; then
set +x
diagnose "${NAME}"
ERROR ".ssh.overVsock=false did not disable vsock forwarder"
exit 1
fi
set +x
fi
fi
# Use GHCR and ECR to avoid hitting Docker Hub rate limit
nginx_image="ghcr.io/stargz-containers/nginx:1.19-alpine-org"
alpine_image="ghcr.io/containerd/alpine:3.14.0"
coredns_image="public.ecr.aws/eks-distro/coredns/coredns:v1.12.2-eks-1-31-latest"
if [[ -n ${CHECKS["container-engine"]} ]]; then
sudo=""
# Currently WSL2 machines only support privileged engine. This requirement might be lifted in the future.
if [[ "$(limactl ls "${NAME}" --yq .vmType)" == "wsl2" ]]; then
sudo="sudo"
fi
INFO "Run a nginx container with port forwarding 127.0.0.1:8080"
set -x
if ! limactl shell "$NAME" $sudo $CONTAINER_ENGINE info; then
limactl shell "$NAME" cat /var/log/cloud-init-output.log
ERROR "\"${CONTAINER_ENGINE} info\" failed"
exit 1
fi
limactl shell "$NAME" $sudo $CONTAINER_ENGINE pull --quiet ${nginx_image}
limactl shell "$NAME" $sudo $CONTAINER_ENGINE run -d --name nginx -p 127.0.0.1:8080:80 ${nginx_image}
timeout 3m bash -euxc "until curl -f --retry 30 --retry-connrefused http://127.0.0.1:8080; do sleep 3; done"
limactl shell "$NAME" $sudo $CONTAINER_ENGINE rm -f nginx
if [ "${OS_HOST}" != "Msys" ]; then
# TODO: support UDP on Windows
INFO "Run a coredns container with port forwarding 127.0.0.1:10053/udp"
limactl shell "$NAME" $sudo $CONTAINER_ENGINE pull --quiet ${coredns_image}
limactl shell "$NAME" $sudo $CONTAINER_ENGINE run -d --name coredns -p 127.0.0.1:10053:53/udp ${coredns_image}
dig @127.0.0.1 -p 10053 lima-vm.io
limactl shell "$NAME" $sudo $CONTAINER_ENGINE rm -f coredns
fi
set +x
if [[ -n ${CHECKS["mount-home"]} ]]; then
hometmp="$HOME_HOST/lima-container-engine-test-tmp"
hometmpguest="$HOME_GUEST/lima-container-engine-test-tmp"
# test for https://github.com/lima-vm/lima/issues/187
INFO "Testing home bind mount (\"$hometmp\")"
rm -rf "$hometmp"
mkdir -p "$hometmp"
defer "rm -rf \"$hometmp\""
set -x
limactl shell "$NAME" $sudo $CONTAINER_ENGINE pull --quiet ${alpine_image}
echo "random-content-${RANDOM}" >"$hometmp/random"
expected="$(cat "$hometmp/random")"
got="$(limactl shell "$NAME" $sudo $CONTAINER_ENGINE run --rm -v "$hometmpguest/random":/mnt/foo ${alpine_image} cat /mnt/foo)"
INFO "$hometmp/random: expected=${expected}, got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "Home directory is not shared?"
exit 1
fi
set +x
fi
fi
if [[ -n ${CHECKS["port-forwards"]} ]]; then
PORT_FORWARDING_CONNECTION_TIMEOUT=1
INFO "Testing port forwarding rules using netcat and socat with connection timeout ${PORT_FORWARDING_CONNECTION_TIMEOUT}s"
set -x
if [[ ${NAME} == "alpine"* ]]; then
limactl shell "${NAME}" sudo apk add socat
fi
if [[ ${NAME} == "archlinux" ]]; then
limactl shell "${NAME}" sudo pacman -Syu --noconfirm openbsd-netcat socat
fi
if [[ ${NAME} == "debian" || ${NAME} == "default" || ${NAME} == "docker" || ${NAME} == "test-misc" ]]; then
limactl shell "${NAME}" sudo apt-get install -y netcat-openbsd socat
fi
if [[ ${NAME} == "fedora" || ${NAME} == "wsl2" ]]; then
limactl shell "${NAME}" sudo dnf install -y nc socat
fi
if [[ ${NAME} == "opensuse" ]]; then
limactl shell "${NAME}" sudo zypper in -y netcat-openbsd socat
fi
if limactl shell "${NAME}" command -v dnf; then
limactl shell "${NAME}" sudo dnf install -y nc socat
fi
if "${scriptdir}/test-port-forwarding.pl" "${NAME}" socat $PORT_FORWARDING_CONNECTION_TIMEOUT; then
INFO "Port forwarding rules work"
else
ERROR "Port forwarding rules do not work with socat"
diagnose "$NAME"
exit 1
fi
if [[ -n ${CHECKS["container-engine"]} || ${NAME} == "alpine"* ]]; then
INFO "Testing that \"${CONTAINER_ENGINE} run\" binds to 0.0.0.0 and is forwarded to the host (non-default behavior, configured via test-port-forwarding.pl)"
if [ "$(uname)" = "Darwin" ]; then
# macOS runners seem to use `localhost` as the hostname, so the perl lookup just returns `127.0.0.1`
hostip=$(system_profiler SPNetworkDataType -json | jq -r 'first(.SPNetworkDataType[] | select(.ip_address) | .ip_address) | first')
else
hostip=$(perl -MSocket -MSys::Hostname -E 'say inet_ntoa(scalar gethostbyname(hostname()))')
fi
if [ -n "${hostip}" ]; then
sudo=""
if [[ ${NAME} == "alpine"* ]]; then
arch=$(limactl info | jq -r .defaultTemplate.arch)
nerdctl=$(limactl info | jq -r ".defaultTemplate.containerd.archives[] | select(.arch==\"$arch\").location")
curl -Lso nerdctl-full.tgz "${nerdctl}"
limactl shell "$NAME" sudo apk add containerd
limactl shell "$NAME" sudo rc-service containerd start
limactl shell "$NAME" sudo tar xzf "${PWD}/nerdctl-full.tgz" -C /usr/local
rm nerdctl-full.tgz
sudo="sudo"
fi
# Currently WSL2 machines only support privileged engine. This requirement might be lifted in the future.
if [[ "$(limactl ls "${NAME}" --yq .vmType)" == "wsl2" ]]; then
sudo="sudo"
fi
limactl shell "$NAME" $sudo $CONTAINER_ENGINE info
limactl shell "$NAME" $sudo $CONTAINER_ENGINE pull --quiet ${nginx_image}
limactl shell "$NAME" $sudo $CONTAINER_ENGINE run -d --name nginx -p 8888:80 ${nginx_image}
timeout 3m bash -euxc "until curl -f --retry 30 --retry-connrefused http://${hostip}:8888; do sleep 3; done"
limactl shell "$NAME" $sudo $CONTAINER_ENGINE rm -f nginx
if [ "$(uname)" = "Darwin" ]; then
# Only macOS can bind to port 80 without root
limactl shell "$NAME" $sudo $CONTAINER_ENGINE run -d --name nginx -p 127.0.0.1:80:80 ${nginx_image}
timeout 3m bash -euxc "until curl -f --retry 30 --retry-connrefused http://localhost:80; do sleep 3; done"
limactl shell "$NAME" $sudo $CONTAINER_ENGINE rm -f nginx
fi
fi
if [[ ${NAME} != "alpine"* ]] && command -v w3m >/dev/null; then
INFO "Testing https://github.com/lima-vm/lima/issues/3685 ([gRPC portfwd] client connection is not closed immediately when server closed the connection)"
# Skip the test on Alpine, as systemd-run is missing
# Skip the test on WSL2, as port forwarding is half broken https://github.com/lima-vm/lima/pull/3686#issuecomment-3034842616
limactl shell "$NAME" systemd-run --user python3 -m http.server 3685
# curl is not enough to reproduce https://github.com/lima-vm/lima/issues/3685
# `w3m -dump` exits with status code 0 even on "Can't load" error.
timeout 30s bash -euxc "until w3m -dump http://localhost:3685 | grep -v \"w3m: Can't load\"; do sleep 3; done"
fi
fi
set +x
fi
if [[ -n ${CHECKS["vmnet"]} ]]; then
INFO "Testing vmnet functionality"
guestip="$(limactl shell "$NAME" ip -4 -j addr show dev lima0 | jq -r '.[0].addr_info[0].local')"
INFO "Pinging the guest IP ${guestip}"
set -x
ping -c 3 "$guestip"
set +x
INFO "Benchmarking with iperf3"
set -x
limactl shell "$NAME" sudo DEBIAN_FRONTEND=noninteractive apt-get install -y iperf3
limactl shell "$NAME" iperf3 -s -1 -D
${IPERF3} -c "$guestip"
set +x
# NOTE: we only test the shared interface here, as the bridged interface cannot be used on GHA (and systemd-networkd-wait-online.service will fail)
fi
if [[ -n ${CHECKS["disk"]} ]]; then
INFO "Testing disk is attached"
set -x
if ! limactl shell "$NAME" lsblk --output NAME,MOUNTPOINT | grep -q "/mnt/lima-data"; then
ERROR "Disk is not mounted"
exit 1
fi
if ! limactl shell "$NAME" lsblk --output NAME,MOUNTPOINT | grep -q "\[SWAP\]"; then
ERROR "Disk is not mounted"
exit 1
fi
set +x
fi
if [[ -n ${CHECKS["restart"]} ]]; then
INFO "Create file in the guest home directory and verify that it still exists after a restart"
# shellcheck disable=SC2016
limactl shell "$NAME" sh -c 'touch $HOME/sweet-home'
if [[ -n ${CHECKS["disk"]} ]]; then
INFO "Create file in disk and verify that it still exists when it is reattached"
limactl shell "$NAME" sudo sh -c 'touch /mnt/lima-data/sweet-disk'
fi
INFO "Stopping \"$NAME\""
limactl stop "$NAME"
sleep 3
if [[ -n ${CHECKS["disk"]} ]]; then
INFO "Resize disk and verify that partition and fs size are increased"
limactl disk resize data --size 11G
fi
export ftp_proxy=my.proxy:8021
INFO "Restarting \"$NAME\""
if ! limactl start "$NAME"; then
ERROR "Failed to start \"$NAME\""
diagnose "$NAME"
exit 1
fi
INFO "Make sure proxy setting is updated"
got=$(limactl shell "$NAME" env | grep FTP_PROXY)
expected="FTP_PROXY=my.proxy:8021"
INFO "FTP_PROXY: expected=${expected} got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "proxy environment variable not set to correct value"
exit 1
fi
# shellcheck disable=SC2016
if ! limactl shell "$NAME" sh -c 'test -f $HOME/sweet-home'; then
ERROR "Guest home directory does not persist across restarts"
exit 1
fi
if [[ -n ${CHECKS["disk"]} ]]; then
if ! limactl shell "$NAME" sh -c 'test -f /mnt/lima-data/sweet-disk'; then
ERROR "Disk does not persist across restarts"
exit 1
fi
if ! limactl shell "$NAME" sh -c 'df -h /mnt/lima-data/ --output=size | grep -q 11G'; then
ERROR "Disk FS does not resized after restart"
exit 1
fi
fi
fi
if [[ -n ${CHECKS["user-v2"]} ]]; then
INFO "Testing user-v2 network"
secondvm="$NAME-1"
"${LIMACTL_CREATE[@]}" --set ".additionalDisks=null" "$FILE_HOST" --name "$secondvm"
if ! limactl start "$secondvm"; then
ERROR "Failed to start \"$secondvm\""
diagnose "$secondvm"
exit 1
fi
secondvmDNS="lima-$secondvm.internal"
INFO "DNS of $secondvm is $secondvmDNS"
set -x
if ! limactl shell "$NAME" ping -c 1 "$secondvmDNS"; then
ERROR "Failed to do vm->vm communication via user-v2"
INFO "Stopping \"$secondvm\""
limactl stop "$secondvm"
INFO "Deleting \"$secondvm\""
limactl delete "$secondvm"
exit 1
fi
INFO "Stopping \"$secondvm\""
limactl stop "$secondvm"
INFO "Deleting \"$secondvm\""
limactl delete "$secondvm"
set +x
fi
if [[ -n ${CHECKS["snapshot-online"]} ]]; then
INFO "Testing online snapshots"
limactl shell "$NAME" sh -c 'echo foo > /tmp/test'
limactl snapshot create "$NAME" --tag snap1
got=$(limactl snapshot list "$NAME" --quiet)
expected="snap1"
INFO "snapshot list: expected=${expected} got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "snapshot list did not return expected value"
exit 1
fi
limactl shell "$NAME" sh -c 'echo bar > /tmp/test'
limactl snapshot apply "$NAME" --tag snap1
got=$(limactl shell "$NAME" cat /tmp/test)
expected="foo"
INFO "snapshot apply: expected=${expected} got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "snapshot apply did not restore snapshot"
exit 1
fi
limactl snapshot delete "$NAME" --tag snap1
limactl shell "$NAME" rm /tmp/test
fi
if [[ -n ${CHECKS["snapshot-offline"]} ]]; then
INFO "Testing offline snapshots"
limactl stop "$NAME"
sleep 3
limactl snapshot create "$NAME" --tag snap2
got=$(limactl snapshot list "$NAME" --quiet)
expected="snap2"
INFO "snapshot list: expected=${expected} got=${got}"
if [ "$got" != "$expected" ]; then
ERROR "snapshot list did not return expected value"
exit 1
fi
limactl snapshot apply "$NAME" --tag snap2
limactl snapshot delete "$NAME" --tag snap2
limactl start "$NAME"
fi
if [[ -n ${CHECKS["clone"]} ]]; then
INFO "Testing cloning"
limactl stop "$NAME"
sleep 3
# [hostagent] could not attach disk \"data\", in use by instance \"test-misc-clone\"
limactl clone --set '.additionalDisks = null' "$NAME" "${NAME}-clone"
limactl start "${NAME}-clone"
[ "$(limactl shell "${NAME}-clone" hostname)" = "lima-${NAME}-clone" ]
limactl start "$NAME"
fi
if [[ $NAME == "fedora" && "$(limactl ls "${NAME}" --yq .vmType)" == "vz" ]]; then
"${scriptdir}"/test-selinux.sh "$NAME"
fi
INFO "Stopping \"$NAME\""
limactl stop "$NAME"
sleep 3
INFO "Deleting \"$NAME\""
limactl delete "$NAME"
if [[ -n ${CHECKS["mount-path-with-spaces"]} ]]; then
rm -rf "/tmp/lima test dir with spaces"
fi
if [[ -n ${CHECKS["static-port-forwards"]} ]]; then
INFO "Testing static port forwarding functionality"
"${scriptdir}/test-plain-static-port-forward.sh" "$NAME"
"${scriptdir}/test-nonplain-static-port-forward.sh" "$NAME"
INFO "All static port forwarding tests passed!"
fi