xref: /cloud-hypervisor/scripts/dev_cli.sh (revision 88a9f799449c04180c6b9a21d3b9c0c4b57e2bd6)
1#!/usr/bin/env bash
2
3# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4# Copyright © 2020 Intel Corporation
5# SPDX-License-Identifier: Apache-2.0
6
7CLI_NAME="Cloud Hypervisor"
8
9CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
10
11# Needs to match explicit version in docker-image.yaml workflow
12CTR_IMAGE_VERSION="20240507-0"
13: "${CTR_IMAGE:=${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}}"
14
15DOCKER_RUNTIME="docker"
16
17# Host paths
18CLH_SCRIPTS_DIR=$(cd "$(dirname "$0")" && pwd)
19CLH_ROOT_DIR=$(cd "${CLH_SCRIPTS_DIR}/.." && pwd)
20CLH_BUILD_DIR="${CLH_ROOT_DIR}/build"
21CLH_CARGO_TARGET="${CLH_BUILD_DIR}/cargo_target"
22CLH_DOCKERFILE="${CLH_SCRIPTS_DIR}/../resources/Dockerfile"
23CLH_CTR_BUILD_DIR="/tmp/cloud-hypervisor/ctr-build"
24CLH_INTEGRATION_WORKLOADS="${HOME}/workloads"
25
26# Container paths
27CTR_CLH_ROOT_DIR="/cloud-hypervisor"
28CTR_CLH_CARGO_BUILT_DIR="${CTR_CLH_ROOT_DIR}/build"
29CTR_CLH_CARGO_TARGET="${CTR_CLH_CARGO_BUILT_DIR}/cargo_target"
30CTR_CLH_INTEGRATION_WORKLOADS="/root/workloads"
31
32# Container networking option
33CTR_CLH_NET="bridge"
34
35# Cargo paths
36# Full path to the cargo registry dir on the host. This appears on the host
37# because we want to persist the cargo registry across container invocations.
38# Otherwise, any rust crates from crates.io would be downloaded again each time
39# we build or test.
40CARGO_REGISTRY_DIR="${CLH_BUILD_DIR}/cargo_registry"
41
42# Full path to the cargo git registry on the host. This serves the same purpose
43# as CARGO_REGISTRY_DIR, for crates downloaded from GitHub repos instead of
44# crates.io.
45CARGO_GIT_REGISTRY_DIR="${CLH_BUILD_DIR}/cargo_git_registry"
46
47# Full path to the cargo target dir on the host.
48CARGO_TARGET_DIR="${CLH_BUILD_DIR}/cargo_target"
49
50# Send a decorated message to stdout, followed by a new line
51#
52say() {
53    [ -t 1 ] && [ -n "$TERM" ] &&
54        echo "$(tput setaf 2)[$CLI_NAME]$(tput sgr0) $*" ||
55        echo "[$CLI_NAME] $*"
56}
57
58# Send a decorated message to stdout, without a trailing new line
59#
60say_noln() {
61    [ -t 1 ] && [ -n "$TERM" ] &&
62        echo -n "$(tput setaf 2)[$CLI_NAME]$(tput sgr0) $*" ||
63        echo "[$CLI_NAME] $*"
64}
65
66# Send a text message to stderr
67#
68say_err() {
69    [ -t 2 ] && [ -n "$TERM" ] &&
70        echo "$(tput setaf 1)[$CLI_NAME] $*$(tput sgr0)" 1>&2 ||
71        echo "[$CLI_NAME] $*" 1>&2
72}
73
74# Send a warning-highlighted text to stdout
75say_warn() {
76    [ -t 1 ] && [ -n "$TERM" ] &&
77        echo "$(tput setaf 3)[$CLI_NAME] $*$(tput sgr0)" ||
78        echo "[$CLI_NAME] $*"
79}
80
81# Exit with an error message and (optional) code
82# Usage: die [-c <error code>] <error message>
83#
84die() {
85    code=1
86    [[ "$1" = "-c" ]] && {
87        code="$2"
88        shift 2
89    }
90    say_err "$@"
91    exit "$code"
92}
93
94# Exit with an error message if the last exit code is not 0
95#
96ok_or_die() {
97    code=$?
98    [[ $code -eq 0 ]] || die -c $code "$@"
99}
100
101# Make sure the build/ dirs are available. Exit if we can't create them.
102# Upon returning from this call, the caller can be certain the build/ dirs exist.
103#
104ensure_build_dir() {
105    for dir in "$CLH_BUILD_DIR" \
106        "$CLH_INTEGRATION_WORKLOADS" \
107        "$CLH_CTR_BUILD_DIR" \
108        "$CARGO_TARGET_DIR" \
109        "$CARGO_REGISTRY_DIR" \
110        "$CARGO_GIT_REGISTRY_DIR"; do
111        mkdir -p "$dir" || die "Error: cannot create dir $dir"
112        [ -x "$dir" ] && [ -w "$dir" ] ||
113            {
114                say "Wrong permissions for $dir. Attempting to fix them ..."
115                chmod +x+w "$dir"
116            } ||
117            die "Error: wrong permissions for $dir. Should be +x+w"
118    done
119}
120
121# Make sure we're using the latest dev container, by just pulling it.
122ensure_latest_ctr() {
123    if [ "$CTR_IMAGE_VERSION" = "local" ]; then
124        build_container
125    else
126        if ! $DOCKER_RUNTIME pull "$CTR_IMAGE"; then
127            build_container
128        fi
129
130        ok_or_die "Error pulling/building container image. Aborting."
131    fi
132}
133
134# Fix main directory permissions after a container ran as root.
135# Since the container ran as root, any files it creates will be owned by root.
136# This fixes that by recursively changing the ownership of /cloud-hypervisor to the
137# current user.
138#
139fix_dir_perms() {
140    # Yes, running Docker to get elevated privileges, just to chown some files
141    # is a dirty hack.
142    $DOCKER_RUNTIME run \
143        --workdir "$CTR_CLH_ROOT_DIR" \
144        --rm \
145        --volume /dev:/dev \
146        --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
147        ${exported_volumes:+"$exported_volumes"} \
148        "$CTR_IMAGE" \
149        chown -R "$(id -u):$(id -g)" "$CTR_CLH_ROOT_DIR"
150
151    return "$1"
152}
153# Process exported volumes argument, separate the volumes and make docker compatible
154# Sample input: --volumes /a:/a#/b:/b
155# Sample output: --volume /a:/a --volume /b:/b
156#
157process_volumes_args() {
158    if [ -z "$arg_vols" ]; then
159        return
160    fi
161    exported_volumes=""
162    arr_vols=("${arg_vols//#/ }")
163    for var in "${arr_vols[@]}"; do
164        parts=("${var//:/ }")
165        if [[ ! -e "${parts[0]}" ]]; then
166            echo "The volume ${parts[0]} does not exist."
167            exit 1
168        fi
169        exported_volumes="$exported_volumes --volume $var"
170    done
171}
172
173cmd_help() {
174    echo ""
175    echo "Cloud Hypervisor $(basename "$0")"
176    echo "Usage: $(basename "$0") [flags] <command> [<command args>]"
177    echo ""
178    echo "Available flags":
179    echo ""
180    echo "    --local        Set the container image version being used to \"local\"."
181    echo ""
182    echo "Available commands:"
183    echo ""
184    echo "    build [--debug|--release] [--libc musl|gnu] [-- [<cargo args>]]"
185    echo "        Build the Cloud Hypervisor binaries."
186    echo "        --debug               Build the debug binaries. This is the default."
187    echo "        --release             Build the release binaries."
188    echo "        --libc                Select the C library Cloud Hypervisor will be built against. Default is gnu"
189    echo "        --volumes             Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
190    echo "        --hypervisor          Underlying hypervisor. Options kvm, mshv"
191    echo ""
192    echo "    tests [<test type (see below)>] [--libc musl|gnu] [-- [<test scripts args>] [-- [<test binary args>]]] "
193    echo "        Run the Cloud Hypervisor tests."
194    echo "        --unit                       Run the unit tests."
195    echo "        --integration                Run the integration tests."
196    echo "        --integration-sgx            Run the SGX integration tests."
197    echo "        --integration-vfio           Run the VFIO integration tests."
198    echo "        --integration-windows        Run the Windows guest integration tests."
199    echo "        --integration-live-migration Run the live-migration integration tests."
200    echo "        --integration-rate-limiter   Run the rate-limiter integration tests."
201    echo "        --libc                       Select the C library Cloud Hypervisor will be built against. Default is gnu"
202    echo "        --metrics                    Generate performance metrics"
203    echo "        --coverage                   Generate code coverage information"
204    echo "        --volumes                    Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
205    echo "        --hypervisor                 Underlying hypervisor. Options kvm, mshv"
206    echo "        --all                        Run all tests."
207    echo ""
208    echo "    build-container [--type]"
209    echo "        Build the Cloud Hypervisor container."
210    echo ""
211    echo "    clean [<cargo args>]]"
212    echo "        Remove the Cloud Hypervisor artifacts."
213    echo ""
214    echo "    shell"
215    echo "        Run the development container into an interactive, privileged BASH shell."
216    echo "        --volumes             Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
217    echo ""
218    echo "    help"
219    echo "        Display this help message."
220    echo ""
221}
222
223cmd_build() {
224    build="debug"
225    libc="gnu"
226    hypervisor="kvm"
227    features_build=()
228    exported_device="/dev/kvm"
229    while [ $# -gt 0 ]; do
230        case "$1" in
231        "-h" | "--help") {
232            cmd_help
233            exit 1
234        } ;;
235        "--debug") { build="debug"; } ;;
236        "--release") { build="release"; } ;;
237        "--runtime")
238            shift
239            DOCKER_RUNTIME="$1"
240            export DOCKER_RUNTIME
241            ;;
242        "--libc")
243            shift
244            [[ "$1" =~ ^(musl|gnu)$ ]] ||
245                die "Invalid libc: $1. Valid options are \"musl\" and \"gnu\"."
246            libc="$1"
247            ;;
248        "--volumes")
249            shift
250            arg_vols="$1"
251            ;;
252        "--hypervisor")
253            shift
254            hypervisor="$1"
255            ;;
256        "--features")
257            shift
258            features_build=(--features "$1")
259            ;;
260        "--") {
261            shift
262            break
263        } ;;
264        *)
265            die "Unknown build argument: $1. Please use --help for help."
266            ;;
267        esac
268        shift
269    done
270
271    ensure_build_dir
272    ensure_latest_ctr
273
274    process_volumes_args
275    if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
276        die "Hypervisor value must be kvm or mshv"
277    fi
278    if [[ "$hypervisor" = "mshv" ]]; then
279        exported_device="/dev/mshv"
280    fi
281    target="$(uname -m)-unknown-linux-${libc}"
282
283    cargo_args=("$@")
284    [ $build = "release" ] && cargo_args+=("--release")
285    cargo_args+=(--target "$target")
286
287    # shellcheck disable=SC2153
288    rustflags="$RUSTFLAGS"
289    target_cc=""
290    if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
291        rustflags="$rustflags -C link-args=-Wl,-Bstatic -C link-args=-lc"
292    fi
293
294    $DOCKER_RUNTIME run \
295        --user "$(id -u):$(id -g)" \
296        --workdir "$CTR_CLH_ROOT_DIR" \
297        --rm \
298        --volume $exported_device \
299        --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
300        ${exported_volumes:+"$exported_volumes"} \
301        --env RUSTFLAGS="$rustflags" \
302        --env TARGET_CC="$target_cc" \
303        "$CTR_IMAGE" \
304        cargo build --all "${features_build[@]}" \
305        --target-dir "$CTR_CLH_CARGO_TARGET" \
306        "${cargo_args[@]}" && say "Binaries placed under $CLH_CARGO_TARGET/$target/$build"
307}
308
309cmd_clean() {
310    cargo_args=("$@")
311
312    ensure_build_dir
313    ensure_latest_ctr
314
315    $DOCKER_RUNTIME run \
316        --user "$(id -u):$(id -g)" \
317        --workdir "$CTR_CLH_ROOT_DIR" \
318        --rm \
319        --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
320        ${exported_volumes:+"$exported_volumes"} \
321        "$CTR_IMAGE" \
322        cargo clean \
323        --target-dir "$CTR_CLH_CARGO_TARGET" \
324        "${cargo_args[@]}"
325}
326
327cmd_tests() {
328    unit=false
329    integration=false
330    integration_sgx=false
331    integration_vfio=false
332    integration_windows=false
333    integration_live_migration=false
334    integration_rate_limiter=false
335    metrics=false
336    coverage=false
337    libc="gnu"
338    arg_vols=""
339    hypervisor="kvm"
340    exported_device="/dev/kvm"
341    while [ $# -gt 0 ]; do
342        case "$1" in
343        "-h" | "--help") {
344            cmd_help
345            exit 1
346        } ;;
347        "--unit") { unit=true; } ;;
348        "--integration") { integration=true; } ;;
349        "--integration-sgx") { integration_sgx=true; } ;;
350        "--integration-vfio") { integration_vfio=true; } ;;
351        "--integration-windows") { integration_windows=true; } ;;
352        "--integration-live-migration") { integration_live_migration=true; } ;;
353        "--integration-rate-limiter") { integration_rate_limiter=true; } ;;
354        "--metrics") { metrics=true; } ;;
355        "--coverage") { coverage=true; } ;;
356        "--libc")
357            shift
358            [[ "$1" =~ ^(musl|gnu)$ ]] ||
359                die "Invalid libc: $1. Valid options are \"musl\" and \"gnu\"."
360            libc="$1"
361            ;;
362        "--volumes")
363            shift
364            arg_vols="$1"
365            ;;
366        "--hypervisor")
367            shift
368            hypervisor="$1"
369            ;;
370        "--all") {
371            unit=true
372            integration=true
373        } ;;
374        "--") {
375            shift
376            break
377        } ;;
378        *)
379            die "Unknown tests argument: $1. Please use --help for help."
380            ;;
381        esac
382        shift
383    done
384    if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
385        die "Hypervisor value must be kvm or mshv"
386    fi
387
388    if [[ "$hypervisor" = "mshv" ]]; then
389        exported_device="/dev/mshv"
390    fi
391
392    if [ ! -e "${exported_device}" ]; then
393        die "${exported_device} does not exist on the system"
394    fi
395
396    set -- '--hypervisor' "$hypervisor" "$@"
397
398    ensure_build_dir
399    ensure_latest_ctr
400
401    process_volumes_args
402    target="$(uname -m)-unknown-linux-${libc}"
403
404    rustflags="$RUSTFLAGS"
405    target_cc=""
406    if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
407        rustflags="$rustflags -C link-args=-Wl,-Bstatic -C link-args=-lc"
408    fi
409
410    if [[ "$unit" = true ]]; then
411        say "Running unit tests for $target..."
412        $DOCKER_RUNTIME run \
413            --workdir "$CTR_CLH_ROOT_DIR" \
414            --rm \
415            --device $exported_device \
416            --device /dev/net/tun \
417            --cap-add net_admin \
418            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
419            ${exported_volumes:+"$exported_volumes"} \
420            --env BUILD_TARGET="$target" \
421            --env RUSTFLAGS="$rustflags" \
422            --env TARGET_CC="$target_cc" \
423            --env LLVM_PROFILE_FILE="$LLVM_PROFILE_FILE" \
424            "$CTR_IMAGE" \
425            ./scripts/run_unit_tests.sh "$@" || fix_dir_perms $? || exit $?
426    fi
427
428    if [ "$integration" = true ]; then
429        say "Running integration tests for $target..."
430        $DOCKER_RUNTIME run \
431            --workdir "$CTR_CLH_ROOT_DIR" \
432            --rm \
433            --privileged \
434            --security-opt seccomp=unconfined \
435            --ipc=host \
436            --net="$CTR_CLH_NET" \
437            --mount type=tmpfs,destination=/tmp \
438            --volume /dev:/dev \
439            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
440            ${exported_volumes:+"$exported_volumes"} \
441            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
442            --env USER="root" \
443            --env BUILD_TARGET="$target" \
444            --env RUSTFLAGS="$rustflags" \
445            --env TARGET_CC="$target_cc" \
446            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
447            --env LLVM_PROFILE_FILE="$LLVM_PROFILE_FILE" \
448            "$CTR_IMAGE" \
449            dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
450    fi
451
452    if [ "$integration_sgx" = true ]; then
453        say "Running SGX integration tests for $target..."
454        $DOCKER_RUNTIME run \
455            --workdir "$CTR_CLH_ROOT_DIR" \
456            --rm \
457            --privileged \
458            --security-opt seccomp=unconfined \
459            --ipc=host \
460            --net="$CTR_CLH_NET" \
461            --mount type=tmpfs,destination=/tmp \
462            --volume /dev:/dev \
463            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
464            ${exported_volumes:+"$exported_volumes"} \
465            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
466            --env USER="root" \
467            --env BUILD_TARGET="$target" \
468            --env RUSTFLAGS="$rustflags" \
469            --env TARGET_CC="$target_cc" \
470            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
471            "$CTR_IMAGE" \
472            ./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $?
473    fi
474
475    if [ "$integration_vfio" = true ]; then
476        say "Running VFIO integration tests for $target..."
477        $DOCKER_RUNTIME run \
478            --workdir "$CTR_CLH_ROOT_DIR" \
479            --rm \
480            --privileged \
481            --security-opt seccomp=unconfined \
482            --ipc=host \
483            --net="$CTR_CLH_NET" \
484            --mount type=tmpfs,destination=/tmp \
485            --volume /dev:/dev \
486            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
487            ${exported_volumes:+"$exported_volumes"} \
488            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
489            --env USER="root" \
490            --env BUILD_TARGET="$target" \
491            --env RUSTFLAGS="$rustflags" \
492            --env TARGET_CC="$target_cc" \
493            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
494            "$CTR_IMAGE" \
495            ./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $?
496    fi
497
498    if [ "$integration_windows" = true ]; then
499        say "Running Windows integration tests for $target..."
500        $DOCKER_RUNTIME run \
501            --workdir "$CTR_CLH_ROOT_DIR" \
502            --rm \
503            --privileged \
504            --security-opt seccomp=unconfined \
505            --ipc=host \
506            --net="$CTR_CLH_NET" \
507            --mount type=tmpfs,destination=/tmp \
508            --volume /dev:/dev \
509            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
510            ${exported_volumes:+"$exported_volumes"} \
511            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
512            --env USER="root" \
513            --env BUILD_TARGET="$target" \
514            --env RUSTFLAGS="$rustflags" \
515            --env TARGET_CC="$target_cc" \
516            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
517            "$CTR_IMAGE" \
518            ./scripts/run_integration_tests_windows_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
519    fi
520
521    if [ "$integration_live_migration" = true ]; then
522        say "Running 'live migration' integration tests for $target..."
523        $DOCKER_RUNTIME run \
524            --workdir "$CTR_CLH_ROOT_DIR" \
525            --rm \
526            --privileged \
527            --security-opt seccomp=unconfined \
528            --ipc=host \
529            --net="$CTR_CLH_NET" \
530            --mount type=tmpfs,destination=/tmp \
531            --volume /dev:/dev \
532            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
533            ${exported_volumes:+"$exported_volumes"} \
534            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
535            --env USER="root" \
536            --env BUILD_TARGET="$target" \
537            --env RUSTFLAGS="$rustflags" \
538            --env TARGET_CC="$target_cc" \
539            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
540            --env LLVM_PROFILE_FILE="$LLVM_PROFILE_FILE" \
541            "$CTR_IMAGE" \
542            ./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
543    fi
544
545    if [ "$integration_rate_limiter" = true ]; then
546        say "Running 'rate limiter' integration tests for $target..."
547        $DOCKER_RUNTIME run \
548            --workdir "$CTR_CLH_ROOT_DIR" \
549            --rm \
550            --privileged \
551            --security-opt seccomp=unconfined \
552            --ipc=host \
553            --net="$CTR_CLH_NET" \
554            --mount type=tmpfs,destination=/tmp \
555            --volume /dev:/dev \
556            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
557            ${exported_volumes:+"$exported_volumes"} \
558            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
559            --env USER="root" \
560            --env BUILD_TARGET="$target" \
561            --env RUSTFLAGS="$rustflags" \
562            --env TARGET_CC="$target_cc" \
563            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
564            "$CTR_IMAGE" \
565            ./scripts/run_integration_tests_rate_limiter.sh "$@" || fix_dir_perms $? || exit $?
566    fi
567
568    if [ "$metrics" = true ]; then
569        say "Generating performance metrics for $target..."
570        $DOCKER_RUNTIME run \
571            --workdir "$CTR_CLH_ROOT_DIR" \
572            --rm \
573            --privileged \
574            --security-opt seccomp=unconfined \
575            --ipc=host \
576            --net="$CTR_CLH_NET" \
577            --mount type=tmpfs,destination=/tmp \
578            --volume /dev:/dev \
579            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
580            ${exported_volumes:+"$exported_volumes"} \
581            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
582            --env USER="root" \
583            --env BUILD_TARGET="$target" \
584            --env RUSTFLAGS="$rustflags" \
585            --env TARGET_CC="$target_cc" \
586            --env RUST_BACKTRACE="${RUST_BACKTRACE}" \
587            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
588            "$CTR_IMAGE" \
589            ./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
590    fi
591
592    if [ "$coverage" = true ]; then
593        say "Generating code coverage information for $target..."
594        $DOCKER_RUNTIME run \
595            --workdir "$CTR_CLH_ROOT_DIR" \
596            --rm \
597            --privileged \
598            --security-opt seccomp=unconfined \
599            --ipc=host \
600            --net="$CTR_CLH_NET" \
601            --mount type=tmpfs,destination=/tmp \
602            --volume /dev:/dev \
603            --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
604            ${exported_volumes:+"$exported_volumes"} \
605            --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
606            --env USER="root" \
607            --env BUILD_TARGET="$target" \
608            --env RUSTFLAGS="$rustflags" \
609            --env TARGET_CC="$target_cc" \
610            --env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
611            "$CTR_IMAGE" \
612            dbus-run-session ./scripts/run_coverage.sh "$@" || fix_dir_perms $? || exit $?
613    fi
614
615    fix_dir_perms $?
616}
617
618build_container() {
619    ensure_build_dir
620
621    BUILD_DIR=/tmp/cloud-hypervisor/container/
622
623    mkdir -p $BUILD_DIR
624    cp "$CLH_DOCKERFILE" $BUILD_DIR
625
626    [ "$(uname -m)" = "aarch64" ] && TARGETARCH="arm64"
627    [ "$(uname -m)" = "x86_64" ] && TARGETARCH="amd64"
628
629    $DOCKER_RUNTIME build \
630        --target dev \
631        -t "$CTR_IMAGE" \
632        -f $BUILD_DIR/Dockerfile \
633        --build-arg TARGETARCH="$TARGETARCH" \
634        $BUILD_DIR
635}
636
637cmd_build-container() {
638    while [ $# -gt 0 ]; do
639        case "$1" in
640        "-h" | "--help") {
641            cmd_help
642            exit 1
643        } ;;
644        "--") {
645            shift
646            break
647        } ;;
648        *)
649            die "Unknown build-container argument: $1. Please use --help for help."
650            ;;
651        esac
652        shift
653    done
654
655    build_container
656}
657
658cmd_shell() {
659    while [ $# -gt 0 ]; do
660        case "$1" in
661        "-h" | "--help") {
662            cmd_help
663            exit 1
664        } ;;
665        "--volumes")
666            shift
667            arg_vols="$1"
668            ;;
669        "--") {
670            shift
671            break
672        } ;;
673        *) ;;
674
675        esac
676        shift
677    done
678    ensure_build_dir
679    ensure_latest_ctr
680    process_volumes_args
681    say_warn "Starting a privileged shell prompt as root ..."
682    say_warn "WARNING: Your $CLH_ROOT_DIR folder will be bind-mounted in the container under $CTR_CLH_ROOT_DIR"
683    $DOCKER_RUNTIME run \
684        -ti \
685        --workdir "$CTR_CLH_ROOT_DIR" \
686        --rm \
687        --privileged \
688        --security-opt seccomp=unconfined \
689        --ipc=host \
690        --net="$CTR_CLH_NET" \
691        --tmpfs /tmp:exec \
692        --volume /dev:/dev \
693        --volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
694        ${exported_volumes:+"$exported_volumes"} \
695        --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
696        --env USER="root" \
697        --entrypoint bash \
698        "$CTR_IMAGE"
699
700    fix_dir_perms $?
701}
702
703if [ $# = 0 ]; then
704    cmd_help
705    say_err "Please specify command to run!"
706    exit 1
707fi
708
709# Parse main command line args.
710#
711while [ $# -gt 0 ]; do
712    case "$1" in
713    -h | --help) {
714        cmd_help
715        exit 1
716    } ;;
717    --local) {
718        CTR_IMAGE_VERSION="local"
719        CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
720    } ;;
721    -*)
722        die "Unknown arg: $1. Please use \`$0 help\` for help."
723        ;;
724    *)
725        break
726        ;;
727    esac
728    shift
729done
730
731# $1 is now a command name. Check if it is a valid command and, if so,
732# run it.
733#
734declare -f "cmd_$1" >/dev/null
735ok_or_die "Unknown command: $1. Please use \`$0 help\` for help."
736
737cmd=cmd_$1
738shift
739
740$cmd "$@"
741