Skip to content

Commit 9c5e2a0

Browse files
authored
Fix(ci): fix delete-env failures and add force-delete fallback (#3819)
bosh delete-deployment used an invalid --skip-drain flag, causing it to silently fail every run and leaving bbl down to hit "umount: target is busy" during its own deployment teardown. Fix the flag and add a force-delete-env.sh fallback that tears down the director/jumpbox directly via the GCP CPI when the graceful path can't recover (e.g. abandoned BOSH tasks or a stuck task worker). Signed-off-by: Prem Kumar Kalle <prem.kalle@broadcom.com>
1 parent 6e0364c commit 9c5e2a0

3 files changed

Lines changed: 102 additions & 5 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/bin/bash
2+
# Force-tears-down a bosh-lite environment directly via the GCP CPI and
3+
# gcloud, bypassing bbl/bosh's graceful deployment-deletion path entirely.
4+
#
5+
# Use this when `bbl down` hangs or fails - e.g. warden bind-mount
6+
# "target is busy" errors during deployment deletion, or SSH-tunnel
7+
# connectivity issues to an unhealthy director/jumpbox. `bosh delete-env`
8+
# only needs the local state file + the CPI (GCP API) to destroy a VM, so it
9+
# works even when the director/jumpbox is unresponsive or already gone.
10+
#
11+
# Usage: force-delete-env.sh <env-name>
12+
# Required env vars: BBL_GCP_SERVICE_ACCOUNT_KEY_PATH, GOOGLE_CLOUD_PROJECT,
13+
# BBL_GCP_REGION
14+
# Expects <env-name>/bbl-state to already be downloaded in the cwd.
15+
16+
set -uo pipefail
17+
18+
env_name="$1"
19+
state_dir="${env_name}/bbl-state"
20+
zone="$(jq -r '.gcp.zone' "${state_dir}/bbl-state.json")"
21+
22+
echo "Force-deleting director VM for ${env_name}"
23+
bosh delete-env \
24+
"${state_dir}/bosh-deployment/bosh.yml" \
25+
--state "${state_dir}/vars/bosh-state.json" \
26+
--vars-store "${state_dir}/vars/director-vars-store.yml" \
27+
--vars-file "${state_dir}/vars/director-vars-file.yml" \
28+
-o "${state_dir}/bosh-deployment/gcp/cpi.yml" \
29+
-o "${state_dir}/bosh-deployment/jumpbox-user.yml" \
30+
-o "${state_dir}/bosh-deployment/uaa.yml" \
31+
-o "${state_dir}/bosh-deployment/credhub.yml" \
32+
-o "${state_dir}/bbl-ops-files/gcp/bosh-director-ephemeral-ip-ops.yml" \
33+
--var-file gcp_credentials_json="${BBL_GCP_SERVICE_ACCOUNT_KEY_PATH}" \
34+
-v project_id="${GOOGLE_CLOUD_PROJECT}" \
35+
-v zone="${zone}" \
36+
--non-interactive || true
37+
38+
echo "Force-deleting jumpbox VM for ${env_name}"
39+
bosh delete-env \
40+
"${state_dir}/jumpbox-deployment/jumpbox.yml" \
41+
--state "${state_dir}/vars/jumpbox-state.json" \
42+
--vars-store "${state_dir}/vars/jumpbox-vars-store.yml" \
43+
--vars-file "${state_dir}/vars/jumpbox-vars-file.yml" \
44+
-o "${state_dir}/jumpbox-deployment/gcp/cpi.yml" \
45+
--var-file gcp_credentials_json="${BBL_GCP_SERVICE_ACCOUNT_KEY_PATH}" \
46+
-v project_id="${GOOGLE_CLOUD_PROJECT}" \
47+
-v zone="${zone}" \
48+
--non-interactive || true
49+
50+
tfstate="${state_dir}/vars/terraform.tfstate"
51+
if [ -f "$tfstate" ]; then
52+
echo "Deleting remaining terraform-managed network resources for ${env_name}"
53+
54+
jq -r '.resources[] | select(.type=="google_compute_firewall") | .instances[0].attributes.name' "$tfstate" | \
55+
while read -r name; do gcloud compute firewall-rules delete "$name" --quiet || true; done
56+
57+
jq -r '.resources[] | select(.type=="google_dns_record_set") | "\(.instances[0].attributes.name)\t\(.instances[0].attributes.managed_zone)\t\(.instances[0].attributes.type)"' "$tfstate" | \
58+
while IFS=$'\t' read -r name dns_zone rtype; do gcloud dns record-sets delete "$name" --zone "$dns_zone" --type "$rtype" --quiet || true; done
59+
60+
jq -r '.resources[] | select(.type=="google_compute_route") | .instances[0].attributes.name' "$tfstate" | \
61+
while read -r name; do gcloud compute routes delete "$name" --quiet || true; done
62+
63+
jq -r '.resources[] | select(.type=="google_compute_router") | .instances[0].attributes.name' "$tfstate" | \
64+
while read -r name; do gcloud compute routers delete "$name" --region "${BBL_GCP_REGION}" --quiet || true; done
65+
66+
jq -r '.resources[] | select(.type=="google_compute_address") | .instances[0].attributes.name' "$tfstate" | \
67+
while read -r name; do gcloud compute addresses delete "$name" --region "${BBL_GCP_REGION}" --quiet || true; done
68+
69+
jq -r '.resources[] | select(.type=="google_compute_subnetwork") | .instances[0].attributes.name' "$tfstate" | \
70+
while read -r name; do gcloud compute networks subnets delete "$name" --region "${BBL_GCP_REGION}" --quiet || true; done
71+
72+
jq -r '.resources[] | select(.type=="google_compute_network") | .instances[0].attributes.name' "$tfstate" | \
73+
while read -r name; do gcloud compute networks delete "$name" --quiet || true; done
74+
fi
75+
76+
echo "Force-delete complete for ${env_name}"

.github/workflows/create-bosh-lite.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ jobs:
132132
133133
bosh upload-release "https://bosh.io/d/github.com/cloudfoundry/capi-release?v=$capi_release_version"
134134
- name: Deploy cf
135+
timeout-minutes: 90
135136
run: |
136137
env_name="${{ steps.setup-bbl-env.outputs.envName }}"
137138
cd $env_name/bbl-state

.github/workflows/delete-bosh-lite.yml

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,41 @@ jobs:
6666

6767
- name: Download file from GCS
6868
run: |
69-
gsutil -m cp -P -R gs://cf-cli-bosh-lites/${ENV_NAME} .
69+
gcloud storage cp -r gs://cf-cli-bosh-lites/${ENV_NAME} .
7070
7171
- name: delete bosh
72+
id: delete-bosh
73+
timeout-minutes: 30
74+
continue-on-error: true
7275
run: |
7376
cd ${ENV_NAME}/bbl-state
7477
eval "$(bbl print-env --shell-type posix)"
7578
7679
# Delete the CF deployment first so warden containers release their
77-
# bind mounts on the director's persistent disk.
80+
# bind mounts on the director's persistent disk. --force makes bosh ignore
81+
# per-instance errors (like a busy unmount) and still delete the
82+
# deployment record.
7883
echo "Deleting CF deployment ${BOSH_DEPLOYMENT}"
79-
bosh delete-deployment -d ${BOSH_DEPLOYMENT} --force --skip-drain || true
84+
bosh delete-deployment -d ${BOSH_DEPLOYMENT} --force || true
8085
8186
echo "Deleting env ${ENV_NAME}"
8287
bbl down --no-confirm
83-
88+
89+
- name: force delete env (fallback)
90+
if: steps.delete-bosh.outcome == 'failure'
91+
timeout-minutes: 15
92+
run: |
93+
echo "${BBL_GCP_SERVICE_ACCOUNT_KEY}" > /tmp/gcp_key.json
94+
export BBL_GCP_SERVICE_ACCOUNT_KEY_PATH=/tmp/gcp_key.json
95+
bash ${GITHUB_WORKSPACE}/cli/.github/bosh-lite-files/force-delete-env.sh "${ENV_NAME}"
96+
rm -f /tmp/gcp_key.json
97+
8498
- name: delete gcs bucket
99+
if: always()
100+
run: |
101+
gcloud storage rm -r gs://cf-cli-bosh-lites/${ENV_NAME}
102+
103+
- name: warn if delete bosh needed the fallback
104+
if: steps.delete-bosh.outcome == 'failure'
85105
run: |
86-
gsutil rm -R gs://cf-cli-bosh-lites/${ENV_NAME}
106+
echo "::warning::The graceful 'delete bosh' step failed for ${ENV_NAME} and the environment was torn down via the force-delete-env.sh fallback instead. This usually means an abandoned BOSH task or a warden mount was still busy - see the 'delete bosh' step log for details."

0 commit comments

Comments
 (0)