mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-06 02:25:23 +00:00
69daee101e
This script is naturally used outside of the container and we want to avoid having to install dependencies or special python versions to run it. This CL reduces the python requirement from 3.9 to 3.8 and allows the script to run without any dependencies. BUG=b:233230344 TEST=pyenv global 3.8.15 ./tools/dev_container Change-Id: Ieeb868f7fb275a8e6e39e577b5e984895307765e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3657816 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Anton Romanov <romanton@google.com>
150 lines
5.2 KiB
Python
Executable file
150 lines
5.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright 2021 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
#
|
|
# Usage:
|
|
#
|
|
# To get an interactive shell for development:
|
|
# ./tools/dev_container
|
|
#
|
|
# To run a command in the container, e.g. to run presubmits:
|
|
# ./tools/dev_container ./tools/presubmit
|
|
#
|
|
# The state of the container (including build artifacts) are preserved between
|
|
# calls. To stop the container call:
|
|
# ./tools/dev_container --stop
|
|
#
|
|
# The dev container can also be called with a fresh container for each call that
|
|
# is cleaned up afterwards (e.g. when run by Kokoro):
|
|
#
|
|
# ./tools/dev_container --hermetic CMD
|
|
|
|
import argparse
|
|
import getpass
|
|
import shutil
|
|
from typing import Tuple
|
|
from impl.common import CROSVM_ROOT, cmd, chdir, quoted
|
|
import sys
|
|
|
|
CONTAINER_NAME = f"crosvm_dev_{getpass.getuser()}"
|
|
IMAGE_VERSION = (CROSVM_ROOT / "tools/impl/dev_container/version").read_text().strip()
|
|
|
|
DOCKER_ARGS = [
|
|
# Share crosvm source
|
|
f"--volume {quoted(CROSVM_ROOT)}:/workspace:rw",
|
|
# Share devices and syslog
|
|
"--device /dev/kvm",
|
|
"--volume /dev/log:/dev/log",
|
|
"--device /dev/net/tun",
|
|
"--device /dev/vhost-net",
|
|
"--device /dev/vhost-vsock",
|
|
# Use tmpfs in the container for faster performance.
|
|
"--mount type=tmpfs,destination=/tmp",
|
|
# For plugin process jail
|
|
"--mount type=tmpfs,destination=/var/empty",
|
|
f"gcr.io/crosvm-packages/crosvm_dev:{IMAGE_VERSION}",
|
|
]
|
|
|
|
PODMAN_IS_DEFAULT = shutil.which("docker") == None
|
|
|
|
|
|
def container_revision(docker: cmd, container_id: str):
|
|
image = docker("container inspect -f {{.Config.Image}}", container_id).stdout()
|
|
parts = image.split(":")
|
|
assert len(parts) == 2, f"Invalid image name {image}"
|
|
return parts[1]
|
|
|
|
|
|
def main(
|
|
command: Tuple[str, ...],
|
|
stop: bool = False,
|
|
hermetic: bool = False,
|
|
interactive: bool = False,
|
|
podman: bool = PODMAN_IS_DEFAULT,
|
|
):
|
|
chdir(CROSVM_ROOT)
|
|
|
|
docker = cmd("podman" if podman else "docker")
|
|
docker_args = [
|
|
# Podman will not share devices when `--privileged` is specified
|
|
"--privileged" if not podman else None,
|
|
*DOCKER_ARGS,
|
|
]
|
|
|
|
if podman:
|
|
print("WARNING: Running dev_container with podman is not fully supported.")
|
|
print("Some crosvm tests require privileges podman cannot provide and may fail.")
|
|
print()
|
|
|
|
container_id = docker(f"ps -a -q -f name={CONTAINER_NAME}").stdout()
|
|
|
|
# If a command is provided run non-interactive unless explicitly asked for.
|
|
tty_args = []
|
|
if not command or interactive:
|
|
if not sys.stdin.isatty():
|
|
raise Exception("Trying to run an interactive session in a non-interactive terminal.")
|
|
tty_args = ["--interactive", "--tty"]
|
|
|
|
# Start an interactive shell by default
|
|
if not command:
|
|
command = ("/bin/bash",)
|
|
|
|
quoted_cmd = list(map(quoted, command))
|
|
|
|
if stop:
|
|
if container_id:
|
|
print(f"Stopping dev-container {container_id}.")
|
|
docker("rm -f", container_id).fg(quiet=True)
|
|
else:
|
|
print(f"Dev-container is not running.")
|
|
return
|
|
|
|
if hermetic:
|
|
docker(f"run --rm", *tty_args, *docker_args, *quoted_cmd).fg()
|
|
else:
|
|
if container_id and container_revision(docker, container_id) != IMAGE_VERSION:
|
|
print(f"New image is available. Stopping old container ({container_id}).")
|
|
docker("rm -f", container_id).fg(quiet=True)
|
|
container_id = None
|
|
|
|
if not container_id:
|
|
container_id = docker(
|
|
f"run --detach --name {CONTAINER_NAME}", *tty_args, *docker_args
|
|
).stdout()
|
|
print(f"Started dev-container ({container_id}).")
|
|
else:
|
|
is_running = docker(f"ps -q -f name={CONTAINER_NAME}").stdout()
|
|
if not is_running:
|
|
# The container may have been stopped (e.g. by a reboot)
|
|
print(f"Starting existing dev-container ({container_id}).")
|
|
docker("start", container_id).fg()
|
|
print(f"Using existing dev-container instance ({container_id}).")
|
|
|
|
docker("exec", *tty_args, container_id, *quoted_cmd).fg()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Note: Since the dev_container script is run outside of the container, we do not want to
|
|
# use common.run_main/argh here, so we can use this script without installing any
|
|
# dependencies. All that's needed is python >= 3.8.
|
|
parser = argparse.ArgumentParser(description="Runs the crosvm dev container.")
|
|
parser.add_argument("--stop", action="store_true", help="Stop the container if it's running.")
|
|
parser.add_argument(
|
|
"--hermetic", action="store_true", help="Do not re-use an existing container."
|
|
)
|
|
parser.add_argument(
|
|
"--interactive", "-i", action="store_true", help="Run the command interactively."
|
|
)
|
|
parser.add_argument("--podman", action="store_true", help="Use podman instead of docker.")
|
|
parser.add_argument(
|
|
"command", nargs=argparse.REMAINDER, help="The command to execute in the container."
|
|
)
|
|
args = parser.parse_args()
|
|
main(
|
|
args.command,
|
|
stop=args.stop,
|
|
hermetic=args.hermetic,
|
|
interactive=args.interactive,
|
|
podman=args.podman,
|
|
)
|