#!/usr/bin/env bash set -euo pipefail log() { printf '[rm] %s\n' "$*" } DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$DIR/dns.sh" STATE="$DIR/state" VM_ROOT="$STATE/vms" usage() { cat <<'EOF' Usage: ./rm.sh ... Removes VM artifacts from state/ and cleans up TAP and mapped devices. EOF } find_vm_json() { local query="$1" local vm_json match_count=0 match="" for vm_json in "$VM_ROOT"/*/vm.json; do [[ -f "$vm_json" ]] || continue local id name id="$(jq -r '.meta.id // empty' "$vm_json")" name="$(jq -r '.meta.name // empty' "$vm_json")" if [[ "$id" == "$query"* || "$name" == "$query"* ]]; then match="$vm_json" match_count=$((match_count + 1)) fi done if (( match_count == 0 )); then log "no VM found for prefix: $query" exit 1 fi if (( match_count > 1 )); then log "multiple VMs found for prefix: $query" exit 1 fi printf '%s' "$match" } QUERIES=("$@") if (( ${#QUERIES[@]} == 1 )) && [[ "${QUERIES[0]}" == "-h" || "${QUERIES[0]}" == "--help" ]]; then usage exit 0 fi if (( ${#QUERIES[@]} == 0 )); then usage exit 1 fi VM_JSONS=() for query in "${QUERIES[@]}"; do VM_JSON="$(find_vm_json "$query")" already_added=0 for existing_vm_json in "${VM_JSONS[@]}"; do if [[ "$existing_vm_json" == "$VM_JSON" ]]; then already_added=1 break fi done if (( already_added == 0 )); then VM_JSONS+=("$VM_JSON") fi done for vm_json in "${VM_JSONS[@]}"; do vm_dir="$(dirname "$vm_json")" vm_id="$(jq -r '.meta.id // empty' "$vm_json")" vm_name="$(jq -r '.meta.name // empty' "$vm_json")" pid="$(jq -r '.meta.pid // empty' "$vm_json")" tap="$(jq -r '.meta.tap // empty' "$vm_json")" api_sock="$(jq -r '.meta.api_sock // empty' "$vm_json")" base_loop="$(jq -r '.meta.base_loop // empty' "$vm_json")" cow_loop="$(jq -r '.meta.cow_loop // empty' "$vm_json")" dm_dev="$(jq -r '.meta.dm_dev // empty' "$vm_json")" dm_name="$(jq -r '.meta.dm_name // empty' "$vm_json")" dns_name="$(jq -r '.meta.dns_name // empty' "$vm_json")" if [[ -z "$dns_name" ]]; then dns_name="$(banger_dns_name "$vm_name")" fi if [[ -n "$pid" ]]; then sudo kill "$pid" 2>/dev/null || true fi if [[ -n "$tap" ]]; then sudo ip link del "$tap" 2>/dev/null || true fi if [[ -n "$api_sock" ]]; then rm -f "$api_sock" fi banger_dns_remove_record_name "$dns_name" if [[ -n "$dm_dev" || -n "$dm_name" ]]; then sudo dmsetup remove "${dm_name:-$dm_dev}" 2>/dev/null || true fi if [[ -n "$cow_loop" ]]; then sudo losetup -d "$cow_loop" 2>/dev/null || true fi if [[ -n "$base_loop" ]]; then sudo losetup -d "$base_loop" 2>/dev/null || true fi if [[ -d "$vm_dir" ]]; then rm -rf "$vm_dir" fi log "removed ${vm_name:-$vm_dir}" done