Build API: Implement validate_only calls.
Add validate-only support to all existing endpoints and
tests to enforce the setting is respected.
Add is_in validator to help transition some endpoints
to decorator-only validation.
Some cleanup and standardization in the controller tests.
BUG=chromium:987263
TEST=run_tests
Cq-Depend: chromium:1726252
Change-Id: I108dfc1a221847eae47a18f2f60e12d2575c9ea8
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1726253
Reviewed-by: David Burger <dburger@chromium.org>
Commit-Queue: Alex Klein <saklein@chromium.org>
Tested-by: Alex Klein <saklein@chromium.org>
diff --git a/api/controller/artifacts.py b/api/controller/artifacts.py
index 446d2a3..e16b7c0 100644
--- a/api/controller/artifacts.py
+++ b/api/controller/artifacts.py
@@ -9,6 +9,7 @@
import os
+from chromite.api import controller
from chromite.api import validate
from chromite.api.controller import controller_util
from chromite.cbuildbot import commands
@@ -44,26 +45,34 @@
@validate.require('build_target.name', 'output_dir')
-def BundleImageZip(input_proto, output_proto):
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundleImageZip(input_proto, output_proto, _config):
"""Bundle image.zip.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ _config (api_config.ApiConfig): The API call config.
"""
target = input_proto.build_target.name
output_dir = input_proto.output_dir
image_dir = _GetImageDir(constants.SOURCE_ROOT, target)
+
archive = artifacts.BundleImageZip(output_dir, image_dir)
output_proto.artifacts.add().path = os.path.join(output_dir, archive)
-def BundleTestUpdatePayloads(input_proto, output_proto):
+@validate.require('build_target.name', 'output_dir')
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundleTestUpdatePayloads(input_proto, output_proto, _config):
"""Generate minimal update payloads for the build target for testing.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ _config (api_config.ApiConfig): The API call config.
"""
target = input_proto.build_target.name
output_dir = input_proto.output_dir
@@ -88,17 +97,17 @@
output_proto.artifacts.add().path = payload
-def BundleAutotestFiles(input_proto, output_proto):
+@validate.require('output_dir')
+@validate.exists('output_dir')
+def BundleAutotestFiles(input_proto, output_proto, config):
"""Tar the autotest files for a build target.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ config (api_config.ApiConfig): The API call config.
"""
output_dir = input_proto.output_dir
- if not output_dir:
- cros_build_lib.Die('output_dir is required.')
-
target = input_proto.build_target.name
if target:
# Legacy call, build out sysroot path from default source root and the
@@ -121,6 +130,11 @@
sysroot = sysroot_lib.Sysroot(os.path.join(chroot.path,
sysroot_path.lstrip(os.sep)))
+ # TODO(saklein): Switch to the validate_only decorator when legacy handling
+ # is removed.
+ if config.validate_only:
+ return controller.RETURN_CODE_VALID_INPUT
+
if not sysroot.Exists():
cros_build_lib.Die('Sysroot path must exist: %s', sysroot.path)
@@ -135,12 +149,14 @@
@validate.require('output_dir')
-def BundleTastFiles(input_proto, output_proto):
+@validate.exists('output_dir')
+def BundleTastFiles(input_proto, output_proto, config):
"""Tar the tast files for a build target.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ config (api_config.ApiConfig): The API call config.
"""
target = input_proto.build_target.name
output_dir = input_proto.output_dir
@@ -160,8 +176,13 @@
if not sysroot_path:
cros_build_lib.Die('sysroot.path is required.')
+ # TODO(saklein): Switch to the validation_complete decorator when legacy
+ # handling is removed.
+ if config.validate_only:
+ return controller.RETURN_CODE_VALID_INPUT
+
sysroot = sysroot_lib.Sysroot(sysroot_path)
- if not sysroot.Exists(chroot):
+ if not sysroot.Exists(chroot=chroot):
cros_build_lib.Die('Sysroot must exist.')
archive = artifacts.BundleTastFiles(chroot, sysroot, output_dir)
@@ -174,12 +195,16 @@
output_proto.artifacts.add().path = archive
-def BundlePinnedGuestImages(input_proto, output_proto):
+@validate.require('build_target.name', 'output_dir')
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundlePinnedGuestImages(input_proto, output_proto, _config):
"""Tar the pinned guest images for a build target.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ _config (api_config.ApiConfig): The API call config.
"""
target = input_proto.build_target.name
output_dir = input_proto.output_dir
@@ -196,19 +221,18 @@
output_proto.artifacts.add().path = os.path.join(output_dir, archive)
-def FetchPinnedGuestImages(input_proto, output_proto):
+@validate.require('sysroot.path')
+@validate.validation_complete
+def FetchPinnedGuestImages(input_proto, output_proto, _config):
"""Get the pinned guest image information."""
sysroot_path = input_proto.sysroot.path
- if not sysroot_path:
- cros_build_lib.Die('sysroot.path is required.')
chroot = controller_util.ParseChroot(input_proto.chroot)
sysroot = sysroot_lib.Sysroot(sysroot_path)
if not chroot.exists():
cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
-
- if not sysroot.Exists(chroot=chroot):
+ elif not sysroot.Exists(chroot=chroot):
cros_build_lib.Die('Sysroot does not exist: %s',
chroot.full_path(sysroot.path))
@@ -221,17 +245,27 @@
@validate.require('output_dir', 'sysroot.path')
-def BundleFirmware(input_proto, output_proto):
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundleFirmware(input_proto, output_proto, _config):
"""Tar the firmware images for a build target.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ _config (api_config.ApiConfig): The API call config.
"""
output_dir = input_proto.output_dir
chroot = controller_util.ParseChroot(input_proto.chroot)
sysroot_path = input_proto.sysroot.path
sysroot = sysroot_lib.Sysroot(sysroot_path)
+
+ if not chroot.exists():
+ cros_build_lib.Die('Chroot does not exist: %s', chroot.path)
+ elif not sysroot.Exists(chroot=chroot):
+ cros_build_lib.Die('Sysroot does not exist: %s',
+ chroot.full_path(sysroot.path))
+
archive = artifacts.BuildFirmwareArchive(chroot, sysroot, output_dir)
if archive is None:
@@ -239,16 +273,17 @@
'Could not create firmware archive. No firmware found for %s.',
sysroot_path)
- output_proto.artifacts.add().path = os.path.join(output_dir, archive)
+ output_proto.artifacts.add().path = archive
@validate.exists('output_dir')
-def BundleEbuildLogs(input_proto, output_proto):
+def BundleEbuildLogs(input_proto, output_proto, config):
"""Tar the ebuild logs for a build target.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ config (api_config.ApiConfig): The API call config.
"""
output_dir = input_proto.output_dir
sysroot_path = input_proto.sysroot.path
@@ -262,6 +297,11 @@
chroot.path = os.path.join(build_root, 'chroot')
sysroot_path = os.path.join('/build', target)
+ # TODO(saklein): Switch to validation_complete decorator after legacy
+ # handling has been cleaned up.
+ if config.validate_only:
+ return controller.RETURN_CODE_VALID_INPUT
+
sysroot = sysroot_lib.Sysroot(sysroot_path)
archive = artifacts.BundleEBuildLogsTarball(chroot, sysroot, output_dir)
if archive is None:
@@ -271,22 +311,16 @@
output_proto.artifacts.add().path = os.path.join(output_dir, archive)
-def BundleSimpleChromeArtifacts(input_proto, output_proto):
+@validate.require('output_dir', 'sysroot.build_target.name', 'sysroot.path')
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundleSimpleChromeArtifacts(input_proto, output_proto, _config):
"""Create the simple chrome artifacts."""
# Required args.
sysroot_path = input_proto.sysroot.path
build_target_name = input_proto.sysroot.build_target.name
output_dir = input_proto.output_dir
- if not build_target_name:
- cros_build_lib.Die('build_target.name is required')
- if not output_dir:
- cros_build_lib.Die('output_dir is required.')
- if not os.path.exists(output_dir):
- cros_build_lib.Die('output_dir (%s) does not exist.', output_dir)
- if not sysroot_path:
- cros_build_lib.Die('sysroot.path is required.')
-
# Optional args.
chroot_path = input_proto.chroot.path or constants.DEFAULT_CHROOT_PATH
cache_dir = input_proto.chroot.cache_dir
@@ -314,12 +348,15 @@
@validate.require('chroot.path', 'test_results_dir', 'output_dir')
-def BundleVmFiles(input_proto, output_proto):
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundleVmFiles(input_proto, output_proto, _config):
"""Tar VM disk and memory files.
Args:
input_proto (SysrootBundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ _config (api_config.ApiConfig): The API call config.
"""
chroot = controller_util.ParseChroot(input_proto.chroot)
test_results_dir = input_proto.test_results_dir
@@ -330,29 +367,27 @@
for archive in archives:
output_proto.artifacts.add().path = archive
-def BundleOrderfileGenerationArtifacts(input_proto, output_proto):
+
+@validate.require('build_target.name', 'output_dir')
+@validate.exists('output_dir')
+@validate.validation_complete
+def BundleOrderfileGenerationArtifacts(input_proto, output_proto, _config):
"""Create tarballs of all the artifacts of orderfile_generate builder.
Args:
input_proto (BundleRequest): The input proto.
output_proto (BundleResponse): The output proto.
+ _config (api_config.ApiConfig): The API call config.
"""
# Required args.
- build_target_name = input_proto.build_target.name
+ build_target = build_target_util.BuildTarget(input_proto.build_target.name)
output_dir = input_proto.output_dir
- if not build_target_name:
- cros_build_lib.Die('build_target.name is required.')
- if not output_dir:
- cros_build_lib.Die('output_dir is required.')
- elif not os.path.isdir(output_dir):
- cros_build_lib.Die('output_dir does not exist.')
-
chroot = controller_util.ParseChroot(input_proto.chroot)
try:
results = artifacts.BundleOrderfileGenerationArtifacts(
- chroot, input_proto.build_target, output_dir)
+ chroot, build_target, output_dir)
except artifacts.Error as e:
cros_build_lib.Die('Error %s raised in BundleSimpleChromeArtifacts: %s',
type(e), e)