Skip to content

Commit bc3bf9f

Browse files
committed
Refactor nuke workflow using reusable workflow pattern
Extract common nuke logic into nuke-account.yml reusable workflow: - Single definition of global/regional/notify jobs - Parameterized: account_name, role_arn, older_than, extra_excludes - Main nuke.yml reduced from 579 to 70 lines (88% reduction) Each account call passes its specific configuration while sharing the same underlying job definitions.
1 parent db7ee0a commit bc3bf9f

File tree

2 files changed

+241
-531
lines changed

2 files changed

+241
-531
lines changed

.github/workflows/nuke-account.yml

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
name: Nuke Account
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
account_name:
7+
required: true
8+
type: string
9+
role_arn:
10+
required: true
11+
type: string
12+
older_than:
13+
required: true
14+
type: string
15+
extra_excludes:
16+
required: false
17+
type: string
18+
default: ''
19+
20+
env:
21+
MISE_VERSION: '2025.12.10'
22+
COMMON_EXCLUDES: >-
23+
--exclude-resource-type iam
24+
--exclude-resource-type iam-group
25+
--exclude-resource-type iam-policy
26+
--exclude-resource-type iam-role
27+
--exclude-resource-type iam-service-linked-role
28+
--exclude-resource-type oidcprovider
29+
--exclude-resource-type route53-hosted-zone
30+
--exclude-resource-type route53-cidr-collection
31+
--exclude-resource-type route53-traffic-policy
32+
--exclude-resource-type ecr
33+
--exclude-resource-type config-rules
34+
--exclude-resource-type nat-gateway
35+
--exclude-resource-type ec2-subnet
36+
37+
jobs:
38+
global:
39+
name: "${{ inputs.account_name }}: Global"
40+
runs-on: ubuntu-latest
41+
timeout-minutes: 30
42+
outputs:
43+
deleted_count: ${{ steps.nuke.outputs.deleted_count }}
44+
error_count: ${{ steps.nuke.outputs.error_count }}
45+
steps:
46+
- uses: actions/checkout@v4
47+
- uses: aws-actions/configure-aws-credentials@v4
48+
with:
49+
role-to-assume: ${{ inputs.role_arn }}
50+
aws-region: us-east-1
51+
- uses: jdx/mise-action@v3
52+
with:
53+
version: ${{ env.MISE_VERSION }}
54+
experimental: true
55+
env:
56+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
- uses: actions/cache@v4
58+
with:
59+
path: |
60+
~/go/pkg/mod
61+
~/.cache/go-build
62+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
63+
restore-keys: ${{ runner.os }}-go-
64+
- run: go mod download
65+
- name: Nuke global resources
66+
id: nuke
67+
run: |
68+
set +e
69+
go run -ldflags="-X 'main.VERSION=${{ github.sha }}'" main.go aws \
70+
--older-than ${{ inputs.older_than }} --force --config ./.github/nuke_config.yml \
71+
--region global ${{ env.COMMON_EXCLUDES }} ${{ inputs.extra_excludes }} \
72+
--delete-unaliased-kms-keys --log-level info 2>&1 | tee /tmp/nuke.log
73+
EXIT_CODE=${PIPESTATUS[0]}
74+
75+
DELETED=$(grep -c "^\s*INFO\s*\[Deleted\]" /tmp/nuke.log || echo "0")
76+
ERRORS=$(grep -c "^\s*ERROR\s*\[Failed\]" /tmp/nuke.log || echo "0")
77+
echo "deleted_count=${DELETED}" >> $GITHUB_OUTPUT
78+
echo "error_count=${ERRORS}" >> $GITHUB_OUTPUT
79+
80+
exit $EXIT_CODE
81+
- name: Upload global log
82+
if: always()
83+
uses: actions/upload-artifact@v4
84+
with:
85+
name: ${{ inputs.account_name }}-global
86+
path: /tmp/nuke.log
87+
retention-days: 7
88+
89+
regional:
90+
name: "${{ inputs.account_name }}: ${{ matrix.region }}"
91+
runs-on: ubuntu-latest
92+
timeout-minutes: 20
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
region:
97+
- ap-northeast-1
98+
- ap-northeast-2
99+
- ap-northeast-3
100+
- ap-south-1
101+
- ap-southeast-1
102+
- ap-southeast-2
103+
- ca-central-1
104+
- eu-central-1
105+
- eu-north-1
106+
- eu-west-1
107+
- eu-west-2
108+
- eu-west-3
109+
- me-central-1
110+
- sa-east-1
111+
- us-east-1
112+
- us-east-2
113+
- us-west-1
114+
- us-west-2
115+
steps:
116+
- uses: actions/checkout@v4
117+
- uses: aws-actions/configure-aws-credentials@v4
118+
with:
119+
role-to-assume: ${{ inputs.role_arn }}
120+
aws-region: ${{ matrix.region }}
121+
- uses: jdx/mise-action@v3
122+
with:
123+
version: ${{ env.MISE_VERSION }}
124+
experimental: true
125+
env:
126+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
127+
- uses: actions/cache@v4
128+
with:
129+
path: |
130+
~/go/pkg/mod
131+
~/.cache/go-build
132+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
133+
restore-keys: ${{ runner.os }}-go-
134+
- run: go mod download
135+
- name: Nuke ${{ matrix.region }}
136+
id: nuke
137+
run: |
138+
set +e
139+
go run -ldflags="-X 'main.VERSION=${{ github.sha }}'" main.go aws \
140+
--older-than ${{ inputs.older_than }} --force --config ./.github/nuke_config.yml \
141+
--region ${{ matrix.region }} ${{ env.COMMON_EXCLUDES }} ${{ inputs.extra_excludes }} \
142+
--delete-unaliased-kms-keys --log-level info 2>&1 | tee /tmp/nuke.log
143+
EXIT_CODE=${PIPESTATUS[0]}
144+
145+
DELETED=$(grep -c "^\s*INFO\s*\[Deleted\]" /tmp/nuke.log || echo "0")
146+
ERRORS=$(grep -c "^\s*ERROR\s*\[Failed\]" /tmp/nuke.log || echo "0")
147+
echo "deleted_count=${DELETED}" >> $GITHUB_OUTPUT
148+
echo "error_count=${ERRORS}" >> $GITHUB_OUTPUT
149+
150+
exit $EXIT_CODE
151+
- name: Upload results
152+
if: always()
153+
uses: actions/upload-artifact@v4
154+
with:
155+
name: ${{ inputs.account_name }}-${{ matrix.region }}
156+
path: /tmp/nuke.log
157+
retention-days: 7
158+
159+
notify:
160+
name: "${{ inputs.account_name }}: Notify"
161+
runs-on: ubuntu-latest
162+
if: always()
163+
needs: [global, regional]
164+
steps:
165+
- uses: aws-actions/configure-aws-credentials@v4
166+
with:
167+
role-to-assume: arn:aws:iam::087285199408:role/cloud-nuke-gha
168+
aws-region: us-east-1
169+
- name: Download all artifacts
170+
uses: actions/download-artifact@v4
171+
with:
172+
pattern: ${{ inputs.account_name }}-*
173+
path: /tmp/logs
174+
merge-multiple: true
175+
continue-on-error: true
176+
- name: Aggregate and notify
177+
run: |
178+
WEBHOOK_URL=$(aws secretsmanager get-secret-value \
179+
--secret-id cloud-nuke/slack-webhook \
180+
--query SecretString --output text)
181+
182+
TOTAL_DELETED=0
183+
TOTAL_ERRORS=0
184+
if [ -d /tmp/logs ]; then
185+
TOTAL_DELETED=$(grep -rh "^\s*INFO\s*\[Deleted\]" /tmp/logs 2>/dev/null | wc -l || echo "0")
186+
TOTAL_ERRORS=$(grep -rh "^\s*ERROR\s*\[Failed\]" /tmp/logs 2>/dev/null | wc -l || echo "0")
187+
fi
188+
189+
if [ "${{ needs.global.result }}" == "success" ] && \
190+
[ "${{ needs.regional.result }}" == "success" ]; then
191+
STATUS="✅ Success"
192+
COLOR="good"
193+
else
194+
STATUS="❌ Failed"
195+
COLOR="danger"
196+
fi
197+
198+
MSG="*${{ inputs.account_name }} Nuke*: ${STATUS}"
199+
MSG="${MSG}\nDeleted: ${TOTAL_DELETED} resources"
200+
if [ "$TOTAL_ERRORS" -gt 0 ]; then
201+
MSG="${MSG} | Errors: ${TOTAL_ERRORS}"
202+
fi
203+
MSG="${MSG}\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>"
204+
205+
curl -sS -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d @- <<EOF
206+
{
207+
"attachments": [{
208+
"color": "${COLOR}",
209+
"blocks": [{
210+
"type": "section",
211+
"text": {
212+
"type": "mrkdwn",
213+
"text": "${MSG}"
214+
}
215+
}]
216+
}]
217+
}
218+
EOF

0 commit comments

Comments
 (0)