#!/usr/bin/env bash set -euo pipefail shopt -s nullglob format_count_unit() { local count="$1" local singular="$2" local plural="$3" if (( count == 1 )); then printf '%s %s ago' "$count" "$singular" else printf '%s %s ago' "$count" "$plural" fi } humanize_created_at() { local created_at="$1" local created_epoch elapsed if [[ -z "$created_at" ]]; then printf '%s' "-" return 0 fi created_epoch="$(date -d "$created_at" +%s 2>/dev/null || true)" if [[ -z "$created_epoch" ]]; then printf '%s' "$created_at" return 0 fi elapsed=$((NOW_EPOCH - created_epoch)) if (( elapsed < 0 )); then elapsed=0 fi if (( elapsed < 45 )); then printf '%s' "a few moments ago" elif (( elapsed < 90 )); then printf '%s' "about a minute ago" elif (( elapsed < 3600 )); then format_count_unit "$((elapsed / 60))" "minute" "minutes" elif (( elapsed < 5400 )); then printf '%s' "about an hour ago" elif (( elapsed < 86400 )); then format_count_unit "$((elapsed / 3600))" "hour" "hours" elif (( elapsed < 172800 )); then printf '%s' "1 day ago" elif (( elapsed < 604800 )); then format_count_unit "$((elapsed / 86400))" "day" "days" elif (( elapsed < 1209600 )); then printf '%s' "1 week ago" elif (( elapsed < 2592000 )); then format_count_unit "$((elapsed / 604800))" "week" "weeks" elif (( elapsed < 5184000 )); then printf '%s' "1 month ago" elif (( elapsed < 31536000 )); then format_count_unit "$((elapsed / 2592000))" "month" "months" elif (( elapsed < 63072000 )); then printf '%s' "1 year ago" else format_count_unit "$((elapsed / 31536000))" "year" "years" fi } statuses=() ids=() names=() ips=() created=() max_name=4 max_ip=2 max_created=7 GREEN='\033[32m' YELLOW='\033[33m' RESET='\033[0m' NOW_EPOCH="$(date +%s)" for vm_json in state/vms/*/vm.json; do id="$(jq -r '.meta.id // empty' "$vm_json")" name="$(jq -r '.meta.name // empty' "$vm_json")" created_at="$(jq -r '.meta.created_at // empty' "$vm_json")" created_display="$(humanize_created_at "$created_at")" guest_ip="$(jq -r '.meta.guest_ip // empty' "$vm_json")" pid="$(jq -r '.meta.pid // empty' "$vm_json")" api_sock="$(jq -r '.meta.api_sock // empty' "$vm_json")" status="stopped" if [[ -n "$pid" && -n "$api_sock" ]]; then if ps -p "$pid" -o comm=,args= 2>/dev/null | rg -q "firecracker.*--api-sock $api_sock"; then status="running" fi fi short_id="${id:0:12}" statuses+=("$status") ids+=("$short_id") names+=("$name") ips+=("$guest_ip") created+=("$created_display") if (( ${#name} > max_name )); then max_name=${#name} fi if (( ${#guest_ip} > max_ip )); then max_ip=${#guest_ip} fi if (( ${#created_display} > max_created )); then max_created=${#created_display} fi done for i in "${!ids[@]}"; do color="$YELLOW" if [[ "${statuses[$i]}" == "running" ]]; then color="$GREEN" fi printf '%-10b %-12s %-*s %-*s %-*s\n' \ "${color}[${statuses[$i]}]${RESET}" "${ids[$i]}" "$max_name" "${names[$i]}" "$max_ip" "${ips[$i]}" "$max_created" "${created[$i]}" done