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