From 988858b66b76f9d14b99289c3cfde108059ba194 Mon Sep 17 00:00:00 2001 From: Zihan Chen Date: Wed, 19 Oct 2022 22:25:57 +0000 Subject: [PATCH] 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 Commit-Queue: Zihan Chen --- infra/README.recipes.md | 34 ++- infra/config/generated/cr-buildbucket.cfg | 21 ++ infra/config/generated/luci-milo.cfg | 4 + infra/config/generated/luci-notify.cfg | 15 + infra/config/generated/luci-scheduler.cfg | 11 + infra/config/main.star | 13 + infra/recipe_modules/crosvm/api.py | 37 ++- .../basic.json | 270 ++++++++++++++++++ .../examples/cros_container_build_context.py | 18 ++ .../build_chromeos_hatch.json | 27 ++ infra/recipes/build_chromeos_hatch.py | 69 +++++ tools/dev_container | 123 +++++--- tools/impl/cros_container/fresh/Dockerfile | 6 +- .../impl/cros_container/fresh/cloudbuild.yaml | 10 +- tools/impl/cros_container/fresh/entrypoint.sh | 11 + .../incremental/cloudbuild.yaml | 2 +- tools/impl/dev_container/entrypoint.sh | 4 +- 17 files changed, 619 insertions(+), 56 deletions(-) create mode 100644 infra/recipe_modules/crosvm/examples/cros_container_build_context.expected/basic.json create mode 100644 infra/recipe_modules/crosvm/examples/cros_container_build_context.py create mode 100644 infra/recipes/build_chromeos_hatch.expected/build_chromeos_hatch.json create mode 100644 infra/recipes/build_chromeos_hatch.py create mode 100644 tools/impl/cros_container/fresh/entrypoint.sh diff --git a/infra/README.recipes.md b/infra/README.recipes.md index 72df599c34..88156989cc 100644 --- a/infra/README.recipes.md +++ b/infra/README.recipes.md @@ -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"]) +— **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) +   **@property**
— **def [dev\_container\_cache](/infra/recipe_modules/crosvm/api.py#39)(self):** -— **def [get\_git\_sha](/infra/recipe_modules/crosvm/api.py#139)(self):** +— **def [get\_git\_sha](/infra/recipe_modules/crosvm/api.py#174)(self):** -— **def [host\_build\_context](/infra/recipe_modules/crosvm/api.py#79)(self):** +— **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. -— **def [prepare\_git](/infra/recipe_modules/crosvm/api.py#124)(self):** +— **def [prepare\_git](/infra/recipe_modules/crosvm/api.py#159)(self):**   **@property**
— **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. -— **def [step\_in\_container](/infra/recipe_modules/crosvm/api.py#110)(self, step_name, command):** +— **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. -— **def [upload\_coverage](/infra/recipe_modules/crosvm/api.py#147)(self, filename):** +— **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 — **def [SetupSource](/infra/recipes/build_chromeos.py#27)(api, workspace):** — **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 + +— **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 — **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 + +— **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] diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 9216d61ebf..e2d8eed3ca 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -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" diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index 93c26fd0b5..8dd2d0263a 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg @@ -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" diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg index 443199dd75..c6d6cd567a 100644 --- a/infra/config/generated/luci-notify.cfg +++ b/infra/config/generated/luci-notify.cfg @@ -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 diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index 3b05a44c47..7c6c76f4c7 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg @@ -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" diff --git a/infra/config/main.star b/infra/config/main.star index de60a29243..888c6defb9 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -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 = { diff --git a/infra/recipe_modules/crosvm/api.py b/infra/recipe_modules/crosvm/api.py index 41606fef28..e4296d84af 100644 --- a/infra/recipe_modules/crosvm/api.py +++ b/infra/recipe_modules/crosvm/api.py @@ -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, ) diff --git a/infra/recipe_modules/crosvm/examples/cros_container_build_context.expected/basic.json b/infra/recipe_modules/crosvm/examples/cros_container_build_context.expected/basic.json new file mode 100644 index 0000000000..dc7571a542 --- /dev/null +++ b/infra/recipe_modules/crosvm/examples/cros_container_build_context.expected/basic.json @@ -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" + } +] \ No newline at end of file diff --git a/infra/recipe_modules/crosvm/examples/cros_container_build_context.py b/infra/recipe_modules/crosvm/examples/cros_container_build_context.py new file mode 100644 index 0000000000..e6fc32fb11 --- /dev/null +++ b/infra/recipe_modules/crosvm/examples/cros_container_build_context.py @@ -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") diff --git a/infra/recipes/build_chromeos_hatch.expected/build_chromeos_hatch.json b/infra/recipes/build_chromeos_hatch.expected/build_chromeos_hatch.json new file mode 100644 index 0000000000..d1bd428f4c --- /dev/null +++ b/infra/recipes/build_chromeos_hatch.expected/build_chromeos_hatch.json @@ -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" + } +] \ No newline at end of file diff --git a/infra/recipes/build_chromeos_hatch.py b/infra/recipes/build_chromeos_hatch.py new file mode 100644 index 0000000000..caecfcedc7 --- /dev/null +++ b/infra/recipes/build_chromeos_hatch.py @@ -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) + ) diff --git a/tools/dev_container b/tools/dev_container index e8951cda8b..d712dda8bd 100755 --- a/tools/dev_container +++ b/tools/dev_container @@ -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",)) diff --git a/tools/impl/cros_container/fresh/Dockerfile b/tools/impl/cros_container/fresh/Dockerfile index e16541b38d..1573dd9c18 100644 --- a/tools/impl/cros_container/fresh/Dockerfile +++ b/tools/impl/cros_container/fresh/Dockerfile @@ -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 diff --git a/tools/impl/cros_container/fresh/cloudbuild.yaml b/tools/impl/cros_container/fresh/cloudbuild.yaml index cefd3d1e5a..83fc4b7138 100644 --- a/tools/impl/cros_container/fresh/cloudbuild.yaml +++ b/tools/impl/cros_container/fresh/cloudbuild.yaml @@ -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' diff --git a/tools/impl/cros_container/fresh/entrypoint.sh b/tools/impl/cros_container/fresh/entrypoint.sh new file mode 100644 index 0000000000..3d03a24c25 --- /dev/null +++ b/tools/impl/cros_container/fresh/entrypoint.sh @@ -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 diff --git a/tools/impl/cros_container/incremental/cloudbuild.yaml b/tools/impl/cros_container/incremental/cloudbuild.yaml index b0cfdbd967..e80a40ca9a 100644 --- a/tools/impl/cros_container/incremental/cloudbuild.yaml +++ b/tools/impl/cros_container/incremental/cloudbuild.yaml @@ -11,4 +11,4 @@ steps: timeout: 10000s options: machineType: 'E2_HIGHCPU_32' - diskSizeGb: '500' + diskSizeGb: '1000' diff --git a/tools/impl/dev_container/entrypoint.sh b/tools/impl/dev_container/entrypoint.sh index 16e9f24693..2d939615f3 100755 --- a/tools/impl/dev_container/entrypoint.sh +++ b/tools/impl/dev_container/entrypoint.sh @@ -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