#!/usr/bin/env bash set -euo pipefail log() { printf '[kill] %s\n' "$*" } usage() { cat <<'EOF' Usage: ./kill.sh [--signal SIGTERM|SIGKILL|...] Sends a signal to the Firecracker process. EOF } find_vm_json() { local query="$1" local vm_json match_count=0 match="" for vm_json in state/vms/*/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" } SIGNAL="TERM" while [[ $# -gt 0 ]]; do case "$1" in --signal) SIGNAL="${2:-}" shift 2 ;; -h|--help) usage exit 0 ;; *) if [[ -z "${QUERY:-}" ]]; then QUERY="$1" shift continue fi log "unknown option: $1" usage exit 1 ;; esac done if [[ -z "$QUERY" || "$QUERY" == "-h" || "$QUERY" == "--help" ]]; then usage exit 1 fi VM_JSON="$(find_vm_json "$QUERY")" PID="$(jq -r '.meta.pid // empty' "$VM_JSON")" API_SOCK="$(jq -r '.meta.api_sock // empty' "$VM_JSON")" if [[ -z "$PID" ]]; then log "pid not found in $VM_JSON" exit 1 fi if [[ -z "$API_SOCK" ]]; then log "api_sock not found in $VM_JSON" exit 1 fi if ! ps -p "$PID" -o comm=,args= 2>/dev/null | rg -q "firecracker.*--api-sock $API_SOCK"; then log "pid $PID does not match a running VM" exit 1 fi log "sending SIG$SIGNAL to pid $PID" sudo kill "-$SIGNAL" "$PID" log "signal sent"