You've already forked tribes-supertest
fix: clean up DNS zones
Add DNS-zone cleanup for Hetzner and OVH, best-effort Scaleway external-domain cleanup, and update the OVH block volume command to the current storage block CLI path.
This commit is contained in:
@@ -19,7 +19,7 @@ usage() {
|
||||
cat <<'USAGE'
|
||||
Usage: scripts/cleanup-cloud-resources [OPTIONS]
|
||||
|
||||
Delete cloud resources from the provider accounts used by supertest.
|
||||
Delete cloud resources and DNS zones from the provider accounts used by supertest.
|
||||
This does not read, modify, or remove Legion state or supertest artifacts.
|
||||
|
||||
Options:
|
||||
@@ -64,6 +64,12 @@ is_test_name() {
|
||||
[[ "$name" == st-* || "$name" == *tribes-supertest* || "$name" == *legion-supertest* ]]
|
||||
}
|
||||
|
||||
normalize_dns_name() {
|
||||
local name="${1:-}"
|
||||
name="${name%.}"
|
||||
printf '%s' "${name,,}"
|
||||
}
|
||||
|
||||
json_array() {
|
||||
jq -c 'if type == "array" then . elif . == null then [] else [.] end'
|
||||
}
|
||||
@@ -82,6 +88,64 @@ run_delete() {
|
||||
"$@"
|
||||
}
|
||||
|
||||
run_ovh_api_post() {
|
||||
local path="$1"
|
||||
|
||||
if (( dry_run )); then
|
||||
printf '+ ovh-api POST %q\n' "$path"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '+ ovh-api POST %q\n' "$path"
|
||||
node - "$path" <<'NODE'
|
||||
const crypto = require("node:crypto")
|
||||
|
||||
async function main() {
|
||||
const path = process.argv[2]
|
||||
const endpoint = (process.env.OVH_ENDPOINT || "ovh-eu").trim()
|
||||
const appKey = (process.env.OVH_APPLICATION_KEY || process.env.OVH_APP_KEY || "").trim()
|
||||
const appSecret = (process.env.OVH_APPLICATION_SECRET || process.env.OVH_APP_SECRET || "").trim()
|
||||
const consumerKey = (process.env.OVH_CONSUMER_KEY || "").trim()
|
||||
const host = endpoint === "ovh-ca" ? "ca.api.ovh.com" : "eu.api.ovh.com"
|
||||
const baseUrl = `https://${host}/1.0`
|
||||
|
||||
if (!appKey || !appSecret || !consumerKey) {
|
||||
throw new Error("OVH application key/secret or consumer key is not set.")
|
||||
}
|
||||
|
||||
const timeResponse = await fetch(`${baseUrl}/auth/time`, {
|
||||
headers: { "X-Ovh-Application": appKey }
|
||||
})
|
||||
if (!timeResponse.ok) {
|
||||
throw new Error(`OVH auth time failed: ${timeResponse.status} ${await timeResponse.text()}`)
|
||||
}
|
||||
const timestamp = (await timeResponse.text()).trim()
|
||||
const method = "POST"
|
||||
const body = ""
|
||||
const url = `${baseUrl}${path}`
|
||||
const signaturePayload = [appSecret, consumerKey, method, url, body, timestamp].join("+")
|
||||
const signature = `$1$${crypto.createHash("sha1").update(signaturePayload).digest("hex")}`
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
"X-Ovh-Application": appKey,
|
||||
"X-Ovh-Consumer": consumerKey,
|
||||
"X-Ovh-Signature": signature,
|
||||
"X-Ovh-Timestamp": timestamp
|
||||
}
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error(`OVH API POST ${path} failed: ${response.status} ${await response.text()}`)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.message : String(error))
|
||||
process.exit(1)
|
||||
})
|
||||
NODE
|
||||
}
|
||||
|
||||
delete_hcloud_collection() {
|
||||
local resource="$1"
|
||||
local label="$2"
|
||||
@@ -117,6 +181,7 @@ cleanup_hetzner() {
|
||||
delete_hcloud_collection primary-ip "primary IP"
|
||||
delete_hcloud_collection firewall "firewall"
|
||||
delete_hcloud_collection network "network"
|
||||
delete_hcloud_collection zone "DNS zone"
|
||||
|
||||
local list
|
||||
if ! list="$(hcloud ssh-key list -o json)"; then
|
||||
@@ -229,6 +294,36 @@ cleanup_scaleway_zone() {
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup_scaleway_dns_zones() {
|
||||
local domain
|
||||
domain="$(normalize_dns_name "${SUPERTEST_DNS_DOMAIN:-}")"
|
||||
|
||||
if [[ -z "$domain" ]]; then
|
||||
warn "skipping Scaleway DNS zone cleanup; Scaleway external-domain API has no list command and SUPERTEST_DNS_DOMAIN is not set"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Deleting Scaleway external DNS zone: $domain"
|
||||
if (( dry_run )); then
|
||||
run_delete scw domain external-domain delete domain="$domain"
|
||||
return
|
||||
fi
|
||||
|
||||
local output
|
||||
if output="$(run_delete scw domain external-domain delete domain="$domain" 2>&1)"; then
|
||||
printf '%s\n' "$output"
|
||||
return
|
||||
fi
|
||||
|
||||
if grep -qi 'domain not found' <<<"$output"; then
|
||||
log "Scaleway external DNS zone not found: $domain"
|
||||
return
|
||||
fi
|
||||
|
||||
printf '%s\n' "$output" >&2
|
||||
fail "failed to delete Scaleway external DNS zone $domain"
|
||||
}
|
||||
|
||||
cleanup_scaleway() {
|
||||
if [[ -z "${SCW_ACCESS_KEY:-}" || -z "${SCW_SECRET_KEY:-}" || -z "${SCW_DEFAULT_PROJECT_ID:-}" ]]; then
|
||||
warn "skipping Scaleway cleanup; SCW_ACCESS_KEY, SCW_SECRET_KEY, or SCW_DEFAULT_PROJECT_ID is not set"
|
||||
@@ -243,6 +338,7 @@ cleanup_scaleway() {
|
||||
for zone in "${scaleway_zones[@]}"; do
|
||||
cleanup_scaleway_zone "$zone"
|
||||
done
|
||||
cleanup_scaleway_dns_zones
|
||||
}
|
||||
|
||||
ovh_project_ids() {
|
||||
@@ -294,11 +390,11 @@ cleanup_ovh_project() {
|
||||
warn "failed to list OVH instance snapshots for project $project"
|
||||
fi
|
||||
|
||||
if list="$(ovh_list_project "$project" storage-block)"; then
|
||||
if list="$(ovh_list_project "$project" storage block)"; then
|
||||
while IFS=$'\t' read -r id name; do
|
||||
[[ -n "${id:-}" ]] || continue
|
||||
log "Deleting OVH block volume: ${name:-$id} ($id)"
|
||||
run_delete ovhcloud cloud storage-block delete "$id" --cloud-project "$project" ||
|
||||
run_delete ovhcloud cloud storage block delete "$id" --cloud-project "$project" ||
|
||||
fail "failed to delete OVH block volume $id"
|
||||
done < <(printf '%s\n' "$list" | jq -r '.[] | [.id, (.name // "")] | @tsv')
|
||||
else
|
||||
@@ -336,6 +432,25 @@ cleanup_ovh_project() {
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup_ovh_dns_zones() {
|
||||
local list
|
||||
|
||||
if ! list="$(ovhcloud domain-zone list -o json 2>/dev/null | json_array)"; then
|
||||
fail "failed to list OVH DNS zones"
|
||||
return
|
||||
fi
|
||||
|
||||
while IFS= read -r zone; do
|
||||
[[ -n "$zone" ]] || continue
|
||||
local encoded_zone
|
||||
encoded_zone="$(jq -rn --arg value "$zone" '$value | @uri')"
|
||||
log "Requesting OVH DNS zone termination: $zone"
|
||||
run_ovh_api_post "/domain/zone/${encoded_zone}/terminate" ||
|
||||
fail "failed to request OVH DNS zone termination for $zone"
|
||||
log "OVH requires email or Manager confirmation before DNS zone $zone is permanently deleted."
|
||||
done < <(printf '%s\n' "$list" | jq -r '.[] | .name // .zoneName // .id // empty')
|
||||
}
|
||||
|
||||
cleanup_ovh() {
|
||||
if [[ -z "${OVH_APP_KEY:-}${OVH_APPLICATION_KEY:-}" ||
|
||||
-z "${OVH_APP_SECRET:-}${OVH_APPLICATION_SECRET:-}" ||
|
||||
@@ -358,6 +473,7 @@ cleanup_ovh() {
|
||||
[[ -n "$project" ]] || continue
|
||||
cleanup_ovh_project "$project"
|
||||
done <<<"$projects"
|
||||
cleanup_ovh_dns_zones
|
||||
}
|
||||
|
||||
selected_providers=()
|
||||
|
||||
Reference in New Issue
Block a user