From 483345c4c02e0b2fa68e40da77361df89d5319e6 Mon Sep 17 00:00:00 2001 From: Zihan Chen Date: Fri, 5 Aug 2022 13:41:33 -0700 Subject: [PATCH] dev_container: Use host UID & GID for user in container Container shell now defaults to user `crosvmdev` which will have same UID & GID as outside user. VS Code Remote Containers extension has the same behavior when loading config from devcontainer.json. TEST=all tests pass in container, new files in container have same permission as files created outside. FIXED=b:239476013 Change-Id: Ib3c696509e9ea45edd5f02ff025d9477576ec765 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3814094 Auto-Submit: Zihan Chen Reviewed-by: Dennis Kempin Tested-by: Zihan Chen Commit-Queue: Dennis Kempin --- .devcontainer/devcontainer.json | 8 +++- integration_tests/tests/block.rs | 3 +- tools/dev_container | 14 +++++-- tools/impl/dev_container/Dockerfile | 55 +++++++++++++++++--------- tools/impl/dev_container/entrypoint.sh | 17 ++++++++ tools/impl/dev_container/setup-user.sh | 18 +++++++++ tools/impl/dev_container/version | 2 +- 7 files changed, 90 insertions(+), 27 deletions(-) create mode 100755 tools/impl/dev_container/entrypoint.sh create mode 100644 tools/impl/dev_container/setup-user.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4a3de11d7c..23e0debab7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "image": "gcr.io/crosvm-infra/crosvm_dev:r0015", + "image": "gcr.io/crosvm-infra/crosvm_dev:r0019", "extensions": [ "rust-lang.rust-analyzer", "bungcip.better-toml", @@ -16,5 +16,9 @@ "--device=/dev/vhost-net", "--device=/dev/vhost-vsock", "--mount=type=tmpfs,destination=/tmp", - ] + "--mount=type=tmpfs,destination=/var/empty", + ], + "containerUser": "crosvmdev", + "updateContentCommand": "sudo chown -R --reference=/workspaces/crosvm /home/crosvmdev", + "postCreateCommand": "sudo chmod 666 /dev/kvm", } diff --git a/integration_tests/tests/block.rs b/integration_tests/tests/block.rs index 4dcf0ac83d..937ba39c17 100644 --- a/integration_tests/tests/block.rs +++ b/integration_tests/tests/block.rs @@ -17,7 +17,8 @@ fn prepare_disk_img() -> NamedTempFile { disk.as_file_mut().set_len(1024 * 1024).unwrap(); // TODO(b/243127910): Use `mkfs.ext4 -d` to include test data. - Command::new("mkfs.ext4") + Command::new("sudo") + .arg("mkfs.ext4") .arg(disk.path().to_str().unwrap()) .output() .expect("failed to execute process"); diff --git a/tools/dev_container b/tools/dev_container index ccad594e7e..2e972ef166 100755 --- a/tools/dev_container +++ b/tools/dev_container @@ -50,6 +50,8 @@ DOCKER_ARGS = [ "--mount type=tmpfs,destination=/tmp", # For plugin process jail "--mount type=tmpfs,destination=/var/empty", + f"--env OUTSIDE_UID={os.getuid()}", + f"--env OUTSIDE_GID={os.getgid()}", f"gcr.io/crosvm-infra/crosvm_dev:{IMAGE_VERSION}", ] @@ -165,14 +167,18 @@ def main( tty_args = ["--interactive", "--tty"] # Start an interactive shell by default - if not command: - command = ("/bin/bash",) - - quoted_cmd = list(map(quoted, command)) if hermetic: + # cmd is passed to entrypoint + quoted_cmd = list(map(quoted, command)) docker(f"run --rm", *tty_args, *docker_args, *quoted_cmd).fg() else: + # cmd is executed directly cid = ensure_container_is_alive(docker, docker_args) + if not command: + command = ("/tools/entrypoint.sh",) + else: + command = ("/tools/entrypoint.sh",) + tuple(command) + quoted_cmd = list(map(quoted, command)) docker("exec", *tty_args, cid, *quoted_cmd).fg() diff --git a/tools/impl/dev_container/Dockerfile b/tools/impl/dev_container/Dockerfile index 4152c501da..42023f94ca 100644 --- a/tools/impl/dev_container/Dockerfile +++ b/tools/impl/dev_container/Dockerfile @@ -5,45 +5,56 @@ ARG RUST_VERSION FROM docker.io/rust:${RUST_VERSION}-slim-bullseye # Use a dedicated target directory so we do not write into the source directory. -RUN mkdir -p /scratch/cargo_target -ENV CARGO_TARGET_DIR=/scratch/cargo_target +RUN mkdir -p /scratch/cargo_target \ + && mkdir /cache -# Prevent the container from writing root-owned __pycache__ files into the src. +# Prevent the container from writing __pycache__ files into the src. ENV PYTHONDONTWRITEBYTECODE=1 +ENV CARGO_TARGET_DIR=/scratch/cargo_target # Add foreign architectures for cross-compilation. RUN dpkg --add-architecture arm64 \ && dpkg --add-architecture armhf -# Install dependencies for native builds. -COPY tools/install-deps /tools/ -COPY tools/install-docs-deps /tools/ -RUN apt-get update \ - && apt-get install --yes sudo \ +# Install dependencies. +COPY tools/install-deps tools/install-aarch64-deps tools/install-armhf-deps tools/install-docs-deps /tools/ +RUN chmod 755 /tools/install-deps /tools/install-aarch64-deps /tools/install-armhf-deps /tools/install-docs-deps \ + && apt update \ + && apt install --yes sudo \ && /tools/install-deps \ + && /tools/install-aarch64-deps \ + && /tools/install-armhf-deps \ + && /tools/install-docs-deps \ # Clear apt cache to save space in layer. && rm -rf /var/lib/apt/lists/* \ # Delete build artifacts from 'cargo install' to save space in layer. && rm -rf /scratch/cargo_target/* +# Add a new password-less sudoer user crosvmdev +RUN useradd -ms /bin/bash crosvmdev \ + && usermod -aG sudo crosvmdev \ + && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \ + # Pass rust envs from rust toolchain image when sudo into new user + && echo 'Defaults env_keep += "RUSTUP_HOME CARGO_HOME RUST_VERSION CARGO_TARGET_DIR"' >> /etc/sudoers \ + # Allow dependencies and build files to be used and overwritten by user + && chmod -R 777 /scratch /cache + +# Following operations will be run as crosvmdev to ensure correct permission. +USER crosvmdev + +# Prepare path to rust toolchain for crosvmdev +RUN echo 'export PATH=/cache/cargo_home/bin:/usr/local/cargo/bin:$PATH' >> /home/crosvmdev/.profile + # Prepare wine64 -RUN ln -sf /usr/bin/wine64-stable /usr/bin/wine64 \ +RUN sudo ln -sf /usr/bin/wine64-stable /usr/bin/wine64 \ && wine64 wineboot -# Install cross-compilation dependencies. -COPY tools/install-aarch64-deps tools/install-armhf-deps /tools/ - -RUN apt-get update \ - && /tools/install-aarch64-deps \ - && /tools/install-armhf-deps \ - # Clear apt cache to save space in layer. - && rm -rf /var/lib/apt/lists/* - # Prebuild aarch64 VM image for faster startup. COPY tools/aarch64vm /tools/ COPY /tools/impl/testvm.py /tools/impl/ COPY /tools/impl/testvm/version /tools/impl/testvm/ -RUN /tools/aarch64vm build +RUN sudo chmod 755 /tools/aarch64vm /tools/impl/testvm.py \ + && /tools/aarch64vm build # Cache CARGO_HOME between container runs in CI. VOLUME /cache @@ -51,3 +62,9 @@ ENV CARGO_HOME=/cache/cargo_home VOLUME /workspace WORKDIR /workspace + +# Switch back to root to avoid usermod crosvmdev as crosvmdev +USER root +COPY tools/impl/dev_container/entrypoint.sh tools/impl/dev_container/setup-user.sh /tools/ +RUN chmod 755 /tools/entrypoint.sh /tools/setup-user.sh +ENTRYPOINT ["/tools/entrypoint.sh"] diff --git a/tools/impl/dev_container/entrypoint.sh b/tools/impl/dev_container/entrypoint.sh new file mode 100755 index 0000000000..45f2d81d73 --- /dev/null +++ b/tools/impl/dev_container/entrypoint.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Copyright 2022 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. + +# Ensure there's only 1 instance of setup-user.sh running +flock /tmp/entrypoint_lock /tools/setup-user.sh + +# Give KVM device correct permission +chmod 666 /dev/kvm + +# Run provided command or interactive shell +if [[ $# -eq 0 ]]; then + sudo -u crosvmdev /bin/bash -l +else + sudo -u crosvmdev /bin/bash -l -c "$*" +fi diff --git a/tools/impl/dev_container/setup-user.sh b/tools/impl/dev_container/setup-user.sh new file mode 100644 index 0000000000..eca19a0384 --- /dev/null +++ b/tools/impl/dev_container/setup-user.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Copyright 2022 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. + +if [[ $OUTSIDE_GID != $(sudo -u crosvmdev id -g) ]]; then + groupmod -g "$OUTSIDE_GID" crosvmdev + chgrp -R crosvmdev /home/crosvmdev +fi +if [[ $OUTSIDE_UID != $(sudo -u crosvmdev id -u) ]]; then + usermod -u "$OUTSIDE_UID" crosvmdev +fi + +# Transitional section to fix CI's cache permission +chmod -R 777 /cache +if [[ -d /workspace/infra/.recipe_deps ]]; then + chmod -R 777 /workspace/infra/.recipe_deps +fi diff --git a/tools/impl/dev_container/version b/tools/impl/dev_container/version index ea1d9ddebb..2180f1328d 100644 --- a/tools/impl/dev_container/version +++ b/tools/impl/dev_container/version @@ -1 +1 @@ -r0016 +r0019