infra: Add build_chromeos_container builder

Add a new builder to build crosvm in crOS tree, and all the
depencies of this new builder.

BUG=b:240692674
TESTED=led get-builder luci.crosvm.ci:chromeos_amd64-generic | led edit-cr-cl https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3966928 | led edit-recipe-bundle | led edit -r build_chromeos_hatch | led launch

Change-Id: Id2f284139922916edd2dd584f576da9fb3445518
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3966928
Reviewed-by: Dennis Kempin <denniskempin@google.com>
Commit-Queue: Zihan Chen <zihanchen@google.com>
This commit is contained in:
Zihan Chen 2022-10-19 22:25:57 +00:00 committed by crosvm LUCI
parent bf4cad131d
commit 988858b66b
17 changed files with 619 additions and 56 deletions

View file

@ -7,10 +7,12 @@
**[Recipes](#Recipes)**
* [build_chromeos](#recipes-build_chromeos) (Python3 ✅)
* [build_chromeos_hatch](#recipes-build_chromeos_hatch) (Python3 ✅)
* [build_docs](#recipes-build_docs) (Python3 ✅)
* [build_linux](#recipes-build_linux) (Python3 ✅)
* [build_windows](#recipes-build_windows) (Python3 ✅)
* [crosvm:examples/container_build_context](#recipes-crosvm_examples_container_build_context) (Python3 ✅)
* [crosvm:examples/cros_container_build_context](#recipes-crosvm_examples_cros_container_build_context) (Python3 ✅)
* [crosvm:examples/host_build_context](#recipes-crosvm_examples_host_build_context) (Python3 ✅)
* [crosvm:examples/source_context](#recipes-crosvm_examples_source_context) (Python3 ✅)
* [health_check](#recipes-health_check) (Python3 ✅)
@ -50,11 +52,19 @@ Usage:
with api.crosvm.container_build_context():
api.crosvm.step_in_container("build crosvm", ["cargo build"])
&mdash; **def [cros\_container\_build\_context](/infra/recipe_modules/crosvm/api.py#79)(self):**
Prepares source and system to build crosvm via cros container.
Usage:
with api.crosvm.cros_container_build_context():
api.crosvm.step_in_container("build crosvm", ["cargo build"], cros=True)
&emsp; **@property**<br>&mdash; **def [dev\_container\_cache](/infra/recipe_modules/crosvm/api.py#39)(self):**
&mdash; **def [get\_git\_sha](/infra/recipe_modules/crosvm/api.py#139)(self):**
&mdash; **def [get\_git\_sha](/infra/recipe_modules/crosvm/api.py#174)(self):**
&mdash; **def [host\_build\_context](/infra/recipe_modules/crosvm/api.py#79)(self):**
&mdash; **def [host\_build\_context](/infra/recipe_modules/crosvm/api.py#113)(self):**
Prepares source and system to build crosvm directly on the host.
@ -69,7 +79,7 @@ Usage:
Directory used to install local tools required by the build.
&mdash; **def [prepare\_git](/infra/recipe_modules/crosvm/api.py#124)(self):**
&mdash; **def [prepare\_git](/infra/recipe_modules/crosvm/api.py#159)(self):**
&emsp; **@property**<br>&mdash; **def [rustup\_home](/infra/recipe_modules/crosvm/api.py#19)(self):**
@ -85,11 +95,11 @@ Use when no build commands are needed.
Where the crosvm source will be checked out.
&mdash; **def [step\_in\_container](/infra/recipe_modules/crosvm/api.py#110)(self, step_name, command):**
&mdash; **def [step\_in\_container](/infra/recipe_modules/crosvm/api.py#144)(self, step_name, command, cros=False):**
Runs a luci step inside the crosvm dev container.
&mdash; **def [upload\_coverage](/infra/recipe_modules/crosvm/api.py#147)(self, filename):**
&mdash; **def [upload\_coverage](/infra/recipe_modules/crosvm/api.py#182)(self, filename):**
## Recipes
### *recipes* / [build\_chromeos](/infra/recipes/build_chromeos.py)
@ -109,6 +119,13 @@ PYTHON_VERSION_COMPATIBILITY: PY3
&mdash; **def [SetupSource](/infra/recipes/build_chromeos.py#27)(api, workspace):**
&mdash; **def [TestCrosWorkonFlow](/infra/recipes/build_chromeos.py#89)(api, board):**
### *recipes* / [build\_chromeos\_hatch](/infra/recipes/build_chromeos_hatch.py)
[DEPS](/infra/recipes/build_chromeos_hatch.py#9): [crosvm](#recipe_modules-crosvm), [depot\_tools/depot\_tools][depot_tools/recipe_modules/depot_tools], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/step][recipe_engine/recipe_modules/step]
PYTHON_VERSION_COMPATIBILITY: PY3
&mdash; **def [RunSteps](/infra/recipes/build_chromeos_hatch.py#19)(api):**
### *recipes* / [build\_docs](/infra/recipes/build_docs.py)
[DEPS](/infra/recipes/build_docs.py#9): [crosvm](#recipe_modules-crosvm), [depot\_tools/gsutil][depot_tools/recipe_modules/gsutil], [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/file][recipe_engine/recipe_modules/file], [recipe\_engine/step][recipe_engine/recipe_modules/step]
@ -146,6 +163,13 @@ PYTHON_VERSION_COMPATIBILITY: PY3
PYTHON_VERSION_COMPATIBILITY: PY3
&mdash; **def [RunSteps](/infra/recipe_modules/crosvm/examples/container_build_context.py#12)(api):**
### *recipes* / [crosvm:examples/cros\_container\_build\_context](/infra/recipe_modules/crosvm/examples/cros_container_build_context.py)
[DEPS](/infra/recipe_modules/crosvm/examples/cros_container_build_context.py#7): [crosvm](#recipe_modules-crosvm)
PYTHON_VERSION_COMPATIBILITY: PY3
&mdash; **def [RunSteps](/infra/recipe_modules/crosvm/examples/cros_container_build_context.py#12)(api):**
### *recipes* / [crosvm:examples/host\_build\_context](/infra/recipe_modules/crosvm/examples/host_build_context.py)
[DEPS](/infra/recipe_modules/crosvm/examples/host_build_context.py#7): [crosvm](#recipe_modules-crosvm), [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/step][recipe_engine/recipe_modules/step]

View file

@ -57,6 +57,27 @@ buckets {
value: 100
}
}
builders {
name: "chromeos_hatch"
swarming_host: "chromium-swarm.appspot.com"
dimensions: "cpu:x86-64"
dimensions: "os:Ubuntu"
dimensions: "pool:luci.crosvm.ci"
exe {
cipd_package: "infra/recipe_bundles/chromium.googlesource.com/crosvm/crosvm"
cipd_version: "refs/heads/main"
cmd: "luciexe"
}
properties:
'{'
' "recipe": "build_chromeos_container"'
'}'
service_account: "crosvm-luci-ci-builder@crosvm-infra.iam.gserviceaccount.com"
experiments {
key: "luci.recipes.use_python3"
value: 100
}
}
builders {
name: "health_check"
swarming_host: "chromium-swarm.appspot.com"

View file

@ -34,6 +34,10 @@ consoles {
name: "buildbucket/luci.crosvm.ci/chromeos_amd64-generic"
category: "linux"
}
builders {
name: "buildbucket/luci.crosvm.ci/chromeos_hatch"
category: "linux"
}
builders {
name: "buildbucket/luci.crosvm.ci/windows"
category: "windows"

View file

@ -33,6 +33,21 @@ notifiers {
repository: "https://chromium.googlesource.com/crosvm/crosvm"
}
}
notifiers {
notifications {
on_change: true
email {
recipients: "crosvm-uprev@grotations.appspotmail.com"
recipients: "crosvm-uprev-apac@grotations.appspotmail.com"
recipients: "denniskempin@google.com"
}
}
builders {
bucket: "ci"
name: "chromeos_hatch"
repository: "https://chromium.googlesource.com/crosvm/crosvm"
}
}
notifiers {
notifications {
on_change: true

View file

@ -24,6 +24,16 @@ job {
builder: "chromeos_amd64-generic"
}
}
job {
id: "chromeos_hatch"
realm: "ci"
acl_sets: "ci"
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "ci"
builder: "chromeos_hatch"
}
}
job {
id: "health_check"
realm: "ci"
@ -121,6 +131,7 @@ trigger {
acl_sets: "ci"
triggers: "build_docs"
triggers: "chromeos_amd64-generic"
triggers: "chromeos_hatch"
triggers: "health_check"
triggers: "linux_aarch64"
triggers: "linux_armhf"

View file

@ -342,6 +342,19 @@ verify_linux_builder("mingw64", coverage = False)
verify_chromeos_builder("amd64-generic", presubmit = False)
verify_builder(
name = "chromeos_hatch",
dimensions = {
"os": "Ubuntu",
"cpu": "x86-64",
},
executable = luci.recipe(
name = "build_chromeos_container",
),
category = "linux",
presubmit = False,
)
verify_builder(
name = "windows",
dimensions = {

View file

@ -76,6 +76,40 @@ class CrosvmApi(recipe_api.RecipeApi):
}
return self.m.context(cwd=self.source_dir, env=env)
def cros_container_build_context(self):
"""
Prepares source and system to build crosvm via cros container.
Usage:
with api.crosvm.cros_container_build_context():
api.crosvm.step_in_container("build crosvm", ["cargo build"], cros=True)
"""
with self.m.step.nest("Prepare Cros Container Build"):
with self.m.context(infra_steps=True):
self.__prepare_source()
with self.m.context(cwd=self.source_dir):
self.m.step(
"Stop existing cros containers",
[
"vpython3",
self.source_dir.join("tools/dev_container"),
"--verbose",
"--stop",
"--cros",
],
)
self.m.step(
"Force pull cros_container",
[
"vpython3",
self.source_dir.join("tools/dev_container"),
"--pull",
"--cros",
],
)
self.m.crosvm.step_in_container("Ensure cros container exists", ["true"], cros=True)
return self.m.context(cwd=self.source_dir)
def host_build_context(self):
"""
Prepares source and system to build crosvm directly on the host.
@ -107,7 +141,7 @@ class CrosvmApi(recipe_api.RecipeApi):
return self.m.context(env=env, env_prefixes=env_prefixes, cwd=self.source_dir)
def step_in_container(self, step_name, command):
def step_in_container(self, step_name, command, cros=False):
"""
Runs a luci step inside the crosvm dev container.
"""
@ -118,6 +152,7 @@ class CrosvmApi(recipe_api.RecipeApi):
self.source_dir.join("tools/dev_container"),
"--verbose",
]
+ (["--cros"] if cros else [])
+ command,
)

View file

@ -0,0 +1,270 @@
[
{
"cmd": [],
"name": "Prepare Cros Container Build"
},
{
"cmd": [],
"name": "Prepare Cros Container Build.Prepare git",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@1@@@"
]
},
{
"cmd": [
"git",
"config",
"--get",
"user.name"
],
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare git.git config user.name",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"git",
"config",
"--get",
"user.email"
],
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare git.git config user.email",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"git",
"config",
"--global",
"user.name",
"Crosvm Bot"
],
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare git.Set git config: user.name",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"git",
"config",
"--global",
"user.email",
"crosvm-bot@crosvm-infra.iam.gserviceaccount.com"
],
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare git.Set git config: user.email",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"git",
"config",
"--global",
"credential.helper",
"gcloud.sh"
],
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare git.Set git config: credential.helper",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [],
"name": "Prepare Cros Container Build.Prepare source",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@1@@@"
]
},
{
"cmd": [
"vpython3",
"-u",
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
"--json-output",
"/path/to/tmp/json",
"ensure-directory",
"--mode",
"0777",
"[CACHE]/builder"
],
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare source.Ensure builder_cache exists",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"vpython3",
"-u",
"RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py",
"--spec-path",
"cache_dir = '[CACHE]/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': True, 'name': 'crosvm', 'url': 'https://chromium.googlesource.com/crosvm/crosvm'}]",
"--revision_mapping_file",
"{\"got_revision\": \"crosvm\"}",
"--git-cache-dir",
"[CACHE]/git",
"--cleanup-dir",
"[CLEANUP]/bot_update",
"--output_json",
"/path/to/tmp/json",
"--revision",
"crosvm@HEAD",
"--gerrit_no_reset"
],
"cwd": "[CACHE]/builder",
"env": {
"DEPOT_TOOLS_COLLECT_METRICS": "0",
"GIT_HTTP_LOW_SPEED_LIMIT": "102400",
"GIT_HTTP_LOW_SPEED_TIME": "1800"
},
"env_suffixes": {
"DEPOT_TOOLS_UPDATE": [
"0"
],
"PATH": [
"RECIPE_REPO[depot_tools]"
]
},
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare source.bot_update",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@",
"@@@STEP_TEXT@Some step text@@@",
"@@@STEP_LOG_LINE@json.output@{@@@",
"@@@STEP_LOG_LINE@json.output@ \"did_run\": true, @@@",
"@@@STEP_LOG_LINE@json.output@ \"fixed_revisions\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"crosvm\": \"HEAD\"@@@",
"@@@STEP_LOG_LINE@json.output@ }, @@@",
"@@@STEP_LOG_LINE@json.output@ \"manifest\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"crosvm\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"repository\": \"https://fake.org/crosvm.git\", @@@",
"@@@STEP_LOG_LINE@json.output@ \"revision\": \"2e31dd442a44af9e1e51e96aeca18017ddb9922c\"@@@",
"@@@STEP_LOG_LINE@json.output@ }@@@",
"@@@STEP_LOG_LINE@json.output@ }, @@@",
"@@@STEP_LOG_LINE@json.output@ \"patch_failure\": false, @@@",
"@@@STEP_LOG_LINE@json.output@ \"patch_root\": \"crosvm\", @@@",
"@@@STEP_LOG_LINE@json.output@ \"properties\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"got_revision\": \"2e31dd442a44af9e1e51e96aeca18017ddb9922c\", @@@",
"@@@STEP_LOG_LINE@json.output@ \"got_revision_cp\": \"refs/heads/main@{#119844}\"@@@",
"@@@STEP_LOG_LINE@json.output@ }, @@@",
"@@@STEP_LOG_LINE@json.output@ \"root\": \"crosvm\", @@@",
"@@@STEP_LOG_LINE@json.output@ \"source_manifest\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"directories\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"crosvm\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"git_checkout\": {@@@",
"@@@STEP_LOG_LINE@json.output@ \"repo_url\": \"https://fake.org/crosvm.git\", @@@",
"@@@STEP_LOG_LINE@json.output@ \"revision\": \"2e31dd442a44af9e1e51e96aeca18017ddb9922c\"@@@",
"@@@STEP_LOG_LINE@json.output@ }@@@",
"@@@STEP_LOG_LINE@json.output@ }@@@",
"@@@STEP_LOG_LINE@json.output@ }, @@@",
"@@@STEP_LOG_LINE@json.output@ \"version\": 0@@@",
"@@@STEP_LOG_LINE@json.output@ }, @@@",
"@@@STEP_LOG_LINE@json.output@ \"step_text\": \"Some step text\"@@@",
"@@@STEP_LOG_LINE@json.output@}@@@",
"@@@STEP_LOG_END@json.output@@@",
"@@@SET_BUILD_PROPERTY@got_revision@\"2e31dd442a44af9e1e51e96aeca18017ddb9922c\"@@@",
"@@@SET_BUILD_PROPERTY@got_revision_cp@\"refs/heads/main@{#119844}\"@@@"
]
},
{
"cmd": [],
"name": "Prepare Cros Container Build.Prepare source.Sync submodules",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"git",
"submodule",
"update",
"--force",
"--init"
],
"cwd": "[CACHE]/builder/crosvm",
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare source.Sync submodules.Init / Update submodules",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@3@@@"
]
},
{
"cmd": [
"git",
"repack",
"-a"
],
"cwd": "[CACHE]/builder/crosvm",
"infra_step": true,
"name": "Prepare Cros Container Build.Prepare source.Repack repository",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@2@@@"
]
},
{
"cmd": [
"vpython3",
"[CACHE]/builder/crosvm/tools/dev_container",
"--verbose",
"--stop",
"--cros"
],
"cwd": "[CACHE]/builder/crosvm",
"name": "Prepare Cros Container Build.Stop existing cros containers",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@1@@@"
]
},
{
"cmd": [
"vpython3",
"[CACHE]/builder/crosvm/tools/dev_container",
"--pull",
"--cros"
],
"cwd": "[CACHE]/builder/crosvm",
"name": "Prepare Cros Container Build.Force pull cros_container",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@1@@@"
]
},
{
"cmd": [
"vpython3",
"[CACHE]/builder/crosvm/tools/dev_container",
"--verbose",
"--cros",
"true"
],
"cwd": "[CACHE]/builder/crosvm",
"name": "Prepare Cros Container Build.Ensure cros container exists",
"~followup_annotations": [
"@@@STEP_NEST_LEVEL@1@@@"
]
},
{
"cmd": [
"vpython3",
"[CACHE]/builder/crosvm/tools/dev_container",
"--verbose",
"--cros",
"true"
],
"cwd": "[CACHE]/builder/crosvm",
"name": "true"
},
{
"name": "$result"
}
]

View file

@ -0,0 +1,18 @@
# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
PYTHON_VERSION_COMPATIBILITY = "PY3"
DEPS = [
"crosvm",
]
def RunSteps(api):
with api.crosvm.cros_container_build_context():
api.crosvm.step_in_container("true", ["true"], cros=True)
def GenTests(api):
yield api.test("basic")

View file

@ -0,0 +1,27 @@
[
{
"cmd": [
"vpython3",
"[CACHE]/builder/crosvm/tools/dev_container",
"--verbose",
"--cros",
"cros_sdk",
"emerge-hatch",
"crosvm"
],
"cwd": "[CACHE]/builder/crosvm",
"luci_context": {
"realm": {
"name": "crosvm/crosvm:ci"
},
"resultdb": {
"current_invocation": {
"name": "invocations/build:8945511751514863184",
"update_token": "token"
},
"hostname": "rdbhost"
}
},
"name": "Build crosvm"
}
]

View file

@ -0,0 +1,69 @@
# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from recipe_engine.post_process import Filter
PYTHON_VERSION_COMPATIBILITY = "PY3"
DEPS = [
"crosvm",
"depot_tools/depot_tools",
"recipe_engine/buildbucket",
"recipe_engine/context",
"recipe_engine/properties",
"recipe_engine/step",
]
def RunSteps(api):
with api.crosvm.cros_container_build_context():
gitilies = api.buildbucket.build.input.gitiles_commit
upstream_url = "https://chromium.googlesource.com/crosvm/crosvm"
revision = gitilies.id or "HEAD"
api.crosvm.step_in_container(
"Sync repo",
[
"repo",
"sync",
"-j8",
"--current-branch",
],
cros=True,
)
# Overwrite crosvm with the upstream revision we need to test
api.crosvm.step_in_container(
"Fetch upstream crosvm", ["git", "fetch", upstream_url], cros=True
)
api.crosvm.step_in_container(
"Checkout upstream revision", ["git", "checkout", revision], cros=True
)
api.crosvm.step_in_container(
"cros-workon-hatch crosvm",
["cros_sdk", "cros-workon-hatch", "start", "crosvm"],
cros=True,
)
api.crosvm.step_in_container(
"Build crosvm",
[
"cros_sdk",
"emerge-hatch",
"crosvm",
],
cros=True,
)
def GenTests(api):
filter_steps = Filter("Build crosvm")
yield (
api.test(
"build_chromeos_hatch",
api.buildbucket.ci_build(project="crosvm/crosvm"),
)
+ api.post_process(filter_steps)
)

View file

@ -19,6 +19,10 @@
# is cleaned up afterwards (e.g. when run by Kokoro):
#
# ./tools/dev_container --hermetic CMD
#
# There's an alternative container which can be used to test crosvm in crOS tree.
# It can be launched with:
# ./tools/dev_container --cros
import argparse
from argh import arg # type: ignore
@ -31,10 +35,17 @@ import unittest
import os
import zlib
CONTAINER_NAME = (
DEV_CONTAINER_NAME = (
f"crosvm_dev_{getpass.getuser()}_{zlib.crc32(os.path.realpath(__file__).encode('utf-8')):x}"
)
IMAGE_VERSION = (CROSVM_ROOT / "tools/impl/dev_container/version").read_text().strip()
CROS_CONTAINER_NAME = (
f"crosvm_cros_{getpass.getuser()}_{zlib.crc32(os.path.realpath(__file__).encode('utf-8')):x}"
)
DEV_IMAGE_NAME = "gcr.io/crosvm-infra/crosvm_dev_user"
CROS_IMAGE_NAME = "gcr.io/crosvm-infra-experimental/crosvm_cros_cloudbuild"
DEV_IMAGE_VERSION = (CROSVM_ROOT / "tools/impl/dev_container/version").read_text().strip()
CACHE_DIR = os.environ.get("CROSVM_CONTAINER_CACHE", None)
DOCKER_ARGS = [
@ -46,7 +57,6 @@ DOCKER_ARGS = [
"--device /dev/kvm",
f"--env OUTSIDE_UID={os.getuid()}",
f"--env OUTSIDE_GID={os.getgid()}",
f"gcr.io/crosvm-infra/crosvm_dev_user:{IMAGE_VERSION}",
]
PODMAN_ARGS = [
@ -56,7 +66,6 @@ PODMAN_ARGS = [
"--mount type=tmpfs,destination=/tmp",
# KVM is required to run a VM for testing.
"--device /dev/kvm",
f"gcr.io/crosvm-infra/crosvm_dev:{IMAGE_VERSION}",
]
PRIVILEGED_ARGS = [
@ -73,6 +82,13 @@ PRIVILEGED_ARGS = [
PODMAN_IS_DEFAULT = shutil.which("docker") == None
def container_name(cros: bool):
if cros:
return CROS_CONTAINER_NAME
else:
return DEV_CONTAINER_NAME
def container_revision(docker: cmd, container_id: str):
image = docker("container inspect -f {{.Config.Image}}", container_id).stdout()
parts = image.split(":")
@ -80,16 +96,16 @@ def container_revision(docker: cmd, container_id: str):
return parts[1]
def container_id(docker: cmd):
return docker(f"ps -a -q -f name={CONTAINER_NAME}").stdout()
def container_id(docker: cmd, cros: bool):
return docker(f"ps -a -q -f name={container_name(cros)}").stdout()
def container_is_running(docker: cmd):
return bool(docker(f"ps -q -f name={CONTAINER_NAME}").stdout())
def container_is_running(docker: cmd, cros: bool):
return bool(docker(f"ps -q -f name={container_name(cros)}").stdout())
def delete_container(docker: cmd):
cid = container_id(docker)
def delete_container(docker: cmd, cros: bool):
cid = container_id(docker, cros)
if cid:
print(f"Deleting dev-container {cid}.")
docker("rm -f", cid).fg(quiet=True)
@ -97,14 +113,16 @@ def delete_container(docker: cmd):
return False
def workspace_mount_args():
def workspace_mount_args(cros: bool):
"""
Returns arguments for mounting the crosvm sources to /workspace.
In ChromeOS checkouts the crosvm repo uses a symlink or worktree checkout, which links to a
different folder in the ChromeOS checkout. So we need to mount the whole CrOS checkout.
"""
if is_cros_repo():
if cros:
return ["--workdir /home/crosvmdev/chromiumos/src/platform/crosvm"]
elif is_cros_repo():
return [
f"--volume {quoted(cros_repo_root())}:/workspace:rw",
"--workdir /workspace/src/platform/crosvm",
@ -115,25 +133,27 @@ def workspace_mount_args():
]
def ensure_container_is_alive(docker: cmd, docker_args: List[Optional[str]]):
cid = container_id(docker)
if cid and not container_is_running(docker):
print("Existing dev-container is not running.")
delete_container(docker)
elif cid and container_revision(docker, cid) != IMAGE_VERSION:
def ensure_container_is_alive(docker: cmd, docker_args: List[Optional[str]], cros: bool):
cid = container_id(docker, cros)
if cid and not container_is_running(docker, cros):
print("Existing container is not running.")
delete_container(docker, cros)
elif cid and not cros and container_revision(docker, cid) != DEV_IMAGE_VERSION:
print(f"New image is available.")
delete_container(docker)
delete_container(docker, cros)
if not container_is_running(docker):
if not container_is_running(docker, cros):
# Run neverending sleep to keep container alive while we 'docker exec' commands.
docker(f"run --detach --name {CONTAINER_NAME}", *docker_args, "sleep infinity").fg(
quiet=True
)
cid = container_id(docker)
print(f"Started dev-container ({cid}).")
docker(
f"run --detach --name {container_name(cros)}",
*docker_args,
"sleep infinity",
).fg(quiet=True)
cid = container_id(docker, cros)
print(f"Started container ({cid}).")
else:
cid = container_id(docker)
print(f"Using existing dev-container ({cid}).")
cid = container_id(docker, cros)
print(f"Using existing container ({cid}).")
return cid
@ -148,16 +168,21 @@ def main(
self_test: bool = False,
pull: bool = False,
unprivileged: bool = False,
cros: bool = False,
):
chdir(CROSVM_ROOT)
if cros and unprivileged:
print("ERROR: crOS container must be run in privileged mode")
sys.exit(1)
if unprivileged:
print("WARNING: Running dev_container with --unprivileged is a work in progress.")
print("Not all tests are expected to pass.")
print()
docker_args = [
*workspace_mount_args(),
*workspace_mount_args(cros),
*(PRIVILEGED_ARGS if not unprivileged else []),
]
if podman:
@ -173,6 +198,11 @@ def main(
*DOCKER_ARGS,
]
if cros:
docker_args.append(CROS_IMAGE_NAME)
else:
docker_args.append(DEV_IMAGE_NAME + ":" + DEV_IMAGE_VERSION)
if self_test:
TestDevContainer.docker = docker
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestDevContainer)
@ -180,16 +210,19 @@ def main(
return
if stop:
if not delete_container(docker):
print(f"Dev-container is not running.")
if not delete_container(docker, cros):
print(f"container is not running.")
return
if clean:
delete_container(docker)
delete_container(docker, cros)
if pull:
docker("pull", f"gcr.io/crosvm-infra/crosvm_dev:{IMAGE_VERSION}").fg()
docker("pull", f"gcr.io/crosvm-infra/crosvm_dev_user:{IMAGE_VERSION}").fg()
if cros:
docker("pull", "gcr.io/crosvm-infra-experimental/crosvm_cros_cloudbuild").fg()
else:
docker("pull", f"gcr.io/crosvm-infra/crosvm_dev:{DEV_IMAGE_VERSION}").fg()
docker("pull", f"gcr.io/crosvm-infra/crosvm_dev_user:{DEV_IMAGE_VERSION}").fg()
return
# If a command is provided run non-interactive unless explicitly asked for.
@ -209,7 +242,7 @@ def main(
docker(f"run --rm", *tty_args, *docker_args, *quoted_cmd).fg()
else:
# cmd is executed directly
cid = ensure_container_is_alive(docker, docker_args)
cid = ensure_container_is_alive(docker, docker_args, cros)
if podman:
if not command:
command = ("/bin/bash",)
@ -232,32 +265,34 @@ class TestDevContainer(unittest.TestCase):
docker: cmd
docker_args = [
*workspace_mount_args(),
*workspace_mount_args(cros=False),
*DOCKER_ARGS,
]
def setUp(self):
# Start with a stopped container for each test.
delete_container(self.docker)
delete_container(self.docker, cros=False)
def test_stopped_container(self):
# Create but do not run a new container.
self.docker(f"create --name {CONTAINER_NAME}", *self.docker_args, "sleep infinity").stdout()
self.assertTrue(container_id(self.docker))
self.assertFalse(container_is_running(self.docker))
self.docker(
f"create --name {DEV_CONTAINER_NAME}", *self.docker_args, "sleep infinity"
).stdout()
self.assertTrue(container_id(self.docker, cros=False))
self.assertFalse(container_is_running(self.docker, cros=False))
def test_container_reuse(self):
cid = ensure_container_is_alive(self.docker, self.docker_args)
cid2 = ensure_container_is_alive(self.docker, self.docker_args)
cid = ensure_container_is_alive(self.docker, self.docker_args, cros=False)
cid2 = ensure_container_is_alive(self.docker, self.docker_args, cros=False)
self.assertEqual(cid, cid2)
def test_handling_of_stopped_container(self):
cid = ensure_container_is_alive(self.docker, self.docker_args)
cid = ensure_container_is_alive(self.docker, self.docker_args, cros=False)
self.docker("kill", cid).fg()
# Make sure we can get back into a good state and execute commands.
ensure_container_is_alive(self.docker, self.docker_args)
self.assertTrue(container_is_running(self.docker))
ensure_container_is_alive(self.docker, self.docker_args, cros=False)
self.assertTrue(container_is_running(self.docker, cros=False))
main(("true",))

View file

@ -3,7 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
FROM docker.io/debian:testing-20220822-slim
FROM docker.io/debian:testing-slim
ARG BOARD=hatch
RUN apt update \
@ -14,6 +14,10 @@ RUN useradd -ms /bin/bash crosvmdev \
&& usermod -aG sudo crosvmdev \
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
COPY entrypoint.sh /tools/
RUN chmod 755 /tools/entrypoint.sh
ENTRYPOINT [ "/tools/entrypoint.sh" ]
# Following operations will be run as crosvmdev to ensure correct permission.
USER crosvmdev
WORKDIR /home/crosvmdev

View file

@ -7,12 +7,16 @@ steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'buildx', 'create', '--use', '--name', 'insecure-builder', '--buildkitd-flags', '--allow-insecure-entitlement security.insecure']
- name: 'gcr.io/cloud-builders/docker'
args: [ 'buildx', 'build', '-t', 'gcr.io/crosvm-infra-experimental/crosvm_cros_cloudbuild', '--allow', 'security.insecure', '.' ]
args: [ 'buildx', 'build', '-t', 'gcr.io/crosvm-infra-experimental/crosvm_cros_cloudbuild', '--cache-to=type=local,dest=/docker_cache', '--allow', 'security.insecure', '.' ]
# docker push is separated out because of https://github.com/docker/buildx/issues/1205
- name: 'gcr.io/cloud-builders/docker'
args: [ 'buildx', 'stop', 'insecure-builder']
- name: 'gcr.io/cloud-builders/docker'
args: [ 'buildx', 'build', '-t', 'gcr.io/crosvm-infra-experimental/crosvm_cros_cloudbuild', '--push', '--allow', 'security.insecure', '.' ]
args: [ 'buildx', 'build', '-t', 'gcr.io/crosvm-infra-experimental/crosvm_cros_cloudbuild', '--cache-from=type=local,src=/docker_cache', '--push', '--allow', 'security.insecure', '.' ]
timeout: 30000s
options:
machineType: 'E2_HIGHCPU_32'
diskSizeGb: '500'
diskSizeGb: '1000'
volumes:
- name: 'docker_cache'
path: '/docker_cache'

View file

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# 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

View file

@ -11,4 +11,4 @@ steps:
timeout: 10000s
options:
machineType: 'E2_HIGHCPU_32'
diskSizeGb: '500'
diskSizeGb: '1000'

View file

@ -7,7 +7,9 @@
flock /tmp/entrypoint_lock /tools/setup-user.sh
# Give KVM device correct permission
chmod 666 /dev/kvm
if [ -f "/dev/kvm" ]; then
chmod 666 /dev/kvm
fi
# Run provided command or interactive shell
if [[ $# -eq 0 ]]; then