blob: 3a46982337720b2f508fd6ec6481f70551b0a790 [file] [log] [blame]
# 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
)
)