blob: 76fc9e550dfd8d53cec8a3437318e2bc9138ecc1 [file] [log] [blame]
#!/bin/bash
#
# Copyright 2018 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.
# Setup script for Ubuntu 14.04 LTS, 16.04 LTS and 18.04 LTS.
# Fail on errors.
# Fail when using undefined variables.
# Print all executed commands.
# Fail when any command in a pipe fails.
set -euxo pipefail
# Prevent dpkg / apt-get / debconf from trying to access stdin.
export DEBIAN_FRONTEND="noninteractive"
### Deduce image configuration from the hostname.
case $(hostname) in
*pipeline*)
config_kind="pipeline"
;;
*trusted*)
config_kind="trusted"
;;
*testing*)
config_kind="testing"
;;
*worker*)
config_kind="worker"
;;
*)
echo "Could not deduce image kind from hostname: $(hostname)!"
exit 1
;;
esac
case $(hostname) in
*ubuntu1404*)
config_os="ubuntu1404"
;;
*ubuntu1604*)
config_os="ubuntu1604"
;;
*ubuntu1804*)
config_os="ubuntu1804"
;;
*)
echo "Could not deduce operating system from hostname: $(hostname)!"
exit 1
esac
case $(hostname) in
*nojava*)
config_java="no"
;;
*java8*)
config_java="8"
;;
*java9*)
config_java="9"
;;
*)
echo "Could not deduce Java version from hostname: $(hostname)!"
exit 1
esac
### Increase file descriptor limits
{
cat >> /etc/security/limits.conf <<EOF
* soft nofile 100000
* hard nofile 100000
EOF
}
### Install base packages.
{
# Android SDK requires 32-bits libraries.
dpkg --add-architecture i386
apt-get -qqy update
apt-get -qqy dist-upgrade > /dev/null
packages=(
# Bazel dependencies.
build-essential
clang
curl
git
python
python-dev
python3
python3-dev
unzip
wget
xvfb
zip
zlib1g-dev
# Dependencies for Android SDK.
# https://developer.android.com/studio/troubleshoot.html#linux-libraries
# https://code.google.com/p/android/issues/detail?id=207212
expect
libbz2-1.0:i386
libncurses5:i386
libstdc++6:i386
libz1:i386
# Dependencies for TensorFlow.
libcurl3-dev
swig
python-enum34
python-mock
python-numpy
python-pip
python-wheel
python3-mock
python3-numpy
python3-pip
python3-wheel
# Required by Envoy: https://github.com/bazelbuild/continuous-integration/issues/218
automake
autotools-dev
cmake
libtool
m4
# Required by our infrastructure.
lvm2
# Required by Android projects that launch the Android emulator headlessly
# (see https://github.com/bazelbuild/continuous-integration/pull/246)
cpu-checker
qemu-system-x86
unzip
xvfb
# Required by our release process.
devscripts
gnupg
pandoc
reprepro
ssmtp
)
# Bazel dependencies.
if [[ "${config_os}" == "ubuntu1804" ]]; then
packages+=("coreutils")
else
packages+=("realpath")
fi
apt-get -qqy install "${packages[@]}" > /dev/null
# Remove apport, as it's unneeded and uses significant CPU and I/O.
apt-get -qqy purge apport
}
### Fetch and save image version to file.
{
IMAGE_VERSION=$(curl -sS "http://metadata.google.internal/computeMetadata/v1/instance/attributes/image-version" -H "Metadata-Flavor: Google")
echo -n "${IMAGE_VERSION}" > /etc/image-version
}
### Install Azul Zulu (OpenJDK).
if [[ "${config_java}" != "no" ]]; then
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0x219BD9C9
apt-add-repository 'deb http://repos.azulsystems.com/ubuntu stable main'
apt-get -qqy update
apt-get -qqy install zulu-${config_java} > /dev/null
else
apt-get -qqy purge *openjdk* *zulu*
apt-get -qqy autoremove --purge
fi
### Install Bazel.
{
bazel_version=$(curl -sSI https://github.com/bazelbuild/bazel/releases/latest | grep '^Location: ' | sed 's|.*/||' | sed $'s/\r//')
curl -sSLo install.sh "https://releases.bazel.build/${bazel_version}/release/bazel-${bazel_version}-installer-linux-x86_64.sh"
bash install.sh > /dev/null
rm -f install.sh
}
### Install the Buildkite Agent on production images.
if [[ "${config_kind}" != "testing" ]]; then
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 \
--recv-keys 32A37959C2FA5C3C99EFBC32A79206696452D198 &> /dev/null
add-apt-repository -y "deb https://apt.buildkite.com/buildkite-agent stable main"
apt-get -qqy update
apt-get -qqy install buildkite-agent > /dev/null
# Write the Buildkite agent configuration.
cat > /etc/buildkite-agent/buildkite-agent.cfg <<EOF
token="xxx"
name="%hostname-%n"
tags="kind=${config_kind},os=${config_os},java=${config_java},image-version=${IMAGE_VERSION}"
build-path="/var/lib/buildkite-agent/builds"
hooks-path="/etc/buildkite-agent/hooks"
plugins-path="/etc/buildkite-agent/plugins"
git-clone-flags="-v --reference /var/lib/bazelbuild"
EOF
# Stop the agent after each job on stateless worker machines.
if [[ "${config_kind}" != "pipeline" ]]; then
cat >> /etc/buildkite-agent/buildkite-agent.cfg <<EOF
disconnect-after-job=true
disconnect-after-job-timeout=86400
EOF
fi
# Add the Buildkite agent hooks.
cat > /etc/buildkite-agent/hooks/environment <<'EOF'
#!/bin/bash
set -euo pipefail
export PATH=$PATH:/snap/bin/
export BUILDKITE_ARTIFACT_UPLOAD_DESTINATION="gs://bazel-buildkite-artifacts/$BUILDKITE_JOB_ID"
export BUILDKITE_GS_ACL="publicRead"
EOF
# The trusted worker machine may only execute certain whitelisted builds.
if [[ "${config_kind}" == "trusted" ]]; then
cat >> /etc/buildkite-agent/hooks/environment <<'EOF'
case ${BUILDKITE_BUILD_CREATOR_EMAIL} in
*@google.com)
;;
*)
echo "Build creator not allowed: ${BUILDKITE_BUILD_CREATOR_EMAIL}"
exit 1
esac
case ${BUILDKITE_REPO} in
https://github.com/bazelbuild/bazel.git|\
https://github.com/bazelbuild/continuous-integration.git)
;;
*)
echo "Repository not allowed: ${BUILDKITE_REPO}"
exit 1
esac
case ${BUILDKITE_ORGANIZATION_SLUG} in
bazel)
;;
*)
echo "Organization not allowed: ${BUILDKITE_PIPELINE_SLUG}"
exit 1
esac
case ${BUILDKITE_PIPELINE_SLUG} in
google-bazel-presubmit-metrics|\
release)
;;
*)
echo "Pipeline not allowed: ${BUILDKITE_PIPELINE_SLUG}"
exit 1
esac
export BUILDKITE_API_TOKEN=$(gsutil cat "gs://bazel-encrypted-secrets/buildkite-api-token.enc" | \
gcloud kms decrypt --location "global" --keyring "buildkite" --key "buildkite-api-token" \
--plaintext-file "-" --ciphertext-file "-")
EOF
fi
# Some notes about our service config:
#
# - All Buildkite agents except the pipeline agent are stateless and need a special service config
# that kills remaining processes and deletes temporary files.
#
# - We set the service to not launch automatically, as the startup script will start it once it is
# done with setting up the local SSD and writing the agent configuration.
if [[ "${config_kind}" == "pipeline" ]]; then
# This is a pipeline worker machine.
systemctl disable buildkite-agent
elif [[ $(systemctl --version 2>/dev/null) ]]; then
# This is a normal worker machine with systemd (e.g. Ubuntu 16.04 LTS).
systemctl disable buildkite-agent
mkdir /etc/systemd/system/buildkite-agent.service.d
cat > /etc/systemd/system/buildkite-agent.service.d/override.conf <<'EOF'
[Service]
Restart=always
PermissionsStartOnly=true
ExecStopPost=/bin/echo "Cleaning up after Buildkite Agent exited ..."
ExecStopPost=/usr/bin/find /tmp -user buildkite-agent -delete
ExecStopPost=/usr/bin/find /var/lib/buildkite-agent -mindepth 1 -maxdepth 1 -execdir rm -rf '{}' +
ExecStopPost=/bin/sh -c 'docker ps -q | xargs -r docker kill'
ExecStopPost=/usr/bin/docker system prune -f --volumes
EOF
elif [[ $(init --version 2>/dev/null | grep upstart) ]]; then
# This is a normal worker machine with upstart (e.g. Ubuntu 14.04 LTS).
cat > /etc/init/buildkite-agent.conf <<'EOF'
description "buildkite-agent"
respawn
respawn limit unlimited
exec sudo -H -u buildkite-agent /usr/bin/buildkite-agent start
# Kill all possibly remaining processes after each build.
post-stop script
set +e
set -x
# Kill all remaining processes.
killall -q -9 -u buildkite-agent
# Clean up left-over files.
find /tmp -user buildkite-agent -delete
find /var/lib/buildkite-agent -mindepth 1 -maxdepth 1 -execdir rm -rf '{}' +
docker ps -q | xargs -r docker kill
docker system prune -f --volumes
end script
EOF
else
echo "Unknown operating system - has neither systemd nor upstart?"
exit 1
fi
fi
### Install Docker.
{
apt-get -qqy install apt-transport-https ca-certificates > /dev/null
# From https://download.docker.com/linux/ubuntu/gpg
curl -sSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get -qqy update
apt-get -qqy install docker-ce > /dev/null
# Allow the buildkite-agent user access to Docker.
if [[ "${config_kind}" != "testing" ]]; then
usermod -aG docker buildkite-agent
fi
# Disable the Docker service, as the startup script has to mount
# /var/lib/docker first.
if [[ -e /bin/systemctl ]]; then
systemctl disable docker
else
echo manual > /etc/init/docker.override
fi
}
### Install Node.js.
{
curl -sSL https://deb.nodesource.com/setup_8.x | bash - > /dev/null
apt-get -qqy install nodejs > /dev/null
# Required by Gerrit:
# https://gerrit.googlesource.com/gerrit/+show/master/polygerrit-ui/README.md
npm install -g \
typescript \
fried-twinkie@0.0.15
}
### Install Python 3.6.
{
if [[ "${config_os}" == "ubuntu1804" ]]; then
pip3 install requests uritemplate pyyaml github3.py
else
packages+=("realpath")
apt-get -qqy install zlib1g-dev libssl-dev
PYTHON_VERSION="3.6.5"
mkdir -p /usr/local/src
pushd /usr/local/src
curl -O "https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz"
tar xfJ "Python-${PYTHON_VERSION}.tar.xz"
rm -f "Python-${PYTHON_VERSION}.tar.xz"
cd "Python-${PYTHON_VERSION}"
# Enable the 'ssl' module.
cat >> Modules/Setup.dist <<'EOF'
_ssl _ssl.c \
-DUSE_SSL -I/usr/include -I/usr/include/openssl \
-L/usr/lib -lssl -lcrypto
EOF
echo "Compiling Python ${PYTHON_VERSION} ..."
./configure --quiet --enable-ipv6
make -s -j8 all > /dev/null
echo "Installing Python ${PYTHON_VERSION} ..."
make -s altinstall > /dev/null
pip3.6 install requests uritemplate pyyaml github3.py
popd
rm -rf "/usr/local/src/Python-${PYTHON_VERSION}"
fi
}
### Enable KVM support.
if [[ "${config_kind}" != "testing" ]]; then
usermod -a -G kvm buildkite-agent
fi
### Install Android SDK and NDK (only if we have a JVM).
if [[ "${config_java}" != "no" ]]; then
if [[ "${config_java}" == "9" ]]; then
export SDKMANAGER_OPTS="--add-modules java.se.ee"
fi
# Android NDK
cd /opt
curl -sSLo android-ndk.zip https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
unzip android-ndk.zip > /dev/null
rm android-ndk.zip
# Android SDK
mkdir -p /opt/android-sdk-linux
cd /opt/android-sdk-linux
curl -sSLo android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
unzip android-sdk.zip > /dev/null
rm android-sdk.zip
expect -c '
set timeout -1
log_user 0
spawn tools/bin/sdkmanager --update
expect {
"Accept? (y/N)" { exp_send "y\r" ; exp_continue }
eof
}
'
# This should be kept in sync with mac/mac-android.sh.
# build-tools 28.0.1 introduces the new dexer, d8.jar
tools/bin/sdkmanager \
"build-tools;27.0.3" \
"build-tools;28.0.1" \
"emulator" \
"extras;android;m2repository" \
"platform-tools" \
"platforms;android-24" \
"platforms;android-25" \
"platforms;android-26" \
"platforms;android-27" \
"system-images;android-19;default;x86" \
"system-images;android-21;default;x86" \
"system-images;android-22;default;x86" \
"system-images;android-23;default;x86" \
> /dev/null
chown -R root:root /opt/android*
if [[ "${config_kind}" != "testing" ]]; then
cat >> /etc/buildkite-agent/hooks/environment <<'EOF'
export ANDROID_HOME="/opt/android-sdk-linux"
echo "Android SDK is at ${ANDROID_HOME}"
export ANDROID_NDK_HOME="/opt/android-ndk-r15c"
echo "Android NDK is at ${ANDROID_NDK_HOME}"
EOF
fi
fi
### Install tools required by the release process.
{
curl -sSL https://github.com/c4milo/github-release/releases/download/v1.1.0/github-release_v1.1.0_linux_amd64.tar.gz | \
tar xvz -C /usr/local/bin
chown root:root /usr/local/bin/github-release
chmod 0755 /usr/local/bin/github-release
}
### Clean up and trim the filesystem (potentially reduces the final image size).
{
rm -rf /var/lib/apt/lists/*
fstrim -v /
sleep 3
}
poweroff