From 26e02cae1a076d4ba2af953d71c2773662c572c7 Mon Sep 17 00:00:00 2001 From: Dennis Ameling Date: Wed, 18 Sep 2024 22:18:21 +0200 Subject: [PATCH] Self-hosted runner cleanup: use Ubuntu instead of azure/cli action The `azure/cli` GitHub Action runs in a Docker container with Alpine or Azure Linux, meaning that many tools like `node` and `gh` (which we rely on) aren't available. Since the Azure CLI is available in the GitHub-hosted `ubuntu-latest` image anyway, let's leverage that instead. In the end, it has all the other tools we need as well. Ref: https://github.com/actions/runner-images/blob/ce2a3e8e67858dc8c3dd77aca6b29e2956d934ed/images/ubuntu/Ubuntu2404-Readme.md?plain=1#L105 Signed-off-by: Dennis Ameling --- .../workflows/cleanup-self-hosted-runners.yml | 108 +++++++++++------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/.github/workflows/cleanup-self-hosted-runners.yml b/.github/workflows/cleanup-self-hosted-runners.yml index 4e16891c..1fc624f8 100644 --- a/.github/workflows/cleanup-self-hosted-runners.yml +++ b/.github/workflows/cleanup-self-hosted-runners.yml @@ -13,58 +13,78 @@ on: # az ad sp create-for-rbac --name "{YOUR_DESCRIPTIVE_NAME_HERE}" --role contributor \ # --scopes /subscriptions/{SUBSCRIPTION_ID_HERE}/resourceGroups/{RESOURCE_GROUP_HERE} \ # --sdk-auth -# AZURE_RESOURCE_GROUP - Resource group to create the runner(s) in +# AZURE_RESOURCE_GROUP - Resource group to find the runner(s) in. It's recommended to set up a resource +# group specifically for self-hosted Actions Runners. jobs: delete-runner: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Azure Login - uses: azure/login@v2 + - name: Process Azure credentials + uses: actions/github-script@v7 + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + script: | + if (!process.env.AZURE_CREDENTIALS) { + core.setFailed('The AZURE_CREDENTIALS secret is required.') + process.exit(1) + } + + const azureCredentials = JSON.parse(process.env.AZURE_CREDENTIALS) + const {clientId, clientSecret, tenantId, subscriptionId} = azureCredentials + + core.setSecret(clientId) + core.exportVariable('AZURE_CLIENT_ID', clientId) + + core.setSecret(clientSecret) + core.exportVariable('AZURE_CLIENT_SECRET', clientSecret) + + core.setSecret(tenantId) + core.exportVariable('AZURE_TENANT_ID', tenantId) + + core.setSecret(subscriptionId) + core.exportVariable('AZURE_SUBSCRIPTION_ID', subscriptionId) - name: Discover VMs to delete - uses: azure/CLI@v2 env: - GH_APP_ID: ${{ secrets.GH_APP_ID }} - GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }} - with: - # Stick to 2.63.0 until jq is added to 2.64.0+ https://github.com/Azure/azure-cli/issues/29830 - azcliversion: 2.63.0 - inlineScript: | - active_vms=$(az vm list -g ${{ secrets.AZURE_RESOURCE_GROUP }} | jq -c '.[] | {name,timeCreated}') - current_time=$(date +%s) - one_hour_ago=$(($current_time - 3600)) + GH_APP_ID: ${{ secrets.GH_APP_ID }} + GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }} + run: | + az login --service-principal -u ${{ env.AZURE_CLIENT_ID }} -p ${{ env.AZURE_CLIENT_SECRET }} --tenant ${{ env.AZURE_TENANT_ID }} + az account set --subscription ${{ env.AZURE_SUBSCRIPTION_ID }} + active_vms=$(az vm list -g ${{ secrets.AZURE_RESOURCE_GROUP }} | jq -c '.[] | {name,timeCreated}') + current_time=$(date +%s) + one_hour_ago=$(($current_time - 3600)) - if [ -z "$active_vms" ]; then - echo "No active VMs found, nothing to do." - exit 0 - else - echo "Found these active VMs:" - echo $active_vms - fi + if [ -z "$active_vms" ]; then + echo "No active VMs found, nothing to do." + exit 0 + else + echo "Found these active VMs:" + echo $active_vms + fi - for active_vm in ${active_vms[@]}; do - vm_name=$(echo $active_vm | jq '.name') - # Use jq to extract and format the date-time string - vm_creation_time_string="$(echo $active_vm | - jq -r '.timeCreated | sub("\\.[0-9]+[+-][0-9]+:[0-9]+$"; "") | sub("T"; " ")')" - vm_creation_time=$(TZ=UTC date -d "$vm_creation_time_string" +%s) + for active_vm in ${active_vms[@]}; do + vm_name=$(echo $active_vm | jq '.name') + # Use jq to extract and format the date-time string + vm_creation_time_string="$(echo $active_vm | + jq -r '.timeCreated | sub("\\.[0-9]+[+-][0-9]+:[0-9]+$"; "") | sub("T"; " ")')" + vm_creation_time=$(TZ=UTC date -d "$vm_creation_time_string" +%s) - if [ "$one_hour_ago" -lt "$vm_creation_time" ]; then - echo "::notice::The VM ${vm_name} was created less then 1 hour ago and shouldn't be deleted yet. Skipping." - elif test true = "$(if test ! -f .cli-authenticated; then - ./gh-cli-auth-as-app.sh && - >.cli-authenticated # only authenticate once - fi && - gh api repos/$GITHUB_REPOSITORY/actions/runners \ - --jq '.runners[] | select(.name == "'$vm_name'") | .busy')"; then - echo "::notice::The VM ${vm_name} is still busy." - else - echo "::warning::The VM ${vm_name} was created more than 3 hours ago and wasn't deleted. Let's do that now." - az vm delete -n "$vm_name" -g ${{ secrets.AZURE_RESOURCE_GROUP }} --yes - az network nsg delete -n "$vm_name"-nsg -g ${{ secrets.AZURE_RESOURCE_GROUP }} - az network vnet delete -n "$vm_name"-vnet -g ${{ secrets.AZURE_RESOURCE_GROUP }} - az network public-ip delete -n "$vm_name"-ip -g ${{ secrets.AZURE_RESOURCE_GROUP }} - fi - done + if [ "$one_hour_ago" -lt "$vm_creation_time" ]; then + echo "::notice::The VM ${vm_name} was created less then 1 hour ago and shouldn't be deleted yet. Skipping." + elif test true = "$(if test ! -f .cli-authenticated; then + ./gh-cli-auth-as-app.sh && + >.cli-authenticated # only authenticate once + fi && + gh api repos/$GITHUB_REPOSITORY/actions/runners \ + --jq '.runners[] | select(.name == "'$vm_name'") | .busy')"; then + echo "::notice::The VM ${vm_name} is still busy." + else + echo "::warning::The VM ${vm_name} was created more than 3 hours ago and wasn't deleted. Let's do that now." + az vm delete -n "$vm_name" -g ${{ secrets.AZURE_RESOURCE_GROUP }} --yes + az network nsg delete -n "$vm_name"-nsg -g ${{ secrets.AZURE_RESOURCE_GROUP }} + az network vnet delete -n "$vm_name"-vnet -g ${{ secrets.AZURE_RESOURCE_GROUP }} + az network public-ip delete -n "$vm_name"-ip -g ${{ secrets.AZURE_RESOURCE_GROUP }} + fi + done