#!/usr/bin/env bash set -euo pipefail log() { printf '[bench-create] %s\n' "$*" >&2 } usage() { cat <<'EOF' Usage: ./scripts/bench-create.sh [--runs N] [--image NAME] [--keep] Measures: - create_ms: time for `banger vm create` - ssh_ready_ms: time until `banger vm ssh -- true` succeeds EOF } RUNS=5 IMAGE_NAME="" KEEP=0 while [[ $# -gt 0 ]]; do case "$1" in --runs) RUNS="${2:-}" shift 2 ;; --image) IMAGE_NAME="${2:-}" shift 2 ;; --keep) KEEP=1 shift ;; -h|--help) usage exit 0 ;; *) log "unknown option: $1" usage exit 1 ;; esac done if ! [[ "$RUNS" =~ ^[0-9]+$ ]] || [[ "$RUNS" -le 0 ]]; then log "--runs must be a positive integer" exit 1 fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" BANGER_BIN="${BANGER_BIN:-$REPO_ROOT/banger}" if [[ ! -x "$BANGER_BIN" ]]; then log "banger binary not found: $BANGER_BIN" log "run 'make build' or set BANGER_BIN" exit 1 fi timestamp_ms() { date +%s%3N } json_escape() { python3 - <<'PY' "$1" import json, sys print(json.dumps(sys.argv[1])) PY } printf '[\n' for run in $(seq 1 "$RUNS"); do vm_name="bench-$(date +%s)-$run" create_args=("$BANGER_BIN" vm create --name "$vm_name") if [[ -n "$IMAGE_NAME" ]]; then create_args+=(--image "$IMAGE_NAME") fi create_start="$(timestamp_ms)" if ! "${create_args[@]}" >/dev/null; then log "create failed for $vm_name" exit 1 fi create_end="$(timestamp_ms)" ssh_start="$create_end" ssh_ready=0 deadline=$((ssh_start + 60000)) while (( $(timestamp_ms) < deadline )); do if "$BANGER_BIN" vm ssh "$vm_name" -- true >/dev/null 2>&1; then ssh_ready="$(timestamp_ms)" break fi sleep 0.5 done if [[ "$ssh_ready" -eq 0 ]]; then log "ssh did not become ready for $vm_name" exit 1 fi if [[ "$KEEP" -ne 1 ]]; then "$BANGER_BIN" vm delete "$vm_name" >/dev/null || true fi printf ' {"run": %d, "vm_name": %s, "create_ms": %d, "ssh_ready_ms": %d}%s\n' \ "$run" \ "$(json_escape "$vm_name")" \ "$((create_end - create_start))" \ "$((ssh_ready - create_start))" \ "$( [[ "$run" -lt "$RUNS" ]] && printf ',' )" done printf ']\n'