containers: Generate container metadata when requested.

Generate ContainerImageInfo message to a jsonpb file when requested
on the command line.

BUG=b:200473935
TEST=local build_api run

Cq-Depend: chromium:3214703
Change-Id: I502daad3d7bdb90ba50a48f05c996db059e6d3c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/3216859
Tested-by: Sean McAllister <smcallis@google.com>
Commit-Queue: Sean McAllister <smcallis@google.com>
Reviewed-by: Seewai Fu <seewaifu@google.com>
Reviewed-by: Otabek Kasimov <otabek@google.com>
Reviewed-by: Derek Beckett <dbeckett@chromium.org>
diff --git a/src/chromiumos/test/dut/docker/build-dockerimage.sh b/src/chromiumos/test/dut/docker/build-dockerimage.sh
index 7f259b9..efdd9b6 100755
--- a/src/chromiumos/test/dut/docker/build-dockerimage.sh
+++ b/src/chromiumos/test/dut/docker/build-dockerimage.sh
@@ -3,7 +3,16 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-set -e
+set -eE -o functrace
+
+# Print context information in the event of a failure to help debugging.
+failure() {
+  local lineno=$1
+  local msg=$2
+  echo "failed at $lineno: $msg" >&2
+}
+trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
+
 readonly script_dir="$(dirname "$(realpath -e "${BASH_SOURCE[0]}")")"
 
 source "${script_dir}/../../../../../test/docker/util.sh"
@@ -20,6 +29,7 @@
     echo
     echo "Options:"
     echo "  --tags/-t - Comma separated list of tag names to apply to container"
+    echo "  --output/-o - File to which to write ContainerImageInfo jsonproto"
     exit 1
 }
 
@@ -31,12 +41,16 @@
 shift # don't care about sysroot
 
 tags=""
+output=""
 while [[ $# -gt 0 ]]; do
     case $1 in
         --tags|-t)
             tags="$2"
-            shift
-            shift
+            shift 2
+            ;;
+        --output|-o)
+            output="$2"
+            shift 2
             ;;
         *)
             break
@@ -49,4 +63,5 @@
     "${script_dir}/Dockerfile" \
     "${chroot}"                \
     "${tags}"                  \
+    "${output}"                \
     "${@}"
diff --git a/src/chromiumos/test/provision/docker/build-dockerimage.sh b/src/chromiumos/test/provision/docker/build-dockerimage.sh
index adb6f6c..bd1f92a 100755
--- a/src/chromiumos/test/provision/docker/build-dockerimage.sh
+++ b/src/chromiumos/test/provision/docker/build-dockerimage.sh
@@ -3,7 +3,16 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-set -e
+set -eE -o functrace
+
+# Print context information in the event of a failure to help debugging.
+failure() {
+  local lineno=$1
+  local msg=$2
+  echo "failed at $lineno: $msg" >&2
+}
+trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
+
 readonly script_dir="$(dirname "$(realpath -e "${BASH_SOURCE[0]}")")"
 
 source "${script_dir}/../../../../../test/docker/util.sh"
@@ -20,6 +29,7 @@
     echo
     echo "Options:"
     echo "  --tags/-t - Comma separated list of tag names to apply to container"
+    echo "  --output/-o - File to which to write ContainerImageInfo jsonproto"
     exit 1
 }
 
@@ -31,12 +41,16 @@
 shift # don't care about sysroot
 
 tags=""
+output=""
 while [[ $# -gt 0 ]]; do
     case $1 in
         --tags|-t)
             tags="$2"
-            shift
-            shift
+            shift 2
+            ;;
+        --output|-o)
+            output="$2"
+            shift 2
             ;;
         *)
             break
@@ -45,8 +59,9 @@
 done
 
 build_server_image             \
-    "cros-provision"          \
+    "cros-provision"           \
     "${script_dir}/Dockerfile" \
     "${chroot}"                \
     "${tags}"                  \
+    "${output}"                \
     "${@}"
