name: Select Self-hosted Runner on: workflow_call: inputs: github-hosted-runner-label: required: true type: string self-hosted-image-name: required: true type: string self-hosted-runner-scope: required: false type: string default: /orgs/${{ github.repository_owner }}/actions/runners force-github-hosted-runner: required: false type: boolean default: false outputs: unique-id: value: ${{ jobs.runner-select.outputs.unique-id }} selected-runner-label: value: ${{ jobs.runner-select.outputs.selected-runner-label }} is-self-hosted: value: ${{ jobs.runner-select.outputs.is-self-hosted }} jobs: # Selects a self-hosted runner if available, or else a GitHub-hosted runner. # We generate a unique id for the workload, then ask our monitor API to # reserve a self-hosted runner for us. runner-select: name: Select Runner runs-on: ubuntu-latest outputs: unique-id: ${{ steps.select.outputs.unique_id }} selected-runner-label: ${{ steps.select.outputs.selected_runner_label }} is-self-hosted: ${{ steps.select.outputs.is_self_hosted }} steps: - name: Select and reserve best available runner id: select run: | github_hosted_runner_label='${{ inputs.github-hosted-runner-label }}' self_hosted_image_name='${{ inputs.self-hosted-image-name }}' self_hosted_runner_scope='${{ inputs.self-hosted-runner-scope }}' set -euo pipefail fall_back_to_github_hosted() { echo 'Falling back to GitHub-hosted runner' echo "selected_runner_label=$github_hosted_runner_label" | tee -a $GITHUB_OUTPUT echo 'is_self_hosted=false' | tee -a $GITHUB_OUTPUT exit 0 } # Generate a unique id that allows the workload job to find the runner # we are reserving for it (via runner labels), and allows the timeout # job to find the workload job run (via the job’s friendly name), even # if there are multiple instances in the workflow call tree. unique_id=$(uuidgen) echo "unique_id=$unique_id" | tee -a $GITHUB_OUTPUT # Disable self-hosted runners by creating a repository variable named # NO_SELF_HOSTED_RUNNERS with any non-empty value. # if [ -n '${{ vars.NO_SELF_HOSTED_RUNNERS }}' ]; then echo 'NO_SELF_HOSTED_RUNNERS is set!' fall_back_to_github_hosted fi if [ '${{ inputs.force-github-hosted-runner }}' = true ]; then echo 'inputs.force-github-hosted-runner is set!' fall_back_to_github_hosted fi for monitor_api_base_url in $(printf \%s\\n \ https://ci0.servo.org \ https://ci1.servo.org \ https://ci2.servo.org \ | shuf); do # Use the monitor API to reserve a runner. If we get an object with # runner details, we succeeded. If we get null, we failed. take_runner_url=$monitor_api_base_url/profile/$self_hosted_image_name/take\?unique_id=$unique_id\&qualified_repo=${{ github.repository }}\&run_id=${{ github.run_id }} result=$(mktemp) echo echo POST "$take_runner_url" if curl -sS --fail-with-body --connect-timeout 5 --max-time 30 -X POST "$take_runner_url" \ -H 'Authorization: Bearer ${{ secrets.SERVO_CI_MONITOR_API_TOKEN }}' > $result \ && jq -e . $result > /dev/null; then echo echo "selected_runner_label=reserved-for:$unique_id" | tee -a $GITHUB_OUTPUT echo 'is_self_hosted=true' | tee -a $GITHUB_OUTPUT exit 0 fi done cat $result echo echo echo 'No self-hosted runners available!' fall_back_to_github_hosted