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/image.py b/api/controller/image.py
index 9099e02..3905da9 100644
--- a/api/controller/image.py
+++ b/api/controller/image.py
@@ -44,12 +44,14 @@
 
 
 @validate.require('build_target.name')
-def Create(input_proto, output_proto):
+@validate.validation_complete
+def Create(input_proto, output_proto, _config):
   """Build an image.
 
   Args:
     input_proto (image_pb2.CreateImageRequest): The input message.
     output_proto (image_pb2.CreateImageResult): The output message.
+    _config (api_config.ApiConfig): The API call config.
   """
   board = input_proto.build_target.name
 
@@ -83,7 +85,7 @@
 
   if not vm_types:
     # No VMs to build, we can exit now.
-    return 0
+    return controller.RETURN_CODE_SUCCESS
 
   # There can be only one.
   vm_type = vm_types.pop()
@@ -161,19 +163,19 @@
     new_image.build_target.name = board
 
 
-@validate.require('build_target.name')
 @validate.exists('image.path')
-def SignerTest(input_proto, output_proto):
+@validate.validation_complete
+def SignerTest(input_proto, output_proto, _config):
   """Run image tests.
 
   Args:
     input_proto (image_pb2.ImageTestRequest): The input message.
     output_proto (image_pb2.ImageTestResult): The output message.
+    _config (api_config.ApiConfig): The API call config.
   """
-  board = input_proto.build_target.name
   image_path = input_proto.image.path
 
-  result = image_lib.SecurityTest(board=board, image=image_path)
+  result = image_lib.SecurityTest(image=image_path)
   output_proto.success = result
   if result:
     return controller.RETURN_CODE_SUCCESS
@@ -182,12 +184,13 @@
 
 @validate.require('build_target.name', 'result.directory')
 @validate.exists('image.path')
-def Test(input_proto, output_proto):
+def Test(input_proto, output_proto, config):
   """Run image tests.
 
   Args:
     input_proto (image_pb2.ImageTestRequest): The input message.
     output_proto (image_pb2.ImageTestResult): The output message.
+    config (api_config.ApiConfig): The API call config.
   """
   image_path = input_proto.image.path
   board = input_proto.build_target.name
@@ -197,6 +200,9 @@
     cros_build_lib.Die(
         'The image.path must be an existing image file with a .bin extension.')
 
+  if config.validate_only:
+    return controller.RETURN_CODE_VALID_INPUT
+
   success = image.Test(board, result_directory, image_dir=image_path)
   output_proto.success = success