diff --git a/test/container/utils/build-dockerimage.sh b/test/container/utils/build-dockerimage.sh
index bab5c1c..f822d75 100755
--- a/test/container/utils/build-dockerimage.sh
+++ b/test/container/utils/build-dockerimage.sh
@@ -3,7 +3,15 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-set -e
+set -eE -o functrace
+
+# Print context information in the event of a failure to help debugging.
+failure() {
+  local lineno=$1
+  local msg=$2
+  echo "failed at $lineno: $msg" >&2
+}
+trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
 
 script_dir="$(dirname "$(realpath -e "${BASH_SOURCE[0]}")")"
 readonly script_dir
@@ -20,6 +28,7 @@
     echo
     echo "Options:"
     echo "  --tags/-t - Comma separated list of tag names to apply to container"
+    echo "  --output/-o - File to which to write ContainerImageInfo jsonproto"
     exit 1
 }
 
@@ -48,12 +57,16 @@
 readonly sysroot_path="$1"; shift
 
 tags=""
+output=""
 while [[ $# -gt 0 ]]; do
     case $1 in
         --tags|-t)
             tags="$2"
-            shift
-            shift
+            shift 2
+            ;;
+        --output|-o)
+            output="$2"
+            shift 2
             ;;
         *)
             break
@@ -75,4 +88,5 @@
     "${full_output_dir}/Dockerfile" \
     "${chroot_path}"                \
     "${tags}"                       \
+    "${output}"                     \
     "$@"
diff --git a/test/docker/util.sh b/test/docker/util.sh
index cce5bba..161d83a 100644
--- a/test/docker/util.sh
+++ b/test/docker/util.sh
@@ -18,12 +18,15 @@
   #   $2:  Dockerfile path for the build
   #   $3:  (optional) chroot path
   #   $4:  (optional) tags
-  #   $5+: (optional) labels
+  #   $5:  (optional) output file for metadata
+  #   $6+: (optional) labels
   [[ $# -lt 3 ]] && die "${FUNCNAME[0]}: Server name and Dockerfile path required"
-  server_name="$1"; shift
-  docker_file="$1"; shift
-  chroot_arg="$1"; shift
-  tags="$1"; shift
+  server_name="$1"
+  docker_file="$2"
+  chroot_arg="$3"
+  tags="$4"
+  output_path="$5"
+  shift 5
 
   # Aggregate rest of CLI arguments as labels into an array
   labels=( "$@" )
@@ -68,15 +71,15 @@
   args=(-f "${docker_file}")
 
   # Map tags into -t options
+  ntag=0
   IFS=,
   for tag in $tags; do
-      echo "tag: ${tag}"
+      ntag="$((ntag+1))"
       args+=(-t "${image_path}:${tag}")
   done
 
   # Map labels into --label options
   for label in "${labels[@]}"; do
-      echo "label: ${label}"
       args+=(--label "${label:Q}")
   done
   args+=("${build_context}")
@@ -87,6 +90,42 @@
   # Push image to register
   sudo docker login -u oauth2accesstoken -p "$(gcloud auth print-access-token)" "https://${registry_name}"
   sudo docker push --all-tags "${image_path}"
+
+  # write output if requested
+  if [[ -n "$output_path" ]]; then
+    local digest
+    digest=$(docker inspect --format='{{index .RepoDigests 0}}' "$image_path:${tag[0]}" \
+                 | cut -d: -f2 )
+
+    cat <<EOF > "$output_path"
+{
+    "repository" : {
+       "hostname": "$registry_name",
+       "project" : "$cloud_project"
+    },
+    "name" : "$image_name",
+    "digest" : "$digest",
+    "tags" : [
+EOF
+
+    ii=0
+    local tag_block=""
+    IFS=,
+    for tag in $tags; do
+        tag_block+="      \"$tag\""
+
+        ii="$((ii+1))"
+        if [[ $ii -lt $ntag ]]; then
+          tag_block+=",\n"
+        fi
+    done
+    echo -e "${tag_block}" >> "$output_path"
+
+    cat <<EOF >> "$output_path"
+    ]
+}
+EOF
+  fi
 }