blob: 48c6974a351ea4e232a5f4e3e0e2d85c333ee5a2 [file] [log] [blame] [edit]
#!/bin/bash
#
# Copyright 2015 The Bazel Authors. All rights reserved.
#
# 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.
# Script to easily re-image the various vms on GCE
set -eu
# List of slaves in the following format:
# GCE-VM-NAME GCE-BASE-IMAGE JENKINS-NODE LOCATION STARTUP-METADATA SETUP-SCRIPTS
# Where
# GCE-VM-NAME is the VM name on GCE
# GCE-BASE-IMAGE is the name of the base image in GCE
# (see `gcloud compute images list`)
# JENKINS-NODE is the name of the node in Jenkins
# LOCATION is the location in GCE (e.g. us-central1-a)
# STARTUP-METADATA is the metadata argument to gcloud to launch the right
# startup script.
# SETUP-SCRIPTS is a list of shell scripts to adapt the slave. It should
# create a ci user with its home in /home/ci
# and ends with writing to /home/ci/node_name the name
# of the jenkins node.
SLAVES=(
"ubuntu-14-04-slave ubuntu-14-04 ubuntu_14.04-x86_64-1 us-central1-a startup-script=jenkins-slave.sh ubuntu-14-04-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-15-10-slave https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1510-wily-v20151026 ubuntu_15.10-x86_64-1 asia-east1-c startup-script=jenkins-slave.sh ubuntu-15-10-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-14-04-slave-2 ubuntu-14-04 ubuntu_14.04-x86_64-2 us-central1-a startup-script=jenkins-slave.sh ubuntu-14-04-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-15-10-slave-2 https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1510-wily-v20151026 ubuntu_15.10-x86_64-2 asia-east1-c startup-script=jenkins-slave.sh ubuntu-15-10-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-14-04-slave-3 ubuntu-14-04 ubuntu_14.04-x86_64-3 us-east1-c startup-script=jenkins-slave.sh ubuntu-14-04-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-15-10-slave-3 https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1510-wily-v20151026 ubuntu_15.10-x86_64-3 us-east1-c startup-script=jenkins-slave.sh ubuntu-15-10-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-14-04-slave-4 ubuntu-14-04 ubuntu_14.04-x86_64-4 europe-west1-c startup-script=jenkins-slave.sh ubuntu-14-04-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-15-10-slave-4 https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1510-wily-v20151026 ubuntu_15.10-x86_64-4 europe-west1-c startup-script=jenkins-slave.sh ubuntu-15-10-slave.sh linux-android.sh cleanup-install.sh"
"ubuntu-docker-slave-1 https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1510-wily-v20151026 ubuntu_15.10-x86_64-docker-1 us-east1-c startup-script=jenkins-slave.sh ubuntu-15-10-slave.sh ubuntu-15-10-docker.sh linux-android.sh cleanup-install.sh"
# Fow Windows, we use a custom image with pre-installed MSVC.
"windows-slave-1 /bazel-public/windows-server-2012-r2-dc-v20160112-vs2015-cpp-python-msys windows-x86_64-1 europe-west1-c windows-startup-script-ps1=jenkins-slave-windows.ps1"
"windows-slave-2 /bazel-public/windows-server-2012-r2-dc-v20160112-vs2015-cpp-python-msys windows-x86_64-2 europe-west1-c windows-startup-script-ps1=jenkins-slave-windows.ps1"
)
cd "$(dirname "${BASH_SOURCE[0]}")"
# Test whether $1 is the name of an existing instance on GCE
function test_vm() {
(( $(gcloud compute instances list "$1" | wc -l) > 1 ))
}
# Create the container engine VM containing the jenkins instance.
function create_master() {
gcloud compute instances create jenkins --tags jenkins \
--zone us-central1-a --machine-type n1-standard-4 \
--image container-vm \
--metadata-from-file google-container-manifest=jenkins.yml,startup-script=mount-volumes.sh \
--boot-disk-type pd-ssd --boot-disk-size 40GB \
--address ci --disk name=jenkins-volumes,device-name=volumes
}
# Wait for a VM $1 in zone $2 to be up and running using ssh.
# This function will wait for at most $3 seconds.
function wait_vm() {
local vm="$1"
local zone="$2"
local timeout="${3-60}" # Wait for 1 minute maximum by default
local starttime="$(date +%s)"
while (( "$(date +%s)" - "$starttime" < "$timeout" )); do
# gcloud compute ssh forward the return code of the executed command.
if gcloud compute ssh --zone="$zone" --command /bin/true "$vm" &>/dev/null
then
return 0
fi
done
return 1
}
function ssh_command() {
local TAG="$1"
local LOCATION="$2"
local tmpdir="${TMPDIR:-/tmp}"
local tmp="$(mktemp ${tmpdir%%/}/vm-ssh.XXXXXXXX)"
trap "rm -f ${tmp}" EXIT
shift 2
echo -n >"${tmp}"
for i in "$@"; do
if [ -f "$i" ]; then
cat "$i" >>"${tmp}"
else
echo "$i" >>"${tmp}"
fi
done
cat "${tmp}" | gcloud compute ssh --zone="${LOCATION}" \
--command "cat >/tmp/s.sh; sudo bash /tmp/s.sh; rm /tmp/s.sh" \
"${TAG}"
rm -f "${tmp}"
trap - EXIT
}
# Create a slave named $1 whose image is $2 (see `gcloud compute image list`)
# and whose jenkins node name is $3. The other arguments are a list of setup
# scripts to run as root on instance creation. The `jenkins-slave.sh` script
# will be used as the startup script for the instance.
function create_slave() {
local TAG="$1"
local IMAGE="$2"
local JENKINS_NODE="$3"
local LOCATION="$4"
local STARTUP_METADATA="$5"
shift 5
gcloud compute instances create "$TAG" \
--zone "$LOCATION" --machine-type n1-standard-8 \
--image "$IMAGE" \
--metadata jenkins_node="$JENKINS_NODE" \
--metadata-from-file "$STARTUP_METADATA" \
--boot-disk-type pd-ssd --boot-disk-size 500GB
case "$TAG" in
windows-*) # Windows
;;
*) # Linux
wait_vm "$TAG" "$LOCATION" # Wait a bit for the VM to fully start
# Create the jenkins user, run additional set-up scripts and mark
# the install process as finished.
ssh_command "$TAG" "$LOCATION" \
"sudo adduser --system --home /home/ci ci" \
"$@" \
"su ci -s /bin/bash -c \"echo -n '$JENKINS_NODE' >/home/ci/node_name\""
;;
esac
}
function get_slave_by_name() {
for i in "${SLAVES[@]}"; do
if [[ "$i" =~ ^"$1 " ]]; then
echo "$i"
fi
done
}
function create_vm() {
if [ "$1" = "jenkins" ]; then
create_master
else
local args="$(get_slave_by_name "$1")"
[ -n "$args" ] || (echo "Unknown vm $1" >&2; exit 1)
create_slave $args
fi
}
function action() {
local action=$1
shift
if (( $# == 0 )); then
$action jenkins
for i in "${SLAVES[@]}"; do
$action "${i%% *}"
done
else
for i in "$@"; do
$action "$i"
done
fi
}
function delete_vm() {
local TAG=$1
if test_vm $TAG; then
local location="$(get_slave_by_name "$TAG" | cut -d " " -f 4)"
gcloud compute instances delete --zone=$location $TAG
fi
}
command="${1-}"
shift || true
case "${command}" in
"create")
action create_vm "$@"
;;
"delete")
action delete_vm "$@"
;;
"reimage")
action delete_vm "$@"
action create_vm "$@"
;;
*)
echo "Usage: $0 (create|delete|reimage) [vm ... vm]" >&2
exit 1
;;
esac