This commit is contained in:
Tiara Rodney 2026-03-14 05:38:45 +01:00
commit 883f31932e
No known key found for this signature in database
GPG key ID: 5CD8EC1D46106723
169 changed files with 5676 additions and 0 deletions

48
scripts/vm/create.sh Executable file
View file

@ -0,0 +1,48 @@
#!/bin/sh
# First-time setup: download image, create volumes, provision VMs,
# wait for cloud-init, then snapshot as "initialized".
set -eu
. "$(dirname "$0")/env.sh"
echo "==> Downloading cloud image"
"$QEMU_VM" image download
echo "==> Creating volumes"
"$QEMU_VM" volume create "$PROXY_VM" --size 20G --backing debian-12
"$QEMU_VM" volume create "$IDP_VM" --size 20G --backing debian-12
echo "==> Preparing TAP interfaces"
sudo --preserve-env=QEMU_VM "$(dirname "$0")/setup-taps.sh"
echo "==> Clearing stale SSH host keys"
clear_host_keys
echo "==> Creating instances (in screen sessions)"
screen -dmS "$PROXY_VM" \
"$QEMU_VM" instance create "$PROXY_VM" 0 \
--network "$NETWORK" --ip "$PROXY_IP" --headless
screen -dmS "$IDP_VM" \
"$QEMU_VM" instance create "$IDP_VM" 0 \
--network "$NETWORK" --ip "$IDP_IP" --headless
echo "==> Waiting for cloud-init"
wait_ssh "$PROXY_HOST"
# shellcheck disable=SC2086
ssh $SSH_OPTS "${SSH_USER}@${PROXY_HOST}" 'cloud-init status --wait'
echo " $PROXY_VM ready"
wait_ssh "$IDP_HOST"
# shellcheck disable=SC2086
ssh $SSH_OPTS "${SSH_USER}@${IDP_HOST}" 'cloud-init status --wait'
echo " $IDP_VM ready"
echo "==> Stopping for initial snapshot"
"$QEMU_VM" instance stop "$PROXY_VM"
"$QEMU_VM" instance stop "$IDP_VM"
echo "==> Snapshotting 'initialized'"
"$QEMU_VM" volume snapshot "$PROXY_VM" initialized
"$QEMU_VM" volume snapshot "$IDP_VM" initialized
echo "==> Done. Run: scripts/vm/start.sh"

13
scripts/vm/destroy.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/sh
# Destroy everything: stop VMs, delete volumes.
# Use scripts/vm/create.sh to start over.
set -eu
. "$(dirname "$0")/env.sh"
"$(dirname "$0")/stop.sh"
echo "==> Deleting volumes"
"$QEMU_VM" volume delete "$PROXY_VM" 2>/dev/null || true
"$QEMU_VM" volume delete "$IDP_VM" 2>/dev/null || true
echo "==> Destroyed. Run scripts/vm/create.sh to recreate."

47
scripts/vm/env.sh Executable file
View file

@ -0,0 +1,47 @@
#!/bin/sh
# Shared environment for all VM scripts.
# Source this — don't execute directly.
# Caller must set QEMU_VM, or we fall back to PATH lookup.
QEMU_VM="${QEMU_VM:-qemu-vm}"
BRIDGE=qemu-br0
GATEWAY=10.10.0.1/24
SUBNET=10.10.0.0/24
NETWORK=lab
PROXY_VM=vm-proxy
PROXY_IP=10.10.0.2/24
IDP_VM=vm-idp
IDP_IP=10.10.0.3/24
PROXY_HOST="${PROXY_IP%%/*}"
IDP_HOST="${IDP_IP%%/*}"
SSH_USER=debian
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR"
clear_host_keys() {
ssh-keygen -R "$PROXY_HOST" 2>/dev/null || true
ssh-keygen -R "$IDP_HOST" 2>/dev/null || true
}
learn_host_keys() {
ssh-keyscan -H "$PROXY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
ssh-keyscan -H "$IDP_HOST" >> ~/.ssh/known_hosts 2>/dev/null
}
wait_ssh() {
_host=$1 _i=0
while [ "$_i" -lt 60 ]; do
# shellcheck disable=SC2086
if ssh $SSH_OPTS "${SSH_USER}@${_host}" true 2>/dev/null; then
return 0
fi
_i=$((_i + 1))
sleep 1
done
echo "SSH timeout: ${_host}" >&2
return 1
}

