Check in scripts to deploy on GitHub runners (#9765)
There's one script that we can bake into the disk image in the runner
home directory. It fetches the other configuration into a subdirectory.
The `actions-runner/.env` is symlinked to `config/runner.env` in the
runner disk image.
This uses a proxy to fetch registration tokens without giving the
runners themselves access to powerful administration privileges. See
https://github.com/google-github-actions/github-runner-token-proxy
GitHub actions on pull requests currently require approval for
non-collaborators and the runners do not yet have any special
privileges, so it shouldn't be a problem that they're not yet
ephemeral (which requires setting up some additional teardown logic).
diff --git a/build_tools/github_actions/runner/config/chown_workdir.sh b/build_tools/github_actions/runner/config/chown_workdir.sh
new file mode 100755
index 0000000..759e4e0
--- /dev/null
+++ b/build_tools/github_actions/runner/config/chown_workdir.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -euo pipefail
+
+# Docker has a tendency to make things owned by root unless you do a dance with
+# which user you run it as. This can make the workspace unusable.
+# TODO: switch to ephemeral runners and get rid of this.
+sudo chown -R runner:runner /home/runner
diff --git a/build_tools/github_actions/runner/config/cleanup_workdir.sh b/build_tools/github_actions/runner/config/cleanup_workdir.sh
new file mode 100755
index 0000000..f117b31
--- /dev/null
+++ b/build_tools/github_actions/runner/config/cleanup_workdir.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# Remove the working directory so we have a fresh version for subsequent
+# actions.
+# TODO: switch to ephemeral runners and get rid of this.
+sudo rm -rf /home/runner/actions-runner/_work/iree/iree/
+mkdir -p /home/runner/actions-runner/_work/iree/iree/
diff --git a/build_tools/github_actions/runner/config/functions.sh b/build_tools/github_actions/runner/config/functions.sh
new file mode 100644
index 0000000..c7bd8fc
--- /dev/null
+++ b/build_tools/github_actions/runner/config/functions.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# Helper functions for other scripts. Should be broken into multiple files if
+# we end up with a lot.
+# This file should be sourced, not executed.
+
+############################## Instance metadata ###############################
+
+get_metadata() {
+ local url="http://metadata.google.internal/computeMetadata/v1/${1}"
+ ret=0
+ curl "${url}" \
+ --silent --fail --show-error \
+ --header "Metadata-Flavor: Google" || ret=$?
+ if [[ $ret != 0 ]]; then
+ echo "Failed fetching ${url}" >&2
+ return ${ret}
+ fi
+}
+
+get_os_info() {
+ get_metadata "instance/guest-attributes/guestInventory/${1}"
+}
+
+get_attribute() {
+ get_metadata "instance/attributes/${1}"
+}
+
+################################################################################
+
+
+############################## Utility functions ###############################
+
+# Tests if the first argument is contained in the array in the second argument.
+# Usage `is_contained "element" "${array[@]}"`
+is_contained() {
+ local e;
+ local match="$1"
+ shift
+ for e in "$@"; do
+ if [[ "$e" == "$match" ]]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+################################################################################
diff --git a/build_tools/github_actions/runner/config/post_job.sh b/build_tools/github_actions/runner/config/post_job.sh
new file mode 100755
index 0000000..83c8e52
--- /dev/null
+++ b/build_tools/github_actions/runner/config/post_job.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -euo pipefail
+
+SCRIPT_DIR="$(dirname -- "$( readlink -f -- "$0"; )")";
+
+"${SCRIPT_DIR}/cleanup_workdir.sh"
diff --git a/build_tools/github_actions/runner/config/pre_job.sh b/build_tools/github_actions/runner/config/pre_job.sh
new file mode 100755
index 0000000..96b1965
--- /dev/null
+++ b/build_tools/github_actions/runner/config/pre_job.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -euo pipefail
+
+SCRIPT_DIR="$(dirname -- "$( readlink -f -- "$0"; )")";
+
+source "${SCRIPT_DIR}/functions.sh"
+
+RUNNER_GROUP="$(get_attribute github-runner-group)"
+
+"${SCRIPT_DIR}/validate_trigger.${RUNNER_GROUP}.sh"
+"${SCRIPT_DIR}/chown_workdir.sh"
diff --git a/build_tools/github_actions/runner/config/runner.env b/build_tools/github_actions/runner/config/runner.env
new file mode 100644
index 0000000..d19607a
--- /dev/null
+++ b/build_tools/github_actions/runner/config/runner.env
@@ -0,0 +1,3 @@
+LANG=C.UTF-8
+ACTIONS_RUNNER_HOOK_JOB_STARTED=/home/runner/config/pre_job.sh
+ACTIONS_RUNNER_HOOK_JOB_COMPLETED=/home/runner/config/post_job.sh
diff --git a/build_tools/github_actions/runner/config/setup.sh b/build_tools/github_actions/runner/config/setup.sh
new file mode 100755
index 0000000..11021a6
--- /dev/null
+++ b/build_tools/github_actions/runner/config/setup.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# Sets up a GitHub actions runner VM. Requires custom attributes to indicate
+# configuration settings and uses a proxy service to obtain runner registration
+# tokens (https://github.com/google-github-actions/github-runner-token-proxy).
+
+set -euo pipefail
+
+SCRIPT_DIR="$(dirname -- "$( readlink -f -- "$0"; )")";
+
+source "${SCRIPT_DIR}/functions.sh"
+
+cd actions-runner
+
+GITHUB_TOKEN_PROXY_URL="$(get_attribute github-token-proxy-url)"
+GITHUB_RUNNER_SCOPE="$(get_attribute github-runner-scope)"
+
+GOOGLE_CLOUD_RUN_ID_TOKEN=$(get_metadata "instance/service-accounts/default/identity?audience=${GITHUB_TOKEN_PROXY_URL}")
+GITHUB_REGISTRATION_TOKEN="$(curl -sSfL "${GITHUB_TOKEN_PROXY_URL}/register" \
+ --header "Authorization: Bearer ${GOOGLE_CLOUD_RUN_ID_TOKEN}" \
+ --data-binary "{\"scope\": \"${GITHUB_RUNNER_SCOPE}\"}" \
+ | jq -r ".token"
+)"
+
+# These use OS inventory management to fetch information about the VM operating
+# system (https://cloud.google.com/compute/docs/instances/os-inventory-management).
+# For some reason, querying these at startup is unreliable. It seems like the
+# guestInventory attributes take a really long time to be populated. For now,
+# anything in here we care about needs to be injected via the
+# `github-runner-labels` custom metadata attribute.
+# OS_ID="$(get_os_info ShortName)"
+# OS_VERSION="$(get_os_info Version)"
+# KERNEL_RELEASE="$(get_os_info KernelRelease)"
+# HOSTNAME="$(get_os_info Hostname)"
+# ARCH="$(get_os_info Architecture)"
+# ARCH="${ARCH^^}"
+# if [[ "${ARCH}" == "X86_64" ]]; then
+# ARCH="X64" # This is the nomenclature GitHub uses
+# fi
+
+kernel="$(uname -s)"
+
+# Matches default nomenclature used by GitHub
+case "${kernel^^}" in
+ LINUX*)
+ OS_FAMILY="Linux";;
+ DARWIN*)
+ OS_FAMILY="macOS";;
+ CYGWIN*|MINGW*)
+ OS_FAMILY="Windows";;
+ *)
+ echo "Did not recognize output of 'uname -s': ${kernel}"
+ exit 1
+ ;;
+esac
+
+HOSTNAME="$(get_metadata instance/name)"
+ZONE="$(get_metadata instance/zone | awk -F/ '{print $NF}')"
+CPU_PLATFORM="$(get_metadata instance/cpu-platform)"
+MACHINE_TYPE="$(get_metadata instance/machine-type | awk -F/ '{print $NF}')"
+
+RUNNER_GROUP="$(get_attribute github-runner-group)"
+RUNNER_TRUST="$(get_attribute github-runner-trust)"
+RUNNER_CUSTOM_LABELS="$(get_attribute github-runner-labels)"
+
+declare -a RUNNER_LABELS_ARRAY=(
+ "os-family=${OS_FAMILY}"
+ # Also as just a raw label, to match GitHub default behavior
+ "${OS_FAMILY}"
+ "hostname=${HOSTNAME}"
+ "runner-group=${RUNNER_GROUP}"
+ "trust=${RUNNER_TRUST}"
+ "zone=${ZONE}"
+ "cpu-platform=${CPU_PLATFORM}"
+ "machine-type=${MACHINE_TYPE}"
+ # These attributes require guest attributes. See note above.
+ # "arch=${ARCH}"
+ # "${ARCH}"
+ # "os=${OS_ID}"
+ # "os-version=${OS_VERSION}"
+ # "kernel-release=${KERNEL_RELEASE}"
+)
+
+RUNNER_LABELS="$(IFS="," ; echo "${RUNNER_LABELS_ARRAY[*]}")"
+# Append custom labels, taking care to only add a comma if there are any
+RUNNER_LABELS="${RUNNER_LABELS}${RUNNER_CUSTOM_LABELS:+,${RUNNER_CUSTOM_LABELS}}"
+
+declare -a args=(
+ --url "https://github.com/${GITHUB_RUNNER_SCOPE}"
+ --labels "${RUNNER_LABELS}"
+ --unattended
+ --runnergroup "${RUNNER_GROUP}"
+ --replace
+)
+# I would love to discover another way to print an array while preserving quote
+# escaping. We're not just using `set -x` on the command itself because we don't
+# want to leak the token (even if it's immediately invalidated, still best not
+# to). `:` is the bash noop command that is equivalent to `true` so we are
+# "running" a command exclusively to print it using the shell's builtin
+# functionality.
+(set -x; : Running configuration with additional args: "${args[@]}")
+
+./config.sh --token "${GITHUB_REGISTRATION_TOKEN}" "${args[@]}"
+sudo ./svc.sh install
+sudo ./svc.sh start
diff --git a/build_tools/github_actions/runner/config/validate_trigger.postsubmit.sh b/build_tools/github_actions/runner/config/validate_trigger.postsubmit.sh
new file mode 100755
index 0000000..78f6d7c
--- /dev/null
+++ b/build_tools/github_actions/runner/config/validate_trigger.postsubmit.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -euo pipefail
+
+SCRIPT_DIR="$(dirname -- "$( readlink -f -- "$0"; )")";
+
+source "${SCRIPT_DIR}/functions.sh"
+
+ALLOWED_EVENTS=(
+ "push"
+ "workflow_dispatch"
+ "release"
+ "deployment"
+ "deployment_status"
+ "schedule"
+)
+
+if ! is_contained "${GITHUB_EVENT_NAME}" "${ALLOWED_EVENTS[@]}"; then
+ echo "Event type '${GITHUB_EVENT_NAME}' is not allowed on this runner. Aborting workflow."
+ # clean up any nefarious stuff we may have fetched in job setup
+ cd /home/runner/actions-runner/_work
+ rm -rf _actions/ _temp/
+ exit 1
+fi
diff --git a/build_tools/github_actions/runner/config/validate_trigger.presubmit.sh b/build_tools/github_actions/runner/config/validate_trigger.presubmit.sh
new file mode 100755
index 0000000..9030a28
--- /dev/null
+++ b/build_tools/github_actions/runner/config/validate_trigger.presubmit.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# No validation for now
diff --git a/build_tools/github_actions/runner/config/validate_trigger.releaser.sh b/build_tools/github_actions/runner/config/validate_trigger.releaser.sh
new file mode 100755
index 0000000..0bc3661
--- /dev/null
+++ b/build_tools/github_actions/runner/config/validate_trigger.releaser.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -euo pipefail
+
+SCRIPT_DIR="$(dirname -- "$( readlink -f -- "$0"; )")";
+
+source "${SCRIPT_DIR}/functions.sh"
+
+ALLOWED_EVENTS=(
+ "workflow_dispatch"
+ "release"
+ "deployment"
+ "deployment_status"
+ "schedule"
+)
+
+if ! is_contained "${GITHUB_EVENT_NAME}" "${ALLOWED_EVENTS[@]}"; then
+ echo "Event type '${GITHUB_EVENT_NAME}' is not allowed on this runner. Aborting workflow."
+ # clean up any nefarious stuff we may have fetched in job setup
+ cd /home/runner/actions-runner/_work
+ rm -rf _actions/ _temp/
+ exit 1
+fi
diff --git a/build_tools/github_actions/runner/fetch_and_setup.sh b/build_tools/github_actions/runner/fetch_and_setup.sh
new file mode 100755
index 0000000..d04d523
--- /dev/null
+++ b/build_tools/github_actions/runner/fetch_and_setup.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# Copyright 2022 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# This script is actually part of the VM image and fetches the rest of the
+# configuration. It is invoked on startup through a one-line startup script that
+# calls it. Longer term, we may want to have an explicit deployment of new
+# scripts instead of fetching them directly from HEAD.
+
+set -euo pipefail
+
+SCRIPT="$( readlink -f -- "$0"; )"
+SCRIPT_BASENAME="$(basename ${SCRIPT})"
+
+if [[ "$(whoami)" != "runner" ]]; then
+ echo "Current user is not 'runner'. Rerunning script as 'runner'."
+ sudo su runner --shell /bin/bash --command "${SCRIPT}"
+ exit
+fi
+
+cd "${HOME}"
+rm -rf config
+
+rm -rf /tmp/iree
+git clone https://github.com/iree-org/iree.git /tmp/iree
+
+cp -r /tmp/iree/build_tools/github_actions/runner/config/ "${HOME}/config"
+
+rm -rf /tmp/iree
+
+./config/setup.sh