Skip to content

Commit 0ee51ad

Browse files
committed
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 <dennis@dennisameling.com>
1 parent 295d792 commit 0ee51ad

File tree

1 file changed

+64
-44
lines changed

1 file changed

+64
-44
lines changed

.github/workflows/cleanup-self-hosted-runners.yml

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,58 +13,78 @@ on:
1313
# az ad sp create-for-rbac --name "{YOUR_DESCRIPTIVE_NAME_HERE}" --role contributor \
1414
# --scopes /subscriptions/{SUBSCRIPTION_ID_HERE}/resourceGroups/{RESOURCE_GROUP_HERE} \
1515
# --sdk-auth
16-
# AZURE_RESOURCE_GROUP - Resource group to create the runner(s) in
16+
# AZURE_RESOURCE_GROUP - Resource group to find the runner(s) in. It's recommended to set up a resource
17+
# group specifically for self-hosted Actions Runners.
1718
jobs:
1819
delete-runner:
1920
runs-on: ubuntu-latest
2021
steps:
2122
- uses: actions/checkout@v4
22-
- name: Azure Login
23-
uses: azure/login@v2
23+
- name: Process Azure credentials
24+
uses: actions/github-script@v7
25+
env:
26+
AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }}
2427
with:
25-
creds: ${{ secrets.AZURE_CREDENTIALS }}
28+
script: |
29+
if (!process.env.AZURE_CREDENTIALS) {
30+
core.setFailed('The AZURE_CREDENTIALS secret is required.')
31+
process.exit(1)
32+
}
33+
34+
const azureCredentials = JSON.parse(process.env.AZURE_CREDENTIALS)
35+
const {clientId, clientSecret, tenantId, subscriptionId} = azureCredentials
36+
37+
core.setSecret(clientId)
38+
core.exportVariable('AZURE_CLIENT_ID', clientId)
39+
40+
core.setSecret(clientSecret)
41+
core.exportVariable('AZURE_CLIENT_SECRET', clientSecret)
42+
43+
core.setSecret(tenantId)
44+
core.exportVariable('AZURE_TENANT_ID', tenantId)
45+
46+
core.setSecret(subscriptionId)
47+
core.exportVariable('AZURE_SUBSCRIPTION_ID', subscriptionId)
2648
- name: Discover VMs to delete
27-
uses: azure/CLI@v2
2849
env:
29-
GH_APP_ID: ${{ secrets.GH_APP_ID }}
30-
GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
31-
with:
32-
# Stick to 2.63.0 until jq is added to 2.64.0+ https://github.com/Azure/azure-cli/issues/29830
33-
azcliversion: 2.63.0
34-
inlineScript: |
35-
active_vms=$(az vm list -g ${{ secrets.AZURE_RESOURCE_GROUP }} | jq -c '.[] | {name,timeCreated}')
36-
current_time=$(date +%s)
37-
one_hour_ago=$(($current_time - 3600))
50+
GH_APP_ID: ${{ secrets.GH_APP_ID }}
51+
GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
52+
run: |
53+
az login --service-principal -u ${{ env.AZURE_CLIENT_ID }} -p ${{ env.AZURE_CLIENT_SECRET }} --tenant ${{ env.AZURE_TENANT_ID }}
54+
az account set --subscription ${{ env.AZURE_SUBSCRIPTION_ID }}
55+
active_vms=$(az vm list -g ${{ secrets.AZURE_RESOURCE_GROUP }} | jq -c '.[] | {name,timeCreated}')
56+
current_time=$(date +%s)
57+
one_hour_ago=$(($current_time - 3600))
3858
39-
if [ -z "$active_vms" ]; then
40-
echo "No active VMs found, nothing to do."
41-
exit 0
42-
else
43-
echo "Found these active VMs:"
44-
echo $active_vms
45-
fi
59+
if [ -z "$active_vms" ]; then
60+
echo "No active VMs found, nothing to do."
61+
exit 0
62+
else
63+
echo "Found these active VMs:"
64+
echo $active_vms
65+
fi
4666
47-
for active_vm in ${active_vms[@]}; do
48-
vm_name=$(echo $active_vm | jq '.name')
49-
# Use jq to extract and format the date-time string
50-
vm_creation_time_string="$(echo $active_vm |
51-
jq -r '.timeCreated | sub("\\.[0-9]+[+-][0-9]+:[0-9]+$"; "") | sub("T"; " ")')"
52-
vm_creation_time=$(TZ=UTC date -d "$vm_creation_time_string" +%s)
67+
for active_vm in ${active_vms[@]}; do
68+
vm_name=$(echo $active_vm | jq -r '.name')
69+
# Use jq to extract and format the date-time string
70+
vm_creation_time_string="$(echo $active_vm |
71+
jq -r '.timeCreated | sub("\\.[0-9]+[+-][0-9]+:[0-9]+$"; "") | sub("T"; " ")')"
72+
vm_creation_time=$(TZ=UTC date -d "$vm_creation_time_string" +%s)
5373
54-
if [ "$one_hour_ago" -lt "$vm_creation_time" ]; then
55-
echo "::notice::The VM ${vm_name} was created less then 1 hour ago and shouldn't be deleted yet. Skipping."
56-
elif test true = "$(if test ! -f .cli-authenticated; then
57-
./gh-cli-auth-as-app.sh &&
58-
>.cli-authenticated # only authenticate once
59-
fi &&
60-
gh api repos/$GITHUB_REPOSITORY/actions/runners \
61-
--jq '.runners[] | select(.name == "'$vm_name'") | .busy')"; then
62-
echo "::notice::The VM ${vm_name} is still busy."
63-
else
64-
echo "::warning::The VM ${vm_name} was created more than 3 hours ago and wasn't deleted. Let's do that now."
65-
az vm delete -n "$vm_name" -g ${{ secrets.AZURE_RESOURCE_GROUP }} --yes
66-
az network nsg delete -n "$vm_name"-nsg -g ${{ secrets.AZURE_RESOURCE_GROUP }}
67-
az network vnet delete -n "$vm_name"-vnet -g ${{ secrets.AZURE_RESOURCE_GROUP }}
68-
az network public-ip delete -n "$vm_name"-ip -g ${{ secrets.AZURE_RESOURCE_GROUP }}
69-
fi
70-
done
74+
if [ "$one_hour_ago" -lt "$vm_creation_time" ]; then
75+
echo "::notice::The VM ${vm_name} was created less then 1 hour ago and shouldn't be deleted yet. Skipping."
76+
elif test true = "$(if test ! -f .cli-authenticated; then
77+
./gh-cli-auth-as-app.sh &&
78+
>.cli-authenticated # only authenticate once
79+
fi &&
80+
gh api repos/$GITHUB_REPOSITORY/actions/runners \
81+
--jq '.runners[] | select(.name == "'$vm_name'") | .busy')"; then
82+
echo "::notice::The VM ${vm_name} is still busy."
83+
else
84+
echo "::warning::The VM ${vm_name} was created more than 3 hours ago and wasn't deleted. Let's do that now."
85+
az vm delete -n "$vm_name" -g ${{ secrets.AZURE_RESOURCE_GROUP }} --yes
86+
az network nsg delete -n "$vm_name"-nsg -g ${{ secrets.AZURE_RESOURCE_GROUP }}
87+
az network vnet delete -n "$vm_name"-vnet -g ${{ secrets.AZURE_RESOURCE_GROUP }}
88+
az network public-ip delete -n "$vm_name"-ip -g ${{ secrets.AZURE_RESOURCE_GROUP }}
89+
fi
90+
done

0 commit comments

Comments
 (0)