summaryrefslogtreecommitdiffhomepage
path: root/tools/vm/build.sh
blob: 098258cad2c625804336732e19e95a9b91f53ec1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/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 -eou 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=$(set -x; gcloud compute images list --filter="name=(${IMAGE_NAME})" --format="value(name)")
if ! [[ -z "${existing}" ]]; then
  echo "${existing}"
  exit 0
fi

# Standard arguments (applies only on script execution).
declare -ar SSH_ARGS=("-o" "ConnectTimeout=60" "--")

# 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.
(set -x; 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 {
  (set -x; gcloud compute instances delete --quiet --zone "${ZONE}" "${INSTANCE_NAME}")
}
trap cleanup EXIT

# Wait for the instance to become available (up to 5 minutes).
echo -n "Waiting for ${INSTANCE_NAME}" >&2
declare timeout=300
declare success=0
declare internal=""
declare -r start=$(date +%s)
declare -r end=$((${start}+${timeout}))
while [[ "$(date +%s)" -lt "${end}" ]] && [[ "${success}" -lt 3 ]]; do
  echo -n "."
  if gcloud compute ssh --zone "${ZONE}" "${USERNAME}"@"${INSTANCE_NAME}" -- true 2>/dev/null; then
    success=$((${success}+1))
  elif gcloud compute ssh --internal-ip --zone "${ZONE}" "${USERNAME}"@"${INSTANCE_NAME}" -- true 2>/dev/null; then
    success=$((${success}+1))
    internal="--internal-ip"
  fi
done

if [[ "${success}" -eq "0" ]]; then
  echo "connect timed out after ${timeout} seconds." >&2
  exit 1
else
  echo "done." >&2
fi

# Run the install scripts provided.
for arg; do
  (set -x; gcloud compute ssh ${internal} \
      --zone "${ZONE}" \
      "${USERNAME}"@"${INSTANCE_NAME}" -- \
      "${SSH_ARGS[@]}" \
      sudo bash - <"${arg}" >/dev/null)
done

# Stop the instance; required before creating an image.
(set -x; gcloud compute instances stop --quiet --zone "${ZONE}" "${INSTANCE_NAME}" >/dev/null)

# Create a snapshot of the instance disk.
(set -x; gcloud compute disks snapshot \
    --quiet \
    --zone "${ZONE}" \
    --snapshot-names="${SNAPSHOT_NAME}" \
    "${INSTANCE_NAME}" >/dev/null)

# Create the disk image.
(set -x; 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}"