Make spawned VMs easier to use and restore from the host. Add shared DNS and runtime helpers, publish <vm-name>.vm records through mapdns, and teach run/customize/interactive/restore to persist the metadata needed for SSH, DNS cleanup, and clean restores. Seed per-VM /home and /var disks from the rootfs snapshot so package state is present on first boot, add an interactive customization entrypoint plus ssh.sh and human-friendly list output, and let stop/kill/rm operate on multiple VM identifiers. Tear down stale TAP, dm, and loop state when VMs stop so restore can recreate them safely, and validate the updated scripts with bash -n plus targeted dry-run harnesses for teardown and restore paths.
98 lines
2.2 KiB
Bash
98 lines
2.2 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
MAPDNS_BIN="${MAPDNS_BIN:-mapdns}"
|
|
MAPDNS_DATA_FILE="/home/thales/.local/share/mapdns/records.json"
|
|
|
|
banger_mapdns_cmd() {
|
|
local subcommand="$1"
|
|
shift
|
|
|
|
"$MAPDNS_BIN" "$subcommand" --data-file "$MAPDNS_DATA_FILE" "$@"
|
|
}
|
|
|
|
banger_dns_name() {
|
|
local vm_name="$1"
|
|
printf '%s.vm' "$vm_name"
|
|
}
|
|
|
|
banger_dns_write_record() {
|
|
local vm_name="$1"
|
|
local guest_ip="$2"
|
|
local dns_name
|
|
|
|
mkdir -p "$(dirname "$MAPDNS_DATA_FILE")"
|
|
dns_name="$(banger_dns_name "$vm_name")"
|
|
banger_mapdns_cmd set "$dns_name" "$guest_ip" >/dev/null
|
|
}
|
|
|
|
banger_dns_record_exists() {
|
|
local dns_name="$1"
|
|
|
|
[[ -n "$dns_name" ]] || return 1
|
|
banger_mapdns_cmd list | awk '{print $1}' | rg -Fxq "$dns_name"
|
|
}
|
|
|
|
banger_dns_remove_record_name() {
|
|
local dns_name="${1:-}"
|
|
[[ -n "$dns_name" ]] || return 0
|
|
if ! banger_dns_record_exists "$dns_name"; then
|
|
return 0
|
|
fi
|
|
banger_mapdns_cmd rm "$dns_name" >/dev/null
|
|
}
|
|
|
|
banger_vm_process_running() {
|
|
local pid="$1"
|
|
local api_sock="$2"
|
|
|
|
[[ -n "$pid" && -n "$api_sock" ]] || return 1
|
|
ps -p "$pid" -o comm=,args= 2>/dev/null | rg -q "firecracker.*--api-sock $api_sock"
|
|
}
|
|
|
|
banger_wait_for_vm_exit() {
|
|
local pid="$1"
|
|
local api_sock="$2"
|
|
local timeout_secs="${3:-30}"
|
|
local deadline=$((SECONDS + timeout_secs))
|
|
|
|
while banger_vm_process_running "$pid" "$api_sock"; do
|
|
if (( SECONDS >= deadline )); then
|
|
return 1
|
|
fi
|
|
sleep 0.1
|
|
done
|
|
}
|
|
|
|
banger_teardown_vm_runtime() {
|
|
local tap="${1:-}"
|
|
local api_sock="${2:-}"
|
|
local dm_name="${3:-}"
|
|
local dm_dev="${4:-}"
|
|
local cow_loop="${5:-}"
|
|
local base_loop="${6:-}"
|
|
|
|
if [[ -n "$tap" ]]; then
|
|
sudo ip link del "$tap" 2>/dev/null || true
|
|
fi
|
|
if [[ -n "$api_sock" ]]; then
|
|
rm -f "$api_sock"
|
|
fi
|
|
if [[ -n "$dm_name" || -n "$dm_dev" ]]; 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
|
|
}
|
|
|
|
banger_mark_vm_stopped() {
|
|
local vm_json="$1"
|
|
|
|
[[ -f "$vm_json" ]] || return 0
|
|
jq \
|
|
'del(.meta.pid, .meta.base_loop, .meta.cow_loop, .meta.dm_dev)' \
|
|
"$vm_json" > "$vm_json.tmp" && mv "$vm_json.tmp" "$vm_json"
|
|
}
|