sdk: Add BuildSdkTarball and create sdk_version.conf CL in CreateBinhostCLs

This adds the following functionality to the SDK service:

 - A BuildSdkTarball function, which creates a tarball from a previously
   built SDK and returns its path.

 - CreateBinhostCLs now takes an sdk_tarball_template parameter
   and uses it to update
   chromiumos-overlay/chromeos/binhost/host/sdk_version.conf.

The new functionality is required for the build_toolchain recipe
update in crrev.com/c/4102441.

BUG=b:261583133
TEST=./run_tests

Cq-Depend: chromium:4102700
Change-Id: If1e7dbd23a1c0ac66c5b0aa0f8c7ecbd5f44eb30
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4103120
Tested-by: Bob Haarman <inglorion@chromium.org>
Commit-Queue: Bob Haarman <inglorion@chromium.org>
Reviewed-by: Greg Edelston <gredelston@google.com>
diff --git a/api/controller/sdk.py b/api/controller/sdk.py
index cde767f..8c8c469 100644
--- a/api/controller/sdk.py
+++ b/api/controller/sdk.py
@@ -11,6 +11,7 @@
 from chromite.api import faux
 from chromite.api import validate
 from chromite.api.controller import controller_util
+from chromite.api.gen.chromiumos import common_pb2
 from chromite.lib import cros_build_lib
 from chromite.service import sdk
 
@@ -28,6 +29,25 @@
     ]
 
 
+def _BuildSdkTarballResponse(_input_proto, output_proto, _config):
+    """Populate a fake BuildSdkTarballResponse."""
+    output_proto.sdk_tarball_path.path = "/fake/sdk/tarball.tar.gz"
+    output_proto.sdk_tarball_path.location = common_pb2.Path.OUTSIDE
+
+
+@faux.success(_BuildSdkTarballResponse)
+@validate.require("chroot")
+@validate.validation_complete
+def BuildSdkTarball(
+    input_proto: "BuildSdkTarballRequest",
+    output_proto: "BuildSdkTarballResponse",
+    _config: "api_config.ApiConfig",
+) -> None:
+    chroot = controller_util.ParseChroot(input_proto.chroot)
+    output_proto.sdk_tarball_path.path = str(sdk.BuildSdkTarball(chroot))
+    output_proto.sdk_tarball_path.location = common_pb2.Path.OUTSIDE
+
+
 @faux.success(_ChrootVersionResponse)
 @faux.empty_error
 def Create(
@@ -180,7 +200,9 @@
 
 @faux.success(_CLUris)
 @faux.empty_error
-@validate.require("prepend_version", "version", "upload_location")
+@validate.require(
+    "prepend_version", "version", "upload_location", "sdk_tarball_template"
+)
 @validate.validation_complete
 def CreateBinhostCLs(
     input_proto: "CreateBinhostCLsRequest",
@@ -192,8 +214,9 @@
         input_proto.prepend_version,
         input_proto.version,
         input_proto.upload_location,
+        input_proto.sdk_tarball_template,
     )
-    output_proto.cls = uris
+    output_proto.cls.extend(uris)
 
 
 @faux.all_empty