From 50c851cf0772b42c5a0a90111cfdd25e22875497 Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Wed, 21 Jan 2026 18:45:45 -0300 Subject: [PATCH] init --- run.sh | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 run.sh diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..bd67534 --- /dev/null +++ b/run.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +set -euo pipefail + +log() { + printf '[spawn] %s\n' "$*" +} + +log "starting" + +DIR="$(pwd)" +STATE="$DIR/state" +mkdir -p "$STATE" + +FC_BIN="$DIR/firecracker" +KERNEL="$DIR/vmlinux" +ROOTFS="$DIR/rootfs.ext4" +SSH_KEY="$DIR/id_ed25519" + +BR_DEV="br-fc" +BR_IP="172.16.0.1" +CIDR="24" + +VM_ID="$(date +%s)-$$" +VM_DIR="$STATE/vm-$VM_ID" +mkdir -p "$VM_DIR" + +API_SOCK="$VM_DIR/firecracker.sock" +LOG_FILE="$VM_DIR/firecracker.log" +TAP_DEV="tap-fc-$VM_ID" + +# Allocate guest IP +NEXT_IP_FILE="$STATE/next_ip" +NEXT_IP="$(cat "$NEXT_IP_FILE" 2>/dev/null || echo 2)" +GUEST_IP="172.16.0.$NEXT_IP" +echo "$((NEXT_IP + 1))" > "$NEXT_IP_FILE" + +log "vm id: $VM_ID" +log "allocated guest ip: $GUEST_IP" + +sudo -v + +# Host bridge +if ! ip link show "$BR_DEV" >/dev/null 2>&1; then + log "creating host bridge $BR_DEV ($BR_IP/$CIDR)" + sudo ip link add name "$BR_DEV" type bridge + sudo ip addr add "${BR_IP}/${CIDR}" dev "$BR_DEV" + sudo ip link set "$BR_DEV" up +else + log "host bridge $BR_DEV already exists" +fi + +# Per-VM TAP +log "creating tap device $TAP_DEV" +sudo ip tuntap add dev "$TAP_DEV" mode tap +sudo ip link set "$TAP_DEV" master "$BR_DEV" +sudo ip link set "$TAP_DEV" up + +# Start Firecracker +log "starting firecracker process" +rm -f "$API_SOCK" +nohup "$FC_BIN" --api-sock "$API_SOCK" >"$LOG_FILE" 2>&1 & +FC_PID="$!" +echo "$FC_PID" > "$VM_DIR/pid" +log "firecracker pid: $FC_PID" + +# Wait for API socket +log "waiting for firecracker api socket" +for _ in $(seq 1 200); do + [[ -S "$API_SOCK" ]] && break + sleep 0.02 +done +[[ -S "$API_SOCK" ]] || { log "firecracker api socket not ready"; exit 1; } +log "api socket ready" + +# Machine config +log "configuring machine" +curl --unix-socket "$API_SOCK" -X PUT http://localhost/machine-config \ + -H "Content-Type: application/json" \ + -d '{ + "vcpu_count": 2, + "mem_size_mib": 1024, + "smt": false + }' >/dev/null + +# Boot source +log "configuring boot source" +KCMD="console=ttyS0 reboot=k panic=1 pci=off root=/dev/vda rw ip=${GUEST_IP}::${BR_IP}:255.255.255.0::eth0:off" + +curl --unix-socket "$API_SOCK" -X PUT http://localhost/boot-source \ + -H "Content-Type: application/json" \ + -d "{ + \"kernel_image_path\": \"$KERNEL\", + \"boot_args\": \"$KCMD\" + }" >/dev/null + +# Root filesystem +log "attaching root filesystem" +curl --unix-socket "$API_SOCK" -X PUT http://localhost/drives/rootfs \ + -H "Content-Type: application/json" \ + -d "{ + \"drive_id\": \"rootfs\", + \"path_on_host\": \"$ROOTFS\", + \"is_root_device\": true, + \"is_read_only\": false + }" >/dev/null + +# Network interface +log "configuring network interface" +curl --unix-socket "$API_SOCK" -X PUT http://localhost/network-interfaces/eth0 \ + -H "Content-Type: application/json" \ + -d "{ + \"iface_id\": \"eth0\", + \"host_dev_name\": \"$TAP_DEV\" + }" >/dev/null + +# Start VM +log "starting virtual machine" +curl --unix-socket "$API_SOCK" -X PUT http://localhost/actions \ + -H "Content-Type: application/json" \ + -d '{ "action_type": "InstanceStart" }' >/dev/null + +cat > "$VM_DIR/info" <