2022-02-16 22:18:46 +00:00
|
|
|
#!/usr/bin/env python3
|
2021-10-13 23:40:53 +00:00
|
|
|
# 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.
|
2021-11-17 22:39:52 +00:00
|
|
|
#
|
|
|
|
# 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
|
2021-10-13 23:40:53 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
import argparse
|
|
|
|
import getpass
|
2022-03-22 20:04:31 +00:00
|
|
|
from argh import arg # type: ignore
|
2022-02-16 22:18:46 +00:00
|
|
|
from impl.common import CROSVM_ROOT, run_main, cmd, chdir, quoted
|
|
|
|
import sys
|
|
|
|
import os
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
CONTAINER_NAME = f"crosvm_dev_{getpass.getuser()}"
|
|
|
|
IMAGE_VERSION = (CROSVM_ROOT / "tools/impl/dev_container/version").read_text().strip()
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
try:
|
|
|
|
docker = cmd(os.environ.get("DOCKER", "docker"))
|
|
|
|
except ValueError:
|
|
|
|
docker = cmd("podman")
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
is_podman = docker.executable.name == "podman"
|
2021-10-13 23:40:53 +00:00
|
|
|
|
|
|
|
# Enable interactive mode when running in an interactive terminal.
|
2022-02-16 22:18:46 +00:00
|
|
|
TTY_ARGS = "--interactive --tty" if sys.stdin.isatty() else None
|
2021-10-13 23:40:53 +00:00
|
|
|
|
2021-11-18 12:20:40 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
DOCKER_ARGS = [
|
|
|
|
TTY_ARGS,
|
|
|
|
# Podman will not share devices when `--privileged` is specified
|
|
|
|
"--privileged" if not is_podman else None,
|
|
|
|
# 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",
|
2022-03-10 00:00:43 +00:00
|
|
|
# For plugin process jail
|
|
|
|
"--mount type=tmpfs,destination=/var/empty",
|
2022-02-16 22:18:46 +00:00
|
|
|
f"gcr.io/crosvm-packages/crosvm_dev:{IMAGE_VERSION}",
|
|
|
|
]
|
2021-11-17 22:39:52 +00:00
|
|
|
|
|
|
|
|
2022-02-16 22:31:27 +00:00
|
|
|
def container_revision(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]
|
|
|
|
|
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
@arg("command", nargs=argparse.REMAINDER)
|
|
|
|
def main(command: tuple[str, ...], stop: bool = False, hermetic: bool = False):
|
|
|
|
chdir(CROSVM_ROOT)
|
|
|
|
container_id = docker(f"ps -q -f name={CONTAINER_NAME}").stdout()
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
# Start an interactive shell by default
|
|
|
|
if not command:
|
|
|
|
command = ("/bin/bash",)
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-03-22 20:04:31 +00:00
|
|
|
quoted_cmd = list(map(quoted, command))
|
2022-03-01 22:09:54 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
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
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
if hermetic:
|
2022-03-22 20:04:31 +00:00
|
|
|
docker(f"run --rm", *DOCKER_ARGS, *quoted_cmd).fg()
|
2022-02-16 22:18:46 +00:00
|
|
|
else:
|
2022-02-16 22:31:27 +00:00
|
|
|
if container_id and container_revision(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
|
|
|
|
|
2022-02-16 22:18:46 +00:00
|
|
|
if not container_id:
|
|
|
|
container_id = docker(f"run --detach --name {CONTAINER_NAME}", *DOCKER_ARGS).stdout()
|
|
|
|
print(f"Started dev-container ({container_id}).")
|
|
|
|
else:
|
|
|
|
print(f"Using existing dev-container instance ({container_id}).")
|
2021-11-17 22:39:52 +00:00
|
|
|
|
2022-03-22 20:04:31 +00:00
|
|
|
docker("exec", TTY_ARGS, container_id, *quoted_cmd).fg()
|
2021-11-03 15:49:17 +00:00
|
|
|
|
2021-10-13 23:40:53 +00:00
|
|
|
|
2022-03-22 20:04:31 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
run_main(main)
|