#!/usr/bin/env bash # ============================================================================= # remove-app.sh — tear down everything created by prepare-app.sh. # # Does NOT touch any existing resources outside sk1-* and the named VM. # Idempotent: safe to re-run; each step skips if already gone. # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" if [ ! -f .env ]; then echo "ERROR: .env not found in $SCRIPT_DIR" >&2 exit 1 fi set -a; source .env; set +a : "${OCI_VM_NAME:=sk1-expense-tracker}" : "${OCI_SSH_PRIVATE_KEY_PATH:=$HOME/.ssh/id_ed25519}" OCI_SSH_PRIVATE_KEY_PATH="${OCI_SSH_PRIVATE_KEY_PATH/#\~/$HOME}" command -v oci >/dev/null || { echo "ERROR: oci CLI not installed"; exit 1; } TENANCY_OCID="$(oci iam compartment list --query 'data[0]."compartment-id"' --raw-output 2>/dev/null)" COMPARTMENT_ID="${OCI_COMPARTMENT_ID:-$TENANCY_OCID}" VCN_NAME="sk1-vcn" SUBNET_NAME="sk1-subnet" IG_NAME="sk1-ig" SL_NAME="sk1-seclist" RT_NAME="sk1-rt" # ---- Find the VM by name ---- INSTANCE_ID="$(oci compute instance list --compartment-id "$COMPARTMENT_ID" \ --display-name "$OCI_VM_NAME" \ --query 'data[?"lifecycle-state" != `TERMINATED`] | [0].id' --raw-output 2>/dev/null || true)" if [ -n "$INSTANCE_ID" ] && [ "$INSTANCE_ID" != "null" ]; then echo "[remove] tearing down Compose stack on the VM..." VNIC_ID="$(oci compute instance list-vnics --instance-id "$INSTANCE_ID" --query 'data[0].id' --raw-output 2>/dev/null || true)" PUBLIC_IP="$(oci network vnic get --vnic-id "$VNIC_ID" --query 'data."public-ip"' --raw-output 2>/dev/null || true)" if [ -n "$PUBLIC_IP" ] && [ "$PUBLIC_IP" != "null" ]; then ssh -i "$OCI_SSH_PRIVATE_KEY_PATH" -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 \ ubuntu@"$PUBLIC_IP" \ 'cd /opt/sk1 && sg docker -c "docker compose down -v --rmi local --remove-orphans" || true' \ || echo "[remove] (could not reach VM via SSH — proceeding to terminate)" fi echo "[remove] terminating VM $OCI_VM_NAME ($INSTANCE_ID)..." oci compute instance terminate --instance-id "$INSTANCE_ID" --force \ --preserve-boot-volume false --wait-for-state TERMINATED else echo "[remove] no running VM named $OCI_VM_NAME — skipping" fi # ---- Delete network resources (in reverse dependency order) ---- VCN_ID="$(oci network vcn list --compartment-id "$COMPARTMENT_ID" --display-name "$VCN_NAME" \ --query 'data[0].id' --raw-output 2>/dev/null || true)" if [ -n "$VCN_ID" ] && [ "$VCN_ID" != "null" ]; then SUBNET_ID="$(oci network subnet list --compartment-id "$COMPARTMENT_ID" --vcn-id "$VCN_ID" \ --display-name "$SUBNET_NAME" --query 'data[0].id' --raw-output 2>/dev/null || true)" if [ -n "$SUBNET_ID" ] && [ "$SUBNET_ID" != "null" ]; then echo "[remove] deleting subnet..." oci network subnet delete --subnet-id "$SUBNET_ID" --force --wait-for-state TERMINATED || true fi SL_ID="$(oci network security-list list --compartment-id "$COMPARTMENT_ID" --vcn-id "$VCN_ID" \ --display-name "$SL_NAME" --query 'data[0].id' --raw-output 2>/dev/null || true)" if [ -n "$SL_ID" ] && [ "$SL_ID" != "null" ]; then echo "[remove] deleting security list..." oci network security-list delete --security-list-id "$SL_ID" --force --wait-for-state TERMINATED || true fi RT_ID="$(oci network route-table list --compartment-id "$COMPARTMENT_ID" --vcn-id "$VCN_ID" \ --display-name "$RT_NAME" --query 'data[0].id' --raw-output 2>/dev/null || true)" if [ -n "$RT_ID" ] && [ "$RT_ID" != "null" ]; then echo "[remove] deleting route table..." oci network route-table delete --rt-id "$RT_ID" --force --wait-for-state TERMINATED || true fi IG_ID="$(oci network internet-gateway list --compartment-id "$COMPARTMENT_ID" --vcn-id "$VCN_ID" \ --display-name "$IG_NAME" --query 'data[0].id' --raw-output 2>/dev/null || true)" if [ -n "$IG_ID" ] && [ "$IG_ID" != "null" ]; then echo "[remove] deleting internet gateway..." oci network internet-gateway delete --ig-id "$IG_ID" --force --wait-for-state TERMINATED || true fi echo "[remove] deleting VCN..." oci network vcn delete --vcn-id "$VCN_ID" --force --wait-for-state TERMINATED || true else echo "[remove] no VCN named $VCN_NAME — skipping" fi # ---- Reset DuckDNS A record (best effort) ---- if [ -n "${DUCKDNS_DOMAIN:-}" ] && [ -n "${DUCKDNS_TOKEN:-}" ]; then echo "[remove] clearing DuckDNS A record..." curl -fsS "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN%%.duckdns.org}&token=${DUCKDNS_TOKEN}&clear=true" \ || echo "(DuckDNS clear failed — non-fatal)" fi echo "" echo "================================================================" echo " All sk1 resources removed. Existing VMs and unrelated" echo " resources are untouched." echo "================================================================"