1#!/bin/bash
2
3# Common code to build a host image on GCE
4
5# INTERNAL_extra_source may be set to a directory containing the source for
6# extra package to build.
7
8# INTERNAL_IP can be set to --internal-ip run on a GCE instance
9# The instance will need --scope compute-rw
10
11source "${ANDROID_BUILD_TOP}/external/shflags/src/shflags"
12
13DEFINE_string build_instance \
14  "${USER}-build" "Instance name to create for the build" "i"
15DEFINE_string build_project "$(gcloud config get-value project)" \
16  "Project to use for scratch"
17DEFINE_string build_zone "$(gcloud config get-value compute/zone)" \
18  "Zone to use for scratch resources"
19DEFINE_string dest_image "vsoc-host-scratch-${USER}" "Image to create" "o"
20DEFINE_string dest_family "" "Image family to add the image to" "f"
21DEFINE_string dest_project "$(gcloud config get-value project)" \
22  "Project to use for the new image" "p"
23DEFINE_string launch_instance "" \
24  "Name of the instance to launch with the new image" "l"
25DEFINE_string source_image_family "debian-10" \
26  "Image familty to use as the base" "s"
27DEFINE_string source_image_project debian-cloud \
28  "Project holding the base image" "m"
29DEFINE_string repository_url \
30  "https://github.com/google/android-cuttlefish.git" \
31  "URL to the repository with host changes" "u"
32DEFINE_string repository_branch master \
33  "Branch to check out" "b"
34DEFINE_string variant master \
35  "Variant to build: generally master or stable"
36
37
38SSH_FLAGS=(${INTERNAL_IP})
39
40fatal_echo() {
41  echo "$1"
42  exit 1
43}
44
45wait_for_instance() {
46  alive=""
47  while [[ -z "${alive}" ]]; do
48    sleep 5
49    alive="$(gcloud compute ssh "${SSH_FLAGS[@]}" "$@" -- uptime || true)"
50  done
51}
52
53package_source() {
54  local url="$1"
55  local branch="$2"
56  local repository_dir="${url/*\//}"
57  local debian_dir="$(basename "${repository_dir}" .git)"
58  if [[ $# -eq 4 ]]; then
59    debian_dir="${repository_dir}/$4"
60  fi
61  git clone "${url}" -b "${branch}"
62  dpkg-source -b "${debian_dir}"
63  rm -rf "${debian_dir}"
64}
65
66main() {
67  set -o errexit
68  set -x
69  PZ=(--project=${FLAGS_build_project} --zone=${FLAGS_build_zone})
70  if [[ -n "${FLAGS_dest_family}" ]]; then
71    dest_family_flag=("--family=${FLAGS_dest_family}")
72  else
73    dest_family_flag=()
74  fi
75  scratch_dir="$(mktemp -d)"
76  pushd "${scratch_dir}"
77  package_source "${FLAGS_repository_url}" "${FLAGS_repository_branch}" \
78    "cuttlefish-common_${FLAGS_version}"
79  popd
80  source_files=(
81    "${ANDROID_BUILD_TOP}/device/google/cuttlefish/tools/create_base_image_gce.sh"
82    ${scratch_dir}/*
83  )
84  if [[ -n "${INTERNAL_extra_source}" ]]; then
85    source_files+=("${INTERNAL_extra_source}"/*)
86  fi
87
88  delete_instances=("${FLAGS_build_instance}" "${FLAGS_dest_image}")
89  if [[ -n "${FLAGS_launch_instance}" ]]; then
90    delete_instances+=("${FLAGS_launch_instance}")
91  fi
92  gcloud compute instances delete -q \
93    "${PZ[@]}" "${delete_instances[@]}" || \
94      echo Not running
95  gcloud compute disks delete -q \
96    "${PZ[@]}" "${FLAGS_dest_image}" || echo No scratch disk
97  gcloud compute images delete -q \
98    --project="${FLAGS_build_project}" "${FLAGS_dest_image}" || echo Not respinning
99  gcloud compute disks create \
100    "${PZ[@]}" \
101    --image-family="${FLAGS_source_image_family}" \
102    --image-project="${FLAGS_source_image_project}" \
103    "${FLAGS_dest_image}"
104  local gpu_type="nvidia-tesla-p100-vws"
105  gcloud compute accelerator-types describe "${gpu_type}" "${PZ[@]}" || \
106    fatal_echo "Please use a zone with ${gpu_type} GPUs available."
107  gcloud compute instances create \
108    "${PZ[@]}" \
109    --machine-type=n1-standard-16 \
110    --image-family="${FLAGS_source_image_family}" \
111    --image-project="${FLAGS_source_image_project}" \
112    --boot-disk-size=200GiB \
113    --accelerator="type=${gpu_type},count=1" \
114    --maintenance-policy=TERMINATE \
115    "${FLAGS_build_instance}"
116  wait_for_instance "${PZ[@]}" "${FLAGS_build_instance}"
117  # Ubuntu tends to mount the wrong disk as root, so help it by waiting until
118  # it has booted before giving it access to the clean image disk
119  gcloud compute instances attach-disk \
120      "${PZ[@]}" \
121      "${FLAGS_build_instance}" --disk="${FLAGS_dest_image}"
122  # beta for the --internal-ip flag that may be passed via SSH_FLAGS
123  gcloud beta compute scp "${SSH_FLAGS[@]}" "${PZ[@]}" \
124    "${source_files[@]}" \
125    "${FLAGS_build_instance}:"
126  gcloud compute ssh "${SSH_FLAGS[@]}" \
127    "${PZ[@]}" "${FLAGS_build_instance}" -- \
128    ./create_base_image_gce.sh
129  gcloud compute instances delete -q \
130    "${PZ[@]}" "${FLAGS_build_instance}"
131  gcloud compute images create \
132    --project="${FLAGS_build_project}" \
133    --source-disk="${FLAGS_dest_image}" \
134    --source-disk-zone="${FLAGS_build_zone}" \
135    --licenses=https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx \
136    "${dest_family_flag[@]}" \
137    "${FLAGS_dest_image}"
138  gcloud compute disks delete -q "${PZ[@]}" \
139    "${FLAGS_dest_image}"
140  if [[ -n "${FLAGS_launch_instance}" ]]; then
141    gcloud compute instances create "${PZ[@]}" \
142      --image-project="${FLAGS_build_project}" \
143      --image="${FLAGS_dest_image}" \
144      --machine-type=n1-standard-4 \
145      --scopes storage-ro \
146      --accelerator="type=${gpu_type},count=1" \
147      --maintenance-policy=TERMINATE \
148      "${FLAGS_launch_instance}"
149  fi
150  cat <<EOF
151    echo Test and if this looks good, consider releasing it via:
152
153    gcloud compute images create \
154      --project="${FLAGS_dest_project}" \
155      --source-image="${FLAGS_dest_image}" \
156      --source-image-project="${FLAGS_build_project}" \
157      "${dest_family_flag[@]}" \
158      "${FLAGS_dest_image}"
159EOF
160}
161