feat: full deployment scripts — backend + LXC creation, frontend installer
backend/install.sh (run on srv2): - Creates /mnt/converter directory tree, clones/updates git repo - Installs 10 system packages (qemu-img, guestfish, archive tools) - Installs Python deps + vm-bench-backend systemd service - Interactive LXC creation: prompts for container ID, IP, gateway, bridge, MAC (all with defaults) - Creates vm-bench LXC: 3 cores, 6GB RAM, 24GB rootfs, nesting, AppArmor unconfined, cgroup access, bind mount /mnt/converter frontend/install.sh (run inside LXC): - Installs python3, pip3, wget, curl - Installs Python deps (fastapi, uvicorn, jinja2, etc.) - Verifies backend connectivity, installs vm-bench systemd service frontend/vm-bench.service: systemd unit bundled in repo README: replaced Prerequisites/Installation with full Deployment section covering both steps, container config table, and re-deploy
This commit is contained in:
parent
c887ccd5a3
commit
4b50b185fa
4 changed files with 548 additions and 64 deletions
134
README.md
134
README.md
|
|
@ -28,6 +28,8 @@ Browser vm-bench LXC Proxmox Host (srv2)
|
|||
├── frontend/ # Web UI (runs on vm-bench LXC)
|
||||
│ ├── app.py # FastAPI app, routes, session handling
|
||||
│ ├── api_client.py # Typed REST client → backend
|
||||
│ ├── install.sh # Frontend installer (system deps + service)
|
||||
│ ├── vm-bench.service # Systemd unit for the frontend
|
||||
│ ├── requirements.txt
|
||||
│ ├── templates/ # Jinja2 HTML templates
|
||||
│ │ ├── base.html
|
||||
|
|
@ -36,14 +38,14 @@ Browser vm-bench LXC Proxmox Host (srv2)
|
|||
│ │ └── polling.html # Progress bar + job status
|
||||
│ └── static/
|
||||
│ └── proxmox.css
|
||||
├── backend/ # REST API (deploy to Proxmox host srv2)
|
||||
├── backend/ # REST API (deploys to Proxmox host srv2)
|
||||
│ ├── app.py # FastAPI app, routes
|
||||
│ ├── models.py # Pydantic request/response models
|
||||
│ ├── converter.py # Archive extraction, disk probing, OS/EFI detection
|
||||
│ ├── provisioner.py # VM provisioning (qm create/importdisk)
|
||||
│ ├── requirements.txt
|
||||
│ ├── install.sh # Systemd installation script
|
||||
│ └── vm-bench-backend.service
|
||||
│ ├── install.sh # Full deployment script (backend + LXC creation)
|
||||
│ ├── vm-bench-backend.service
|
||||
│ └── requirements.txt
|
||||
├── open-api.yaml # API spec (single source of truth)
|
||||
├── in/ # Shared staging directory (gitignored)
|
||||
└── out/ # Shared output directory (gitignored)
|
||||
|
|
@ -60,53 +62,121 @@ Browser vm-bench LXC Proxmox Host (srv2)
|
|||
|
||||
## Prerequisites
|
||||
|
||||
### Backend (Proxmox host `srv2`)
|
||||
### Proxmox host (`srv2`)
|
||||
|
||||
- Python 3.13+
|
||||
- `qemu-img` (from `qemu-utils`)
|
||||
- `guestfish` (from `libguestfs-tools`)
|
||||
- `7z`, `unzip`, `tar` (for archive extraction)
|
||||
- `systemd` (for service management)
|
||||
The host must be a Proxmox VE node with:
|
||||
- `pct` — LXC container management (built-in)
|
||||
- `git` — to clone the repository (install script handles this)
|
||||
- Internet access to download container templates
|
||||
|
||||
### Frontend (`vm-bench` LXC)
|
||||
### LXC container (`vm-bench`)
|
||||
|
||||
- Python 3.13+
|
||||
- `wget` (for URL downloads)
|
||||
- `systemd` (for service management)
|
||||
- Network access to backend at `10.2.0.2:9000`
|
||||
Created automatically by the install script. Requires:
|
||||
- 3 CPU cores, 6 GB RAM, 24 GB disk, 2 GB swap
|
||||
- Debian 12 template (downloaded by script)
|
||||
- Network bridge `vmbr0`
|
||||
|
||||
## Installation
|
||||
## Deployment
|
||||
|
||||
### 1. Backend (on Proxmox host `srv2`)
|
||||
All deployment is driven by a single script on the Proxmox host. It creates the
|
||||
directory tree, clones the repo, installs the backend, and provisions the
|
||||
`vm-bench` LXC container ready for the frontend.
|
||||
|
||||
### Step 1: Clone & deploy (on `srv2`)
|
||||
|
||||
```bash
|
||||
# The backend code is shared via /mnt/converter/backend/
|
||||
cd /mnt/converter/backend
|
||||
bash install.sh
|
||||
# Create the shared directory and clone the repo
|
||||
mkdir -p /mnt/converter
|
||||
cd /mnt/converter
|
||||
git clone https://git.lohmar.co.uk/cclohmar/vm-bench.git .
|
||||
|
||||
# Run the installer — handles everything interactively
|
||||
bash backend/install.sh
|
||||
```
|
||||
|
||||
This installs Python dependencies, copies the systemd service, and starts
|
||||
`vm-bench-backend` on port 9000. Verify:
|
||||
The script will:
|
||||
1. Create the `/mnt/converter/` directory tree
|
||||
2. Clone or update the git repository
|
||||
3. Install system packages (qemu-img, guestfish, archive tools, etc.)
|
||||
4. Install Python dependencies and start the backend systemd service
|
||||
5. **Prompt for container ID + network settings**
|
||||
6. **Create and configure the `vm-bench` LXC container** with:
|
||||
- 3 cores, 6 GB RAM, 24 GB rootfs, 2 GB swap
|
||||
- Bind mount: `/mnt/converter` shared with host
|
||||
- Unprivileged mode off, nesting enabled
|
||||
- AppArmor unconfined, cgroup device access allowed
|
||||
7. Optionally start the container
|
||||
|
||||
Example prompts:
|
||||
```
|
||||
Container ID (e.g. 20020): 20020
|
||||
IP address/CIDR [10.2.0.20/16]:
|
||||
Gateway [10.2.0.2]:
|
||||
Bridge [vmbr0]:
|
||||
MAC address [BC:24:11:80:5A:B1]:
|
||||
```
|
||||
|
||||
Verify the backend is running:
|
||||
```bash
|
||||
curl http://127.0.0.1:9000/api/v1/health
|
||||
# → {"status":"ok"}
|
||||
```
|
||||
|
||||
### 2. Frontend (on `vm-bench` LXC)
|
||||
### Step 2: Install frontend (inside the LXC)
|
||||
|
||||
After the container is created and started, enter it:
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
cd /mnt/converter/frontend
|
||||
pip3 install --break-system-packages -r requirements.txt
|
||||
|
||||
# Copy service file and start
|
||||
cp /etc/systemd/system/vm-bench.service /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now vm-bench
|
||||
pct enter 20020 # use your container ID
|
||||
```
|
||||
|
||||
The frontend serves on port 5000. Open `http://<vm-bench-ip>:5000` in a browser.
|
||||
Inside the container, run the frontend installer:
|
||||
|
||||
```bash
|
||||
bash /mnt/converter/frontend/install.sh
|
||||
```
|
||||
|
||||
This installs Python, pip, `wget`, `curl`, Python dependencies, and starts the
|
||||
`vm-bench` systemd service on port 5000.
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
curl http://127.0.0.1:5000
|
||||
# → HTML response (the web UI)
|
||||
```
|
||||
|
||||
Open `http://<container-ip>:5000` in a browser.
|
||||
|
||||
### Container LXC Config (created by install script)
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| Arch | `amd64` |
|
||||
| Cores | `3` |
|
||||
| Memory | `6144` MB |
|
||||
| Swap | `2048` MB |
|
||||
| Rootfs | `local-lvm:24G` |
|
||||
| OS type | `debian` |
|
||||
| Unprivileged | `0` (disabled) |
|
||||
| Features | `nesting=1` |
|
||||
| Network | `vmbr0`, firewall enabled, veth |
|
||||
| Bind mount | `mp0: /mnt/converter,mp=/mnt/converter` |
|
||||
| AppArmor | `unconfined` |
|
||||
| Cgroup | `devices.allow: a`, `mount.auto: proc:rw sys:rw cgroup:rw` |
|
||||
|
||||
### Re-deploying / updating
|
||||
|
||||
The install scripts are idempotent — safe to re-run:
|
||||
|
||||
```bash
|
||||
# On srv2: update backend
|
||||
cd /mnt/converter && git pull
|
||||
bash backend/install.sh # skips LXC creation if container exists
|
||||
|
||||
# Inside LXC: update frontend
|
||||
cd /mnt/converter && git pull
|
||||
bash frontend/install.sh
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
|
|
|
|||
|
|
@ -1,56 +1,323 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# VM Bench Backend — Installer for Proxmox host (srv2)
|
||||
# Run: bash /mnt/converter/backend/install.sh
|
||||
# ╔════════════════════════════════════════════════════════════════════╗
|
||||
# ║ VM Bench — Full Deployment Script (run on Proxmox host srv2) ║
|
||||
# ║ ║
|
||||
# ║ Usage: bash /mnt/converter/backend/install.sh ║
|
||||
# ║ ║
|
||||
# ║ Does everything: ║
|
||||
# ║ 1. Creates /mnt/converter/ directory tree ║
|
||||
# ║ 2. Clones (or pulls) the git repository ║
|
||||
# ║ 3. Installs system packages + Python deps + systemd service ║
|
||||
# ║ 4. Prompts for container ID + network config ║
|
||||
# ║ 5. Creates the vm-bench LXC container with bind mount ║
|
||||
# ╚════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Colours & paths
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||
|
||||
REPO_URL="https://git.lohmar.co.uk/cclohmar/vm-bench.git"
|
||||
CONVERTER_ROOT="/mnt/converter"
|
||||
SCRIPT_DIR="${CONVERTER_ROOT}/backend"
|
||||
SERVICE_NAME="vm-bench-backend"
|
||||
SERVICE_FILE="${SCRIPT_DIR}/${SERVICE_NAME}.service"
|
||||
SYSTEMD_DIR="/etc/systemd/system"
|
||||
|
||||
echo "=== VM Bench Backend Installer ==="
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Banner
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "╔═════════════════════════════════════════════════════════╗"
|
||||
echo "║ VM Bench — Full Deployment Installer ║"
|
||||
echo "║ Target: Proxmox host (srv2) ║"
|
||||
echo "╚═════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# 1. Install Python dependencies
|
||||
echo "[1/4] Installing Python dependencies..."
|
||||
cd "$SCRIPT_DIR"
|
||||
python3 -m pip install --break-system-packages -r requirements.txt -q
|
||||
echo " Dependencies installed."
|
||||
|
||||
# 2. Copy systemd service file
|
||||
echo "[2/4] Installing systemd service..."
|
||||
if [ ! -f "$SERVICE_FILE" ]; then
|
||||
echo " ERROR: ${SERVICE_FILE} not found."
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Pre-flight: must run on a Proxmox host
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo "[preflight] Checking environment..."
|
||||
if ! command -v pct &>/dev/null; then
|
||||
echo " ${RED}✗${NC} 'pct' not found — this script must run on a Proxmox host."
|
||||
exit 1
|
||||
fi
|
||||
cp "$SERVICE_FILE" "$SYSTEMD_DIR/${SERVICE_NAME}.service"
|
||||
echo " Service file copied to ${SYSTEMD_DIR}/"
|
||||
if ! command -v git &>/dev/null; then
|
||||
echo " Installing git..."
|
||||
apt-get update -qq && apt-get install -y -qq git
|
||||
fi
|
||||
echo " ${GREEN}✓${NC} Running on Proxmox host."
|
||||
|
||||
# 3. Reload systemd and enable
|
||||
echo "[3/4] Enabling service..."
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 1: Create directory tree
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[1/6] Creating directory structure..."
|
||||
|
||||
for d in \
|
||||
"$CONVERTER_ROOT" \
|
||||
"$CONVERTER_ROOT/in" \
|
||||
"$CONVERTER_ROOT/out" \
|
||||
"$CONVERTER_ROOT/backend" \
|
||||
"$CONVERTER_ROOT/frontend" \
|
||||
"$CONVERTER_ROOT/frontend/templates" \
|
||||
"$CONVERTER_ROOT/frontend/static"; do
|
||||
if [ ! -d "$d" ]; then
|
||||
mkdir -p "$d"
|
||||
echo " Created: $d"
|
||||
fi
|
||||
done
|
||||
echo " ${GREEN}✓${NC} Directories ready."
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 2: Clone or update the git repository
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[2/6] Cloning / updating repository..."
|
||||
|
||||
if [ -d "$CONVERTER_ROOT/.git" ]; then
|
||||
echo " Existing repo found, pulling latest..."
|
||||
git -C "$CONVERTER_ROOT" pull --ff-only
|
||||
echo " ${GREEN}✓${NC} Repository updated."
|
||||
else
|
||||
# Clone into a temp location, then move if /mnt/converter is not empty
|
||||
if [ -z "$(ls -A "$CONVERTER_ROOT" 2>/dev/null)" ]; then
|
||||
git clone "$REPO_URL" "$CONVERTER_ROOT"
|
||||
else
|
||||
echo " ${YELLOW}!${NC} ${CONVERTER_ROOT} is not empty — cloning into temp and copying..."
|
||||
TMP_CLONE=$(mktemp -d)
|
||||
git clone "$REPO_URL" "$TMP_CLONE"
|
||||
cp -a "$TMP_CLONE"/. "$CONVERTER_ROOT"/
|
||||
rm -rf "$TMP_CLONE"
|
||||
fi
|
||||
echo " ${GREEN}✓${NC} Repository cloned."
|
||||
fi
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 3: System packages
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[3/6] Checking system packages..."
|
||||
|
||||
PACKAGES=()
|
||||
REQUIRED=(
|
||||
python3 "python3"
|
||||
python3-pip "pip3"
|
||||
qemu-utils "qemu-img"
|
||||
libguestfs-tools "guestfish"
|
||||
p7zip-full "7z"
|
||||
unzip "unzip"
|
||||
tar "tar"
|
||||
gzip "gunzip"
|
||||
bzip2 "bunzip2"
|
||||
xz-utils "xz"
|
||||
)
|
||||
|
||||
for ((i=0; i<${#REQUIRED[@]}; i+=2)); do
|
||||
pkg="${REQUIRED[$i]}"
|
||||
bin="${REQUIRED[$i+1]}"
|
||||
if command -v "$bin" &>/dev/null; then
|
||||
echo " ${GREEN}✓${NC} $bin"
|
||||
else
|
||||
echo " ${YELLOW}○${NC} $bin (will install ${pkg})"
|
||||
PACKAGES+=("$pkg")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#PACKAGES[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
echo " Installing: ${PACKAGES[*]}"
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq "${PACKAGES[@]}"
|
||||
echo " ${GREEN}✓${NC} System packages installed."
|
||||
else
|
||||
echo " ${GREEN}✓${NC} All system packages present."
|
||||
fi
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 4: Python dependencies + systemd service
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[4/6] Installing Python dependencies..."
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
python3 -m pip install --break-system-packages -r requirements.txt -q
|
||||
echo " ${GREEN}✓${NC} Python dependencies installed."
|
||||
|
||||
echo ""
|
||||
echo "[5/6] Installing systemd service..."
|
||||
|
||||
if [ ! -f "$SERVICE_FILE" ]; then
|
||||
echo " ${RED}✗${NC} Service file not found: $SERVICE_FILE"
|
||||
echo " Make sure the repository was cloned correctly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "$SERVICE_FILE" "$SYSTEMD_DIR/${SERVICE_NAME}.service"
|
||||
systemctl daemon-reload
|
||||
systemctl enable "$SERVICE_NAME"
|
||||
echo " Service enabled (auto-start on boot)."
|
||||
|
||||
# 4. Start the service
|
||||
echo "[4/4] Starting service..."
|
||||
systemctl restart "$SERVICE_NAME"
|
||||
sleep 2
|
||||
|
||||
# Verify
|
||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
echo ""
|
||||
echo " Backend is RUNNING on port 9000"
|
||||
echo ""
|
||||
echo " Check: curl http://127.0.0.1:9000/health"
|
||||
echo " Logs: journalctl -u ${SERVICE_NAME} -f"
|
||||
echo " ${GREEN}✓${NC} Backend is RUNNING on port 9000"
|
||||
echo " Verify: curl http://127.0.0.1:9000/api/v1/health"
|
||||
else
|
||||
echo ""
|
||||
echo " WARNING: Service did not start. Check logs:"
|
||||
echo " journalctl -u ${SERVICE_NAME} -n 30"
|
||||
echo " ${RED}✗${NC} Backend failed to start. Check logs:"
|
||||
echo " journalctl -u ${SERVICE_NAME} -n 30"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 6: Create the vm-bench LXC container
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "╔═════════════════════════════════════════════════════════╗"
|
||||
echo "║ LXC Container Setup (vm-bench frontend) ║"
|
||||
echo "╚═════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# ── Prompt for container ID ──────────────────────────────────────
|
||||
read -p " Container ID (e.g. 20020): " CTID
|
||||
if [ -z "$CTID" ]; then
|
||||
echo " ${RED}✗${NC} Container ID is required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if ID already exists
|
||||
if pct status "$CTID" &>/dev/null; then
|
||||
echo " ${YELLOW}!${NC} Container $CTID already exists."
|
||||
read -p " Overwrite? [y/N]: " OVERWRITE
|
||||
if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then
|
||||
echo " Aborted."
|
||||
exit 0
|
||||
fi
|
||||
echo " Destroying existing container $CTID..."
|
||||
pct stop "$CTID" --skiplock 2>/dev/null || true
|
||||
pct destroy "$CTID" --purge 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ── Network settings ─────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " ${CYAN}Network configuration:${NC}"
|
||||
read -p " IP address/CIDR [10.2.0.20/16]: " CT_IP
|
||||
read -p " Gateway [10.2.0.2]: " CT_GW
|
||||
read -p " Bridge [vmbr0]: " CT_BRIDGE
|
||||
read -p " MAC address [BC:24:11:80:5A:B1]: " CT_MAC
|
||||
|
||||
CT_IP="${CT_IP:-10.2.0.20/16}"
|
||||
CT_GW="${CT_GW:-10.2.0.2}"
|
||||
CT_BRIDGE="${CT_BRIDGE:-vmbr0}"
|
||||
CT_MAC="${CT_MAC:-BC:24:11:80:5A:B1}"
|
||||
|
||||
NET_CFG="name=eth0,bridge=${CT_BRIDGE},firewall=1,gw=${CT_GW},hwaddr=${CT_MAC},ip=${CT_IP},type=veth"
|
||||
ROOTFS="local-lvm:vm-${CTID}-disk-0,size=24G"
|
||||
|
||||
# ── Template selection ────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " ${CYAN}Available Debian templates:${NC}"
|
||||
pveam available 2>/dev/null | grep debian-12 || echo " (none found locally, will attempt to download)"
|
||||
|
||||
TEMPLATE=$(pveam available 2>/dev/null | grep -m1 "debian-12.*amd64" | awk '{print $2}')
|
||||
if [ -z "$TEMPLATE" ]; then
|
||||
# Try to find any available Debian template
|
||||
TEMPLATE=$(pveam available 2>/dev/null | grep -m1 "debian.*amd64" | awk '{print $2}')
|
||||
fi
|
||||
if [ -z "$TEMPLATE" ]; then
|
||||
echo " ${YELLOW}!${NC} No Debian template found. Downloading debian-12-standard..."
|
||||
pveam update 2>/dev/null || true
|
||||
pveam download local debian-12-standard_12.7-1_amd64.tar.zst 2>/dev/null || true
|
||||
TEMPLATE="local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst"
|
||||
else
|
||||
# Check if template is downloaded locally
|
||||
TEMPLATE_NAME=$(basename "$TEMPLATE")
|
||||
if [ ! -f "/var/lib/vz/template/cache/${TEMPLATE_NAME}" ]; then
|
||||
echo " Downloading template: ${TEMPLATE_NAME}..."
|
||||
pveam download local "$TEMPLATE_NAME" 2>/dev/null || {
|
||||
echo " ${YELLOW}!${NC} Auto-download failed. Trying to continue anyway..."
|
||||
}
|
||||
fi
|
||||
TEMPLATE="local:vztmpl/${TEMPLATE_NAME}"
|
||||
fi
|
||||
|
||||
echo " Using template: ${TEMPLATE}"
|
||||
|
||||
# ── Create container ──────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " Creating container ${CTID}..."
|
||||
|
||||
pct create "$CTID" "$TEMPLATE" \
|
||||
--arch amd64 \
|
||||
--cores 3 \
|
||||
--hostname vm-bench \
|
||||
--memory 6144 \
|
||||
--net0 "$NET_CFG" \
|
||||
--ostype debian \
|
||||
--rootfs "$ROOTFS" \
|
||||
--swap 2048 \
|
||||
--unprivileged 0 \
|
||||
--features nesting=1 \
|
||||
--mp0 /mnt/converter,mp=/mnt/converter \
|
||||
--onboot 1 \
|
||||
--start 0
|
||||
|
||||
echo " ${GREEN}✓${NC} Container created."
|
||||
|
||||
# ── Write LXC config overrides ────────────────────────────────────
|
||||
CONF_FILE="/etc/pve/lxc/${CTID}.conf"
|
||||
echo ""
|
||||
echo " Writing LXC config overrides..."
|
||||
|
||||
# Add lines only if not already present
|
||||
add_conf_line() {
|
||||
local key="$1"
|
||||
local val="$2"
|
||||
if ! grep -q "^${key}:" "$CONF_FILE" 2>/dev/null; then
|
||||
echo "${key}: ${val}" >> "$CONF_FILE"
|
||||
echo " + ${key}: ${val}"
|
||||
fi
|
||||
}
|
||||
|
||||
add_conf_line "lxc.cgroup2.devices.allow" "a"
|
||||
add_conf_line "lxc.mount.auto" "proc:rw sys:rw cgroup:rw"
|
||||
add_conf_line "lxc.apparmor.profile" "unconfined"
|
||||
|
||||
echo " ${GREEN}✓${NC} LXC config written."
|
||||
|
||||
# ── Start the container ───────────────────────────────────────────
|
||||
echo ""
|
||||
read -p " Start container now? [Y/n]: " START
|
||||
if [ "$START" != "n" ] && [ "$START" != "N" ]; then
|
||||
pct start "$CTID"
|
||||
sleep 3
|
||||
if pct status "$CTID" | grep -q running; then
|
||||
echo " ${GREEN}✓${NC} Container ${CTID} is running."
|
||||
echo ""
|
||||
echo " ${CYAN}Next steps:${NC}"
|
||||
echo " 1. Enter the container: pct enter ${CTID}"
|
||||
echo " 2. Run the frontend installer:"
|
||||
echo " bash /mnt/converter/frontend/install.sh"
|
||||
echo ""
|
||||
echo " 3. Open the web UI: http://${CT_IP%/*}:5000"
|
||||
echo ""
|
||||
else
|
||||
echo " ${YELLOW}!${NC} Container may not have started. Check: pct status ${CTID}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Done
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "╔═════════════════════════════════════════════════════════╗"
|
||||
echo "║ ${GREEN}Deployment complete.${NC} ║"
|
||||
echo "║ ║"
|
||||
echo "║ Backend: http://$(hostname -I | awk '{print $1}'):9000 ║"
|
||||
echo "║ Frontend: http://${CT_IP%/*}:5000 ║"
|
||||
echo "║ ║"
|
||||
echo "║ Backend logs: journalctl -u ${SERVICE_NAME} -f ║"
|
||||
echo "║ Container: pct enter ${CTID} ║"
|
||||
echo "╚═════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "=== Done ==="
|
||||
|
|
|
|||
131
frontend/install.sh
Executable file
131
frontend/install.sh
Executable file
|
|
@ -0,0 +1,131 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# VM Bench Frontend — Installer for vm-bench LXC
|
||||
#
|
||||
# Run: bash /mnt/converter/frontend/install.sh
|
||||
#
|
||||
# Installs system tools, Python dependencies, and the systemd
|
||||
# service that serves the web UI on port 5000.
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SERVICE_NAME="vm-bench"
|
||||
SERVICE_FILE="${SCRIPT_DIR}/${SERVICE_NAME}.service"
|
||||
SYSTEMD_DIR="/etc/systemd/system"
|
||||
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════╗"
|
||||
echo "║ VM Bench Frontend Installer (LXC) ║"
|
||||
echo "╚════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 1: System packages
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo "[1/5] Checking system packages..."
|
||||
|
||||
PACKAGES=()
|
||||
REQUIRED=(
|
||||
python3 "python3"
|
||||
python3-pip "pip3"
|
||||
wget "wget"
|
||||
curl "curl"
|
||||
)
|
||||
|
||||
for ((i=0; i<${#REQUIRED[@]}; i+=2)); do
|
||||
pkg="${REQUIRED[$i]}"
|
||||
bin="${REQUIRED[$i+1]}"
|
||||
if command -v "$bin" &>/dev/null; then
|
||||
echo " ${GREEN}✓${NC} $bin"
|
||||
else
|
||||
echo " ${YELLOW}○${NC} $bin (will install ${pkg})"
|
||||
PACKAGES+=("$pkg")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#PACKAGES[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
echo " Installing missing packages: ${PACKAGES[*]}"
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq "${PACKAGES[@]}"
|
||||
echo " ${GREEN}✓${NC} System packages installed."
|
||||
else
|
||||
echo " ${GREEN}✓${NC} All system packages present."
|
||||
fi
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 2: Python dependencies
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[2/5] Installing Python dependencies..."
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
python3 -m pip install --break-system-packages -r requirements.txt -q
|
||||
echo " ${GREEN}✓${NC} Python dependencies installed."
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 3: Verify backend connectivity
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[3/5] Checking backend connectivity..."
|
||||
|
||||
BACKEND_URL="${BACKEND_URL:-http://10.2.0.2:9000}"
|
||||
if curl -sf --max-time 5 "${BACKEND_URL}/api/v1/health" > /dev/null 2>&1; then
|
||||
echo " ${GREEN}✓${NC} Backend reachable at $BACKEND_URL"
|
||||
else
|
||||
echo " ${YELLOW}!${NC} Backend not reachable at $BACKEND_URL"
|
||||
echo " The frontend will start, but conversion jobs will fail until the"
|
||||
echo " backend is running on srv2. You can change BACKEND_URL in"
|
||||
echo " ${SYSTEMD_DIR}/${SERVICE_NAME}.service"
|
||||
fi
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 4: Systemd service
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[4/5] Installing systemd service..."
|
||||
|
||||
if [ ! -f "$SERVICE_FILE" ]; then
|
||||
echo " ${RED}✗${NC} Service file not found: $SERVICE_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "$SERVICE_FILE" "$SYSTEMD_DIR/${SERVICE_NAME}.service"
|
||||
systemctl daemon-reload
|
||||
systemctl enable "$SERVICE_NAME"
|
||||
echo " ${GREEN}✓${NC} Service installed and enabled."
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
# Step 5: Start & verify
|
||||
# ───────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "[5/5] Starting service..."
|
||||
|
||||
systemctl restart "$SERVICE_NAME"
|
||||
sleep 2
|
||||
|
||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
echo " ${GREEN}✓${NC} Frontend is RUNNING on port 5000"
|
||||
echo ""
|
||||
echo " Open: http://$(hostname -I 2>/dev/null | awk '{print $1}'):5000"
|
||||
echo " Verify: curl http://127.0.0.1:5000"
|
||||
echo " Logs: journalctl -u ${SERVICE_NAME} -f"
|
||||
echo " Status: systemctl status ${SERVICE_NAME}"
|
||||
else
|
||||
echo " ${RED}✗${NC} Service failed to start. Check logs:"
|
||||
echo " journalctl -u ${SERVICE_NAME} -n 30"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════╗"
|
||||
echo "║ ${GREEN}Frontend installation complete.${NC} ║"
|
||||
echo "╚════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
16
frontend/vm-bench.service
Normal file
16
frontend/vm-bench.service
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=VM Bench — Proxmox Image Conversion Frontend
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/mnt/converter/frontend
|
||||
Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
||||
Environment=BACKEND_URL=http://10.2.0.2:9000
|
||||
ExecStart=/usr/bin/python3 -m uvicorn app:app --host 0.0.0.0 --port 5000
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Reference in a new issue