summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2020-01-22 10:38:03 -0800
committergVisor bot <gvisor-bot@google.com>2020-01-22 10:39:45 -0800
commitcb3906ae00575859a6910b8edc62ab9d531d1c85 (patch)
tree2dcb1dfd4f7f3d400682b74fa036c43c0f54871a
parent6a59e7f510a7b12f8b3bd768dfe569033ef07d30 (diff)
Add tools for generating images.
This formalizes the adhoc scripts previously in kokoro. The image targets can be used by e.g. benchmarks in order to automated image prepation. PiperOrigin-RevId: 290982744
-rw-r--r--kokoro/ubuntu1604/README.md34
l---------kokoro/ubuntu1804/10_core.sh1
l---------kokoro/ubuntu1804/20_bazel.sh1
l---------kokoro/ubuntu1804/25_docker.sh1
l---------kokoro/ubuntu1804/30_containerd.sh1
l---------kokoro/ubuntu1804/40_kokoro.sh1
-rw-r--r--tools/images/BUILD68
-rwxr-xr-xtools/images/build.sh101
-rw-r--r--tools/images/defs.bzl178
-rwxr-xr-xtools/images/execute.sh152
-rw-r--r--tools/images/test.cc23
-rwxr-xr-xtools/images/ubuntu1604/10_core.sh (renamed from kokoro/ubuntu1604/10_core.sh)0
-rwxr-xr-xtools/images/ubuntu1604/20_bazel.sh (renamed from kokoro/ubuntu1604/20_bazel.sh)0
-rwxr-xr-xtools/images/ubuntu1604/25_docker.sh (renamed from kokoro/ubuntu1604/25_docker.sh)0
-rwxr-xr-xtools/images/ubuntu1604/30_containerd.sh (renamed from kokoro/ubuntu1604/30_containerd.sh)0
-rwxr-xr-xtools/images/ubuntu1604/40_kokoro.sh (renamed from kokoro/ubuntu1604/40_kokoro.sh)0
-rw-r--r--tools/images/ubuntu1604/BUILD7
-rw-r--r--tools/images/ubuntu1804/BUILD7
-rw-r--r--tools/installers/BUILD22
-rwxr-xr-xtools/installers/head.sh (renamed from kokoro/ubuntu1604/build.sh)7
-rwxr-xr-xtools/installers/master.sh (renamed from kokoro/ubuntu1804/build.sh)8
-rwxr-xr-xtools/installers/shim.sh24
22 files changed, 590 insertions, 46 deletions
diff --git a/kokoro/ubuntu1604/README.md b/kokoro/ubuntu1604/README.md
deleted file mode 100644
index 64f913b9a..000000000
--- a/kokoro/ubuntu1604/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-## Image Update
-
-After making changes to files in the directory, you must run the following
-commands to update the image Kokoro uses:
-
-```shell
-gcloud config set project gvisor-kokoro-testing
-third_party/gvisor/kokoro/ubuntu1604/build.sh
-third_party/gvisor/kokoro/ubuntu1804/build.sh
-```
-
-Note: the command above will change your default project for `gcloud`. Run
-`gcloud config set project` again to revert back to your default project.
-
-Note: Files in `third_party/gvisor/kokoro/ubuntu1804/` as symlinks to
-`ubuntu1604`, therefore both images must be updated.
-
-After the script finishes, the last few lines of the output will container the
-image name. If the output was lost, you can run `build.sh` again to print the
-image name.
-
-```
-NAME PROJECT FAMILY DEPRECATED STATUS
-image-6777fa4666a968c8 gvisor-kokoro-testing READY
-+ cleanup
-+ gcloud compute instances delete --quiet build-tlfrdv
-Deleted [https://www.googleapis.com/compute/v1/projects/gvisor-kokoro-testing/zones/us-central1-f/instances/build-tlfrdv].
-```
-
-To setup Kokoro to use the new image, copy the image names to their
-corresponding file below:
-
-* //devtools/kokoro/config/gcp/gvisor/ubuntu1604.gcl
-* //devtools/kokoro/config/gcp/gvisor/ubuntu1804.gcl
diff --git a/kokoro/ubuntu1804/10_core.sh b/kokoro/ubuntu1804/10_core.sh
deleted file mode 120000
index 6facceeee..000000000
--- a/kokoro/ubuntu1804/10_core.sh
+++ /dev/null
@@ -1 +0,0 @@
-../ubuntu1604/10_core.sh \ No newline at end of file
diff --git a/kokoro/ubuntu1804/20_bazel.sh b/kokoro/ubuntu1804/20_bazel.sh
deleted file mode 120000
index 39194c0f5..000000000
--- a/kokoro/ubuntu1804/20_bazel.sh
+++ /dev/null
@@ -1 +0,0 @@
-../ubuntu1604/20_bazel.sh \ No newline at end of file
diff --git a/kokoro/ubuntu1804/25_docker.sh b/kokoro/ubuntu1804/25_docker.sh
deleted file mode 120000
index 63269bd83..000000000
--- a/kokoro/ubuntu1804/25_docker.sh
+++ /dev/null
@@ -1 +0,0 @@
-../ubuntu1604/25_docker.sh \ No newline at end of file
diff --git a/kokoro/ubuntu1804/30_containerd.sh b/kokoro/ubuntu1804/30_containerd.sh
deleted file mode 120000
index 6ac2377ed..000000000
--- a/kokoro/ubuntu1804/30_containerd.sh
+++ /dev/null
@@ -1 +0,0 @@
-../ubuntu1604/30_containerd.sh \ No newline at end of file
diff --git a/kokoro/ubuntu1804/40_kokoro.sh b/kokoro/ubuntu1804/40_kokoro.sh
deleted file mode 120000
index e861fb5e1..000000000
--- a/kokoro/ubuntu1804/40_kokoro.sh
+++ /dev/null
@@ -1 +0,0 @@
-../ubuntu1604/40_kokoro.sh \ No newline at end of file
diff --git a/tools/images/BUILD b/tools/images/BUILD
new file mode 100644
index 000000000..2b77c2737
--- /dev/null
+++ b/tools/images/BUILD
@@ -0,0 +1,68 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary")
+load("//tools/images:defs.bzl", "vm_image", "vm_test")
+
+package(
+ default_visibility = ["//:sandbox"],
+ licenses = ["notice"],
+)
+
+genrule(
+ name = "zone",
+ outs = ["zone.txt"],
+ cmd = "gcloud config get-value compute/zone > $@",
+ tags = [
+ "local",
+ "manual",
+ ],
+)
+
+sh_binary(
+ name = "builder",
+ srcs = ["build.sh"],
+)
+
+sh_binary(
+ name = "executer",
+ srcs = ["execute.sh"],
+)
+
+cc_binary(
+ name = "test",
+ testonly = 1,
+ srcs = ["test.cc"],
+ linkstatic = 1,
+ deps = [
+ "//test/util:test_main",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+vm_image(
+ name = "ubuntu1604",
+ family = "ubuntu-1604-lts",
+ project = "ubuntu-os-cloud",
+ scripts = [
+ "//tools/images/ubuntu1604",
+ ],
+)
+
+vm_test(
+ name = "ubuntu1604_test",
+ image = ":ubuntu1604",
+ targets = [":test"],
+)
+
+vm_image(
+ name = "ubuntu1804",
+ family = "ubuntu-1804-lts",
+ project = "ubuntu-os-cloud",
+ scripts = [
+ "//tools/images/ubuntu1804",
+ ],
+)
+
+vm_test(
+ name = "ubuntu1804_test",
+ image = ":ubuntu1804",
+ targets = [":test"],
+)
diff --git a/tools/images/build.sh b/tools/images/build.sh
new file mode 100755
index 000000000..be462d556
--- /dev/null
+++ b/tools/images/build.sh
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+# Copyright 2019 The gVisor Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script is responsible for building a new GCP image that: 1) has nested
+# virtualization enabled, and 2) has been completely set up with the
+# image_setup.sh script. This script should be idempotent, as we memoize the
+# setup script with a hash and check for that name.
+
+set -xeou pipefail
+
+# Parameters.
+declare -r USERNAME=${USERNAME:-test}
+declare -r IMAGE_PROJECT=${IMAGE_PROJECT:-ubuntu-os-cloud}
+declare -r IMAGE_FAMILY=${IMAGE_FAMILY:-ubuntu-1604-lts}
+declare -r ZONE=${ZONE:-us-central1-f}
+
+# Random names.
+declare -r DISK_NAME=$(mktemp -u disk-XXXXXX | tr A-Z a-z)
+declare -r SNAPSHOT_NAME=$(mktemp -u snapshot-XXXXXX | tr A-Z a-z)
+declare -r INSTANCE_NAME=$(mktemp -u build-XXXXXX | tr A-Z a-z)
+
+# Hash inputs in order to memoize the produced image.
+declare -r SETUP_HASH=$( (echo ${USERNAME} ${IMAGE_PROJECT} ${IMAGE_FAMILY} && cat "$@") | sha256sum - | cut -d' ' -f1 | cut -c 1-16)
+declare -r IMAGE_NAME=${IMAGE_FAMILY:-image-}${SETUP_HASH}
+
+# Does the image already exist? Skip the build.
+declare -r existing=$(gcloud compute images list --filter="name=(${IMAGE_NAME})" --format="value(name)")
+if ! [[ -z "${existing}" ]]; then
+ echo "${existing}"
+ exit 0
+fi
+
+# gcloud has path errors; is this a result of being a genrule?
+export PATH=${PATH:-/bin:/usr/bin:/usr/local/bin}
+
+# Start a unique instance. Note that this instance will have a unique persistent
+# disk as it's boot disk with the same name as the instance.
+gcloud compute instances create \
+ --quiet \
+ --image-project "${IMAGE_PROJECT}" \
+ --image-family "${IMAGE_FAMILY}" \
+ --boot-disk-size "200GB" \
+ --zone "${ZONE}" \
+ "${INSTANCE_NAME}" >/dev/null
+function cleanup {
+ gcloud compute instances delete --quiet --zone "${ZONE}" "${INSTANCE_NAME}"
+}
+trap cleanup EXIT
+
+# Wait for the instance to become available (up to 5 minutes).
+declare timeout=300
+declare success=0
+declare -r start=$(date +%s)
+declare -r end=$((${start}+${timeout}))
+while [[ "$(date +%s)" -lt "${end}" ]] && [[ "${success}" -lt 3 ]]; do
+ if gcloud compute ssh --zone "${ZONE}" "${USERNAME}"@"${INSTANCE_NAME}" -- env - true 2>/dev/null; then
+ success=$((${success}+1))
+ fi
+done
+if [[ "${success}" -eq "0" ]]; then
+ echo "connect timed out after ${timeout} seconds."
+ exit 1
+fi
+
+# Run the install scripts provided.
+for arg; do
+ gcloud compute ssh --zone "${ZONE}" "${USERNAME}"@"${INSTANCE_NAME}" -- sudo bash - <"${arg}" >/dev/null
+done
+
+# Stop the instance; required before creating an image.
+gcloud compute instances stop --quiet --zone "${ZONE}" "${INSTANCE_NAME}" >/dev/null
+
+# Create a snapshot of the instance disk.
+gcloud compute disks snapshot \
+ --quiet \
+ --zone "${ZONE}" \
+ --snapshot-names="${SNAPSHOT_NAME}" \
+ "${INSTANCE_NAME}" >/dev/null
+
+# Create the disk image.
+gcloud compute images create \
+ --quiet \
+ --source-snapshot="${SNAPSHOT_NAME}" \
+ --licenses="https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx" \
+ "${IMAGE_NAME}" >/dev/null
+
+# Finish up.
+echo "${IMAGE_NAME}"
diff --git a/tools/images/defs.bzl b/tools/images/defs.bzl
new file mode 100644
index 000000000..d8e422a5d
--- /dev/null
+++ b/tools/images/defs.bzl
@@ -0,0 +1,178 @@
+"""Image configuration.
+
+Images can be generated by using the vm_image rule. For example,
+
+ vm_image(
+ name = "ubuntu",
+ project = "...",
+ family = "...",
+ scripts = [
+ "script.sh",
+ "other.sh",
+ ],
+ )
+
+This will always create an vm_image in the current default gcloud project. The
+rule has a text file as its output containing the image name. This will enforce
+serialization for all dependent rules.
+
+Images are always named per the hash of all the hermetic input scripts. This
+allows images to be memoized quickly and easily.
+
+The vm_test rule can be used to execute a command remotely. For example,
+
+ vm_test(
+ name = "mycommand",
+ image = ":myimage",
+ targets = [":test"],
+ )
+"""
+
+def _vm_image_impl(ctx):
+ script_paths = []
+ for script in ctx.files.scripts:
+ script_paths.append(script.short_path)
+
+ resolved_inputs, argv, runfiles_manifests = ctx.resolve_command(
+ command = "USERNAME=%s ZONE=$(cat %s) IMAGE_PROJECT=%s IMAGE_FAMILY=%s %s %s > %s" %
+ (
+ ctx.attr.username,
+ ctx.files.zone[0].path,
+ ctx.attr.project,
+ ctx.attr.family,
+ ctx.executable.builder.path,
+ " ".join(script_paths),
+ ctx.outputs.out.path,
+ ),
+ tools = [ctx.attr.builder] + ctx.attr.scripts,
+ )
+
+ ctx.actions.run_shell(
+ tools = resolved_inputs,
+ outputs = [ctx.outputs.out],
+ progress_message = "Building image...",
+ execution_requirements = {"local": "true"},
+ command = argv,
+ input_manifests = runfiles_manifests,
+ )
+ return [DefaultInfo(files = depset([ctx.outputs.out]))]
+
+_vm_image = rule(
+ attrs = {
+ "builder": attr.label(
+ executable = True,
+ default = "//tools/images:builder",
+ cfg = "host",
+ ),
+ "username": attr.string(default = "$(whoami)"),
+ "zone": attr.label(
+ default = "//tools/images:zone",
+ cfg = "host",
+ ),
+ "family": attr.string(mandatory = True),
+ "project": attr.string(mandatory = True),
+ "scripts": attr.label_list(allow_files = True),
+ },
+ outputs = {
+ "out": "%{name}.txt",
+ },
+ implementation = _vm_image_impl,
+)
+
+def vm_image(**kwargs):
+ _vm_image(
+ tags = [
+ "local",
+ "manual",
+ ],
+ **kwargs
+ )
+
+def _vm_test_impl(ctx):
+ runner = ctx.actions.declare_file("%s-executer" % ctx.label.name)
+
+ # Note that the remote execution case must actually generate an
+ # intermediate target in order to collect all the relevant runfiles so that
+ # they can be copied over for remote execution.
+ runner_content = "\n".join([
+ "#!/bin/bash",
+ "export ZONE=$(cat %s)" % ctx.files.zone[0].short_path,
+ "export USERNAME=%s" % ctx.attr.username,
+ "export IMAGE=$(cat %s)" % ctx.files.image[0].short_path,
+ "export SUDO=%s" % "true" if ctx.attr.sudo else "false",
+ "%s %s" % (
+ ctx.executable.executer.short_path,
+ " ".join([
+ target.files_to_run.executable.short_path
+ for target in ctx.attr.targets
+ ]),
+ ),
+ "",
+ ])
+ ctx.actions.write(runner, runner_content, is_executable = True)
+
+ # Return with all transitive files.
+ runfiles = ctx.runfiles(
+ transitive_files = depset(transitive = [
+ depset(target.data_runfiles.files)
+ for target in ctx.attr.targets
+ if hasattr(target, "data_runfiles")
+ ]),
+ files = ctx.files.executer + ctx.files.zone + ctx.files.image +
+ ctx.files.targets,
+ collect_default = True,
+ collect_data = True,
+ )
+ return [DefaultInfo(executable = runner, runfiles = runfiles)]
+
+_vm_test = rule(
+ attrs = {
+ "image": attr.label(
+ mandatory = True,
+ cfg = "host",
+ ),
+ "executer": attr.label(
+ executable = True,
+ default = "//tools/images:executer",
+ cfg = "host",
+ ),
+ "username": attr.string(default = "$(whoami)"),
+ "zone": attr.label(
+ default = "//tools/images:zone",
+ cfg = "host",
+ ),
+ "sudo": attr.bool(default = True),
+ "machine": attr.string(default = "n1-standard-1"),
+ "targets": attr.label_list(
+ mandatory = True,
+ allow_empty = False,
+ cfg = "target",
+ ),
+ },
+ test = True,
+ implementation = _vm_test_impl,
+)
+
+def vm_test(
+ installer = "//tools/installers:head",
+ **kwargs):
+ """Runs the given targets as a remote test.
+
+ Args:
+ installer: Script to run before all targets.
+ **kwargs: All test arguments. Should include targets and image.
+ """
+ targets = kwargs.pop("targets", [])
+ if installer:
+ targets = [installer] + targets
+ targets = [
+ ] + targets
+ _vm_test(
+ tags = [
+ "local",
+ "manual",
+ ],
+ targets = targets,
+ local = 1,
+ **kwargs
+ )
diff --git a/tools/images/execute.sh b/tools/images/execute.sh
new file mode 100755
index 000000000..ba4b1ac0e
--- /dev/null
+++ b/tools/images/execute.sh
@@ -0,0 +1,152 @@
+#!/bin/bash
+
+# Copyright 2019 The gVisor Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -xeo pipefail
+
+# Required input.
+if ! [[ -v IMAGE ]]; then
+ echo "no image provided: set IMAGE."
+ exit 1
+fi
+
+# Parameters.
+declare -r USERNAME=${USERNAME:-test}
+declare -r KEYNAME=$(mktemp --tmpdir -u key-XXXXXX)
+declare -r SSHKEYS=$(mktemp --tmpdir -u sshkeys-XXXXXX)
+declare -r INSTANCE_NAME=$(mktemp -u test-XXXXXX | tr A-Z a-z)
+declare -r MACHINE=${MACHINE:-n1-standard-1}
+declare -r ZONE=${ZONE:-us-central1-f}
+declare -r SUDO=${SUDO:-false}
+
+# This script is executed as a test rule, which will reset the value of HOME.
+# Unfortunately, it is needed to load the gconfig credentials. We will reset
+# HOME when we actually execute in the remote environment, defined below.
+export HOME=$(eval echo ~$(whoami))
+
+# Generate unique keys for this test.
+[[ -f "${KEYNAME}" ]] || ssh-keygen -t rsa -N "" -f "${KEYNAME}" -C "${USERNAME}"
+cat > "${SSHKEYS}" <<EOF
+${USERNAME}:$(cat ${KEYNAME}.pub)
+EOF
+
+# Start a unique instance. This means that we first generate a unique set of ssh
+# keys to ensure that only we have access to this instance. Note that we must
+# constrain ourselves to Haswell or greater in order to have nested
+# virtualization available.
+gcloud compute instances create \
+ --min-cpu-platform "Intel Haswell" \
+ --preemptible \
+ --no-scopes \
+ --metadata block-project-ssh-keys=TRUE \
+ --metadata-from-file ssh-keys="${SSHKEYS}" \
+ --machine-type "${MACHINE}" \
+ --image "${IMAGE}" \
+ --zone "${ZONE}" \
+ "${INSTANCE_NAME}"
+function cleanup {
+ gcloud compute instances delete --quiet --zone "${ZONE}" "${INSTANCE_NAME}"
+}
+trap cleanup EXIT
+
+# Wait for the instance to become available (up to 5 minutes).
+declare timeout=300
+declare success=0
+declare -r start=$(date +%s)
+declare -r end=$((${start}+${timeout}))
+while [[ "$(date +%s)" -lt "${end}" ]] && [[ "${success}" -lt 3 ]]; do
+ if gcloud compute ssh --ssh-key-file="${KEYNAME}" --zone "${ZONE}" "${USERNAME}"@"${INSTANCE_NAME}" -- true 2>/dev/null; then
+ success=$((${success}+1))
+ fi
+done
+if [[ "${success}" -eq "0" ]]; then
+ echo "connect timed out after ${timeout} seconds."
+ exit 1
+fi
+
+# Copy the local directory over.
+tar czf - --dereference --exclude=.git . |
+ gcloud compute ssh \
+ --ssh-key-file="${KEYNAME}" \
+ --zone "${ZONE}" \
+ "${USERNAME}"@"${INSTANCE_NAME}" -- tar xzf -
+
+# Execute the command remotely.
+for cmd; do
+ # Setup relevant environment.
+ #
+ # N.B. This is not a complete test environment, but is complete enough to
+ # provide rudimentary sharding and test output support.
+ declare -a PREFIX=( "env" )
+ if [[ -v TEST_SHARD_INDEX ]]; then
+ PREFIX+=( "TEST_SHARD_INDEX=${TEST_SHARD_INDEX}" )
+ fi
+ if [[ -v TEST_SHARD_STATUS_FILE ]]; then
+ SHARD_STATUS_FILE=$(mktemp -u test-shard-status-XXXXXX)
+ PREFIX+=( "TEST_SHARD_STATUS_FILE=/tmp/${SHARD_STATUS_FILE}" )
+ fi
+ if [[ -v TEST_TOTAL_SHARDS ]]; then
+ PREFIX+=( "TEST_TOTAL_SHARDS=${TEST_TOTAL_SHARDS}" )
+ fi
+ if [[ -v TEST_TMPDIR ]]; then
+ REMOTE_TMPDIR=$(mktemp -u test-XXXXXX)
+ PREFIX+=( "TEST_TMPDIR=/tmp/${REMOTE_TMPDIR}" )
+ # Create remotely.
+ gcloud compute ssh \
+ --ssh-key-file="${KEYNAME}" \
+ --zone "${ZONE}" \
+ "${USERNAME}"@"${INSTANCE_NAME}" -- \
+ mkdir -p "/tmp/${REMOTE_TMPDIR}"
+ fi
+ if [[ -v XML_OUTPUT_FILE ]]; then
+ TEST_XML_OUTPUT=$(mktemp -u xml-output-XXXXXX)
+ PREFIX+=( "XML_OUTPUT_FILE=/tmp/${TEST_XML_OUTPUT}" )
+ fi
+ if [[ "${SUDO}" == "true" ]]; then
+ PREFIX+=( "sudo" "-E" )
+ fi
+
+ # Execute the command.
+ gcloud compute ssh \
+ --ssh-key-file="${KEYNAME}" \
+ --zone "${ZONE}" \
+ "${USERNAME}"@"${INSTANCE_NAME}" -- \
+ "${PREFIX[@]}" "${cmd}"
+
+ # Collect relevant results.
+ if [[ -v TEST_SHARD_STATUS_FILE ]]; then
+ gcloud compute scp \
+ --ssh-key-file="${KEYNAME}" \
+ --zone "${ZONE}" \
+ "${USERNAME}"@"${INSTANCE_NAME}":/tmp/"${SHARD_STATUS_FILE}" \
+ "${TEST_SHARD_STATUS_FILE}" 2>/dev/null || true # Allowed to fail.
+ fi
+ if [[ -v XML_OUTPUT_FILE ]]; then
+ gcloud compute scp \
+ --ssh-key-file="${KEYNAME}" \
+ --zone "${ZONE}" \
+ "${USERNAME}"@"${INSTANCE_NAME}":/tmp/"${TEST_XML_OUTPUT}" \
+ "${XML_OUTPUT_FILE}" 2>/dev/null || true # Allowed to fail.
+ fi
+
+ # Clean up the temporary directory.
+ if [[ -v TEST_TMPDIR ]]; then
+ gcloud compute ssh \
+ --ssh-key-file="${KEYNAME}" \
+ --zone "${ZONE}" \
+ "${USERNAME}"@"${INSTANCE_NAME}" -- \
+ rm -rf "/tmp/${REMOTE_TMPDIR}"
+ fi
+done
diff --git a/tools/images/test.cc b/tools/images/test.cc
new file mode 100644
index 000000000..4f31d93c5
--- /dev/null
+++ b/tools/images/test.cc
@@ -0,0 +1,23 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(Image, Sanity) {
+ // Do nothing.
+}
+
+} // namespace
diff --git a/kokoro/ubuntu1604/10_core.sh b/tools/images/ubuntu1604/10_core.sh
index 46dda6bb1..46dda6bb1 100755
--- a/kokoro/ubuntu1604/10_core.sh
+++ b/tools/images/ubuntu1604/10_core.sh
diff --git a/kokoro/ubuntu1604/20_bazel.sh b/tools/images/ubuntu1604/20_bazel.sh
index b33e1656c..b33e1656c 100755
--- a/kokoro/ubuntu1604/20_bazel.sh
+++ b/tools/images/ubuntu1604/20_bazel.sh
diff --git a/kokoro/ubuntu1604/25_docker.sh b/tools/images/ubuntu1604/25_docker.sh
index 1d3defcd3..1d3defcd3 100755
--- a/kokoro/ubuntu1604/25_docker.sh
+++ b/tools/images/ubuntu1604/25_docker.sh
diff --git a/kokoro/ubuntu1604/30_containerd.sh b/tools/images/ubuntu1604/30_containerd.sh
index a7472bd1c..a7472bd1c 100755
--- a/kokoro/ubuntu1604/30_containerd.sh
+++ b/tools/images/ubuntu1604/30_containerd.sh
diff --git a/kokoro/ubuntu1604/40_kokoro.sh b/tools/images/ubuntu1604/40_kokoro.sh
index 5f2dfc858..5f2dfc858 100755
--- a/kokoro/ubuntu1604/40_kokoro.sh
+++ b/tools/images/ubuntu1604/40_kokoro.sh
diff --git a/tools/images/ubuntu1604/BUILD b/tools/images/ubuntu1604/BUILD
new file mode 100644
index 000000000..ab1df0c4c
--- /dev/null
+++ b/tools/images/ubuntu1604/BUILD
@@ -0,0 +1,7 @@
+package(licenses = ["notice"])
+
+filegroup(
+ name = "ubuntu1604",
+ srcs = glob(["*.sh"]),
+ visibility = ["//:sandbox"],
+)
diff --git a/tools/images/ubuntu1804/BUILD b/tools/images/ubuntu1804/BUILD
new file mode 100644
index 000000000..7aa1ecdf7
--- /dev/null
+++ b/tools/images/ubuntu1804/BUILD
@@ -0,0 +1,7 @@
+package(licenses = ["notice"])
+
+alias(
+ name = "ubuntu1804",
+ actual = "//tools/images/ubuntu1604",
+ visibility = ["//:sandbox"],
+)
diff --git a/tools/installers/BUILD b/tools/installers/BUILD
new file mode 100644
index 000000000..01bc4de8c
--- /dev/null
+++ b/tools/installers/BUILD
@@ -0,0 +1,22 @@
+# Installers for use by the tools/vm_test rules.
+
+package(
+ default_visibility = ["//:sandbox"],
+ licenses = ["notice"],
+)
+
+sh_binary(
+ name = "head",
+ srcs = ["head.sh"],
+ data = ["//runsc"],
+)
+
+sh_binary(
+ name = "master",
+ srcs = ["master.sh"],
+)
+
+sh_binary(
+ name = "shim",
+ srcs = ["shim.sh"],
+)
diff --git a/kokoro/ubuntu1604/build.sh b/tools/installers/head.sh
index d664a3a76..4435cb27a 100755
--- a/kokoro/ubuntu1604/build.sh
+++ b/tools/installers/head.sh
@@ -14,7 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set -xeo pipefail
+# Install our runtime.
+third_party/gvisor/runsc/runsc install
-# Run the image_build.sh script with appropriate parameters.
-IMAGE_PROJECT=ubuntu-os-cloud IMAGE_FAMILY=ubuntu-1604-lts $(dirname $0)/../../tools/image_build.sh $(dirname $0)/??_*.sh
+# Restart docker.
+service docker restart || true
diff --git a/kokoro/ubuntu1804/build.sh b/tools/installers/master.sh
index 2b5c9a6f2..7b1956454 100755
--- a/kokoro/ubuntu1804/build.sh
+++ b/tools/installers/master.sh
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set -xeo pipefail
-
-# Run the image_build.sh script with appropriate parameters.
-IMAGE_PROJECT=ubuntu-os-cloud IMAGE_FAMILY=ubuntu-1804-lts $(dirname $0)/../../tools/image_build.sh $(dirname $0)/??_*.sh
+# Install runsc from the master branch.
+curl -fsSL https://gvisor.dev/archive.key | sudo apt-key add -
+add-apt-repository "deb https://storage.googleapis.com/gvisor/releases release main"
+apt-get update && apt-get install -y runsc
diff --git a/tools/installers/shim.sh b/tools/installers/shim.sh
new file mode 100755
index 000000000..f7dd790a1
--- /dev/null
+++ b/tools/installers/shim.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright 2019 The gVisor Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Reinstall the latest containerd shim.
+declare -r base="https://storage.googleapis.com/cri-containerd-staging/gvisor-containerd-shim"
+declare -r latest=$(mktemp --tmpdir gvisor-containerd-shim-latest.XXXXXX)
+declare -r shim_path=$(mktemp --tmpdir gvisor-containerd-shim.XXXXXX)
+wget --no-verbose "${base}"/latest -O ${latest}
+wget --no-verbose "${base}"/gvisor-containerd-shim-$(cat ${latest}) -O ${shim_path}
+chmod +x ${shim_path}
+mv ${shim_path} /usr/local/bin/gvisor-containerd-shim