| # Copyright 2021 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """ |
| Recipe to roll base/source_images for Packer. |
| """ |
| |
| from recipe_engine.recipe_api import Property |
| |
| DEPS = [ |
| "fuchsia/auto_roller", |
| "fuchsia/build_input_resolver", |
| "fuchsia/gcloud", |
| "fuchsia/gerrit", |
| "fuchsia/git", |
| "fuchsia/status_check", |
| "recipe_engine/buildbucket", |
| "recipe_engine/context", |
| "recipe_engine/file", |
| "recipe_engine/json", |
| "recipe_engine/path", |
| "recipe_engine/properties", |
| "recipe_engine/raw_io", |
| "recipe_engine/step", |
| ] |
| |
| PROPERTIES = { |
| "repo": Property(kind=str, help="Salt repository to checkout."), |
| "dry_run": Property( |
| kind=bool, help="Exit early instead of committing a change.", default=True |
| ), |
| } |
| |
| |
| def RunSteps(api, repo, dry_run): |
| # Resolve the build input to always contain a Gitiles commit. |
| api.build_input_resolver.resolve(default_project_url=repo) |
| |
| with api.step.nest("checkout"): |
| salt_path = api.path["start_dir"].join("salt") |
| revision = api.git.checkout_commit( |
| api.buildbucket.build.input.gitiles_commit, path=salt_path |
| ) |
| |
| # Get a short revision, image names must be < 64 characters |
| with api.context(cwd=salt_path): |
| revision = api.git( |
| "git rev-parse", |
| "rev-parse", |
| "--short", |
| revision, |
| stdout=api.raw_io.output(), |
| ).stdout.rstrip() |
| |
| template_path = salt_path.join("packer", "template.json") |
| |
| template = api.file.read_json(name="load packer template", source=template_path) |
| |
| images = {} |
| commit_message = "Rolling Salt Packer Base Images:\n\n" |
| for build in template["builders"]: |
| k = "{}/{}".format( |
| build["source_image_project_id"], build["source_image_family"] |
| ) |
| image = images.get(k, "") |
| if not image: |
| result = api.gcloud( |
| "compute", |
| "images", |
| "describe-from-family", |
| "{}".format(build["source_image_family"]), |
| "--project={}".format(build["source_image_project_id"]), |
| "--format=json", |
| ok_ret="any", |
| stdout=api.json.output(), |
| step_name="get latest image for {}".format(k), |
| ) |
| if result.retcode != 0 or "name" not in result.stdout: |
| raise api.step.StepFailure("Unable to find image for {}".format(k)) |
| images[k] = result.stdout["name"] |
| image = images[k] |
| if build["source_image"] != image: |
| commit_message += "{build}: {old} -> {new}\n".format( |
| build=build["name"], old=build["source_image"], new=image |
| ) |
| build["source_image"] = image |
| |
| api.file.write_json( |
| name="update packer template", |
| dest=template_path, |
| data=template, |
| indent=2, |
| ) |
| |
| env = { |
| # Disable update checks. |
| "CHECKPOINT_DISABLE": "1", |
| # Enable verbose logging. |
| "PACKER_LOG": "1", |
| # Disable color in logging. |
| "PACKER_NO_COLOR": "1", |
| } |
| |
| with api.context(env=env): |
| api.step( |
| "packer validate", |
| [ |
| "packer", |
| "validate", |
| "-var", |
| "revision={}".format(revision), |
| template_path, |
| ], |
| ) |
| |
| api.auto_roller.attempt_roll( |
| gerrit_host=api.gerrit.host_from_remote_url(repo), |
| gerrit_project=repo.split("/", 1)[1], |
| repo_dir=salt_path, |
| commit_message=commit_message, |
| dry_run=dry_run, |
| ) |
| |
| |
| def GenTests(api): |
| yield ( |
| api.status_check.test("update") |
| + api.buildbucket.ci_build( |
| git_repo="https://fuchsia.googlesource.com/infra/salt" |
| ) |
| + api.properties( |
| repo="https://fuchsia.googlesource.com/infra/salt", dry_run=False |
| ) |
| + api.step_data( |
| "load packer template", |
| api.file.read_json( |
| json_content={ |
| "builders": [ |
| { |
| "name": "needs_update", |
| "source_image_family": "bar", |
| "source_image_project_id": "foo", |
| "source_image": "old", |
| } |
| ] |
| } |
| ), |
| ) |
| + api.step_data( |
| "get latest image for foo/bar", |
| stdout=api.json.output({"name": "new"}), |
| retcode=0, |
| ) |
| + api.auto_roller.success() |
| ) |
| |
| yield ( |
| api.status_check.test("get_latest_failure", status="failure") |
| + api.buildbucket.ci_build( |
| git_repo="https://fuchsia.googlesource.com/infra/salt" |
| ) |
| + api.properties( |
| repo="https://fuchsia.googlesource.com/infra/salt", dry_run=False |
| ) |
| + api.step_data( |
| "load packer template", |
| api.file.read_json( |
| json_content={ |
| "builders": [ |
| { |
| "name": "needs_update", |
| "source_image_family": "bar", |
| "source_image_project_id": "foo", |
| "source_image": "old", |
| } |
| ] |
| } |
| ), |
| ) |
| + api.step_data( |
| "get latest image for foo/bar", stdout=api.json.output({}), retcode=1 |
| ) |
| ) |