diff --git a/cmd/ate-setup/commands.md b/cmd/ate-setup/commands.md index 0506efd3ac..99d1b26ed1 100644 --- a/cmd/ate-setup/commands.md +++ b/cmd/ate-setup/commands.md @@ -173,6 +173,7 @@ The demo list is not hard-coded here — it is built from the registry in `go run ./cmd/ate-setup deploy demo --help` is authoritative for both the list and the per-demo flags. -Each demo previously had its own `hack/install-demo-*.sh`, sourced by the -installer, which registered the flags above. Those scripts are gone; the demos -now live in [`internal/demos`](internal/demos). +The demos also each have a `hack/install-demo-*.sh`, sourced by +`hack/install-ate.sh`, which registers `--deploy-demo-NAME` / +`--delete-demo-NAME` flags on that installer. ate-setup does not use those +scripts; its demos live in [`internal/demos`](internal/demos). diff --git a/hack/teardown.sh b/hack/teardown.sh index 2f0258de65..831a7793b6 100755 --- a/hack/teardown.sh +++ b/hack/teardown.sh @@ -16,18 +16,28 @@ set -o errexit -o nounset -o pipefail -# Source the environment variables +# Source the environment variables. The file is optional: an installer (or a +# user pasting a one-liner) can pass the same variables through the +# environment instead, which also makes teardown possible on a machine that +# never had a dev-env file. if [ -f .ate-dev-env.sh ]; then source .ate-dev-env.sh -else - echo "Please create .ate-dev-env.sh from the example file in hack" - exit 1 fi +# No cluster-admin precheck here: every step below talks to GCP, not to the +# cluster, and requiring a live kubectl context would block tearing down a +# cluster that is already half-gone. -# Precheck for cluster-admin permissions -kubectl auth can-i delete crd 2>/dev/null | grep -q yes || { - echo "teardown requires cluster-admin on the GKE cluster" >&2 - exit 1 +# require checks that each named variable is set, so a step fails up front +# with the variable's name rather than mid-deletion with a gcloud error. Each +# step declares only what it uses: deleting a bucket must not demand a node +# pool name. +require() { + for var in "$@"; do + if [ -z "${!var:-}" ]; then + echo "${var} is not set; export it or create .ate-dev-env.sh from the example file in hack" >&2 + exit 1 + fi + done } # --- Helper Functions --- @@ -35,10 +45,12 @@ function usage() { echo "Usage: $0 [options]" echo "Options:" echo " --revoke-gke-node-permissions Revoke GKE nodes permission to pull images" + echo " --revoke-atelet-permissions Revoke atelet's project-level IAM bindings" echo " --delete-iam-policy-bindings Delete IAM policy bindings for atelet" echo " --delete-snapshot-bucket Delete snapshot bucket" echo " --delete-gvisor-node-pool Delete gVisor node pool" echo " --delete-cluster Delete GKE cluster" + echo " --delete-dashboards Delete the Substrate monitoring dashboards" echo " --all Run all teardown steps (reverse order of setup)" exit 1 } @@ -47,6 +59,7 @@ function usage() { # Revoke GKE Node Permissions (Reverse of grant_gke_node_permissions) revoke_gke_node_permissions() { + require PROJECT_ID PROJECT_NUMBER echo "Revoking GKE node permissions..." gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ @@ -60,8 +73,48 @@ revoke_gke_node_permissions() { --quiet || true } +# Revoke Atelet's project-level bindings (Reverse of grant_atelet_permissions) +revoke_atelet_permissions() { + require PROJECT_ID PROJECT_NUMBER + echo "Revoking atelet project-level permissions..." + local member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/ate-system/sa/atelet" + gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \ + --member="${member}" \ + --role="roles/storage.objectAdmin" \ + --condition=None \ + --quiet || true + gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \ + --member="${member}" \ + --role="roles/artifactregistry.reader" \ + --condition=None \ + --quiet || true +} + +# Delete Monitoring Dashboards (Reverse of create_monitoring_dashboards) +delete_dashboards() { + require PROJECT_ID + echo "Deleting Substrate monitoring dashboards..." + # Matched by display name, since setup only records names in its JSON. + local names=( + "Substrate Snapshot Size & QPS" + "Substrate Routing & E2E Latency" + "Substrate gRPC Server — latency / QPS / errors" + ) + for display_name in "${names[@]}"; do + for dashboard in $(gcloud monitoring dashboards list \ + --project="${PROJECT_ID}" \ + --filter="displayName=\"${display_name}\"" \ + --format="value(name)" 2>/dev/null); do + gcloud monitoring dashboards delete "${dashboard}" \ + --project="${PROJECT_ID}" \ + --quiet || true + done + done +} + # Delete IAM Policy Bindings for Bucket (Reverse of create_iam_policy_bindings) delete_iam_policy_bindings() { + require PROJECT_ID PROJECT_NUMBER BUCKET_NAME echo "Deleting IAM policy bindings for bucket..." gcloud storage buckets remove-iam-policy-binding "gs://${BUCKET_NAME}" \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/ate-system/sa/atelet" \ @@ -75,6 +128,7 @@ delete_iam_policy_bindings() { # Delete Snapshot Bucket (Reverse of create_snapshot_bucket) delete_snapshot_bucket() { + require PROJECT_ID BUCKET_NAME echo "Deleting snapshot bucket..." gcloud storage rm --recursive "gs://${BUCKET_NAME}/**" --project="${PROJECT_ID}" --quiet || true gcloud storage buckets delete "gs://${BUCKET_NAME}" --project="${PROJECT_ID}" --quiet || true @@ -82,6 +136,7 @@ delete_snapshot_bucket() { # Delete gVisor Node Pool (Reverse of create_gvisor_node_pool) delete_gvisor_node_pool() { + require PROJECT_ID CLUSTER_NAME CLUSTER_LOCATION NODE_POOL_NAME echo "Deleting gVisor node pool..." gcloud container node-pools delete "${NODE_POOL_NAME}" \ --cluster="${CLUSTER_NAME}" \ @@ -92,6 +147,7 @@ delete_gvisor_node_pool() { # Delete Cluster (Reverse of create_cluster) delete_cluster() { + require PROJECT_ID CLUSTER_NAME CLUSTER_LOCATION echo "Deleting GKE cluster..." gcloud container clusters delete "${CLUSTER_NAME}" \ --location="${CLUSTER_LOCATION}" \ @@ -107,15 +163,25 @@ fi while [[ "$#" -gt 0 ]]; do case $1 in --revoke-gke-node-permissions) revoke_gke_node_permissions ;; + --revoke-atelet-permissions) revoke_atelet_permissions ;; --delete-iam-policy-bindings) delete_iam_policy_bindings ;; --delete-snapshot-bucket) delete_snapshot_bucket ;; --delete-gvisor-node-pool) delete_gvisor_node_pool ;; --delete-cluster) delete_cluster ;; + --delete-dashboards) delete_dashboards ;; --all) - revoke_gke_node_permissions + delete_dashboards delete_iam_policy_bindings + revoke_atelet_permissions + revoke_gke_node_permissions delete_snapshot_bucket - delete_gvisor_node_pool + # Deleting the cluster removes its node pools, so --all does not insist + # on a pool name a caller (e.g. an installer) may not track. + if [ -n "${NODE_POOL_NAME:-}" ]; then + delete_gvisor_node_pool + else + echo "NODE_POOL_NAME not set; skipping node pool deletion (the cluster deletion removes its pools)" + fi delete_cluster ;; *) usage ;; diff --git a/tools/setup-gcp/cmd/api.go b/tools/setup-gcp/cmd/api.go index c80916fc89..586eca8f31 100644 --- a/tools/setup-gcp/cmd/api.go +++ b/tools/setup-gcp/cmd/api.go @@ -32,6 +32,7 @@ func enableRequiredAPIs(ctx context.Context, cfg *Config) error { defer suClient.Close() services := []string{ + "artifactregistry.googleapis.com", "cloudresourcemanager.googleapis.com", "container.googleapis.com", "networkconnectivity.googleapis.com",