20
scripts/vm/restore.sh Executable file
View file

@ -0,0 +1,20 @@
#!/bin/sh
# Restore both VM volumes to a snapshot and start them.
#
# Usage: scripts/vm/restore.sh <label>
# e.g. scripts/vm/restore.sh initialized
set -eu
. "$(dirname "$0")/env.sh"
label="${1:?Usage: restore.sh <label>}"
"$(dirname "$0")/stop.sh"
echo "==> Restoring '$label'"
"$QEMU_VM" volume restore "$PROXY_VM" "$label"
"$QEMU_VM" volume restore "$IDP_VM" "$label"
echo "==> Clearing stale SSH host keys"
clear_host_keys
exec "$(dirname "$0")/start.sh"

12
scripts/vm/setup-network.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
# Create and activate the bridge network. Requires root.
set -eu
. "$(dirname "$0")/env.sh"
"$QEMU_VM" network create "$NETWORK" \
--type bridge \
--bridge "$BRIDGE" \
--gateway "$GATEWAY" \
--subnet "$SUBNET" 2>/dev/null || true
exec "$QEMU_VM" network setup "$NETWORK"

7
scripts/vm/setup-taps.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
# Pre-create TAP interfaces for both VMs. Requires root.
set -eu
. "$(dirname "$0")/env.sh"
"$QEMU_VM" network attach "$NETWORK" "$PROXY_VM"
"$QEMU_VM" network attach "$NETWORK" "$IDP_VM"

16
scripts/vm/snapshot.sh Executable file
View file

@ -0,0 +1,16 @@
#!/bin/sh
# Snapshot both VM volumes. Stops VMs first.
#
# Usage: scripts/vm/snapshot.sh <label>
set -eu
. "$(dirname "$0")/env.sh"
label="${1:?Usage: snapshot.sh <label>}"
"$(dirname "$0")/stop.sh"
echo "==> Snapshotting '$label'"
"$QEMU_VM" volume snapshot "$PROXY_VM" "$label"
"$QEMU_VM" volume snapshot "$IDP_VM" "$label"
echo "==> Done. Restart with: scripts/vm/start.sh"

26
scripts/vm/start.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/sh
# Start VMs in detached GNU screen sessions.
# Attach with: screen -r vm-proxy / screen -r vm-idp
set -eu
. "$(dirname "$0")/env.sh"
echo "==> Ensuring bridge network"
sudo --preserve-env=QEMU_VM "$(dirname "$0")/setup-network.sh"
echo "==> Preparing TAP interfaces"
sudo --preserve-env=QEMU_VM "$(dirname "$0")/setup-taps.sh"
echo "==> Starting $PROXY_VM"
screen -dmS "$PROXY_VM" "$QEMU_VM" instance start "$PROXY_VM"
echo "==> Starting $IDP_VM"
screen -dmS "$IDP_VM" "$QEMU_VM" instance start "$IDP_VM"
echo "==> Waiting for SSH"
wait_ssh "$PROXY_HOST" && echo " $PROXY_VM ready"
wait_ssh "$IDP_HOST" && echo " $IDP_VM ready"
echo "==> Learning host keys"
learn_host_keys
echo "==> Attach with: screen -r vm-proxy / screen -r vm-idp"

13
scripts/vm/status.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/sh
# Show VM and volume status, plus screen sessions.
set -eu
. "$(dirname "$0")/env.sh"
echo "==> Instances"
"$QEMU_VM" instance list
echo
echo "==> Volumes"
"$QEMU_VM" volume list
echo
echo "==> Screen sessions"
screen -ls 2>/dev/null | grep -E 'vm-(proxy|idp)' || echo " (none)"

7
scripts/vm/stop.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
# Stop both VMs gracefully.
set -eu
. "$(dirname "$0")/env.sh"
"$QEMU_VM" instance stop "$PROXY_VM" || true
"$QEMU_VM" instance stop "$IDP_VM" || true