d8cb0dc06d
Web tool for designing nickel/copper busbars over cylindrical-cell battery packs (21700, 18650) in hex holders. Flask + build123d backend exports STEP/DXF/SVG; vanilla JS frontend with live preview, multi-project SQLite persistence, snapshot history. Deploy scripts in deploy/ (proxmox-lxc.sh, install.sh, update.sh).
196 lines
7.2 KiB
Bash
196 lines
7.2 KiB
Bash
#!/usr/bin/env bash
|
|
# proxmox-lxc.sh — create an unprivileged Debian 12 LXC on a Proxmox VE host
|
|
# and install Busbar Designer into it. Inspired by the community-scripts style.
|
|
#
|
|
# Run on the Proxmox host as root, e.g.:
|
|
#
|
|
# bash -c "$(curl -fsSL https://gitea.local/me/busbar-designer/raw/branch/main/deploy/proxmox-lxc.sh)"
|
|
#
|
|
# Interactive whiptail prompts; or pre-set everything via env to skip prompts:
|
|
#
|
|
# REPO_URL=https://gitea.local/me/busbar-designer.git \
|
|
# CTID=210 HOSTNAME=busbar DISK_SIZE=4 CORES=2 RAM=1024 \
|
|
# BRIDGE=vmbr0 IP=dhcp STORAGE=local-lvm \
|
|
# bash proxmox-lxc.sh
|
|
|
|
set -euo pipefail
|
|
|
|
# ---- colors ----------------------------------------------------------------
|
|
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'
|
|
BLUE='\033[0;34m'; BOLD='\033[1m'; NC='\033[0m'
|
|
log() { echo -e "${GREEN}▸${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}!${NC} $*"; }
|
|
die() { echo -e "${RED}✗ $*${NC}" >&2; exit 1; }
|
|
|
|
banner() {
|
|
cat <<'EOF'
|
|
|
|
____ _ ____ _
|
|
| __ ) _ _ ___| |__ __ _ _ __ | _ \ ___ ___(_) __ _ _ __ ___ _ __
|
|
| _ \| | | / __| '_ \ / _` | '__| | | | |/ _ \/ __| |/ _` | '_ \ / _ \ '__|
|
|
| |_) | |_| \__ \ |_) | (_| | | | |_| | __/\__ \ | (_| | | | | __/ |
|
|
|____/ \__,_|___/_.__/ \__,_|_| |____/ \___||___/_|\__, |_| |_|\___|_|
|
|
|___/
|
|
Proxmox VE LXC installer
|
|
|
|
EOF
|
|
}
|
|
|
|
# ---- preflight -------------------------------------------------------------
|
|
[[ $EUID -eq 0 ]] || die "Run as root on the Proxmox host."
|
|
command -v pveversion >/dev/null 2>&1 || die "pveversion not found — is this a Proxmox VE host?"
|
|
command -v pct >/dev/null 2>&1 || die "pct not found — Proxmox VE tools missing?"
|
|
|
|
banner
|
|
|
|
# ---- defaults --------------------------------------------------------------
|
|
CTID_DEFAULT=$(pvesh get /cluster/nextid 2>/dev/null || echo "200")
|
|
CTID="${CTID:-$CTID_DEFAULT}"
|
|
HOSTNAME="${HOSTNAME:-busbar-designer}"
|
|
DISK_SIZE="${DISK_SIZE:-4}"
|
|
CORES="${CORES:-2}"
|
|
RAM="${RAM:-1024}"
|
|
SWAP="${SWAP:-512}"
|
|
BRIDGE="${BRIDGE:-vmbr0}"
|
|
IP="${IP:-dhcp}"
|
|
STORAGE="${STORAGE:-local-lvm}"
|
|
TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}"
|
|
REPO_URL="${REPO_URL:-}"
|
|
BRANCH="${BRANCH:-main}"
|
|
GIT_SSL_NO_VERIFY="${GIT_SSL_NO_VERIFY:-0}"
|
|
|
|
# ---- interactive prompts (whiptail) ----------------------------------------
|
|
ask() {
|
|
local var="$1" prompt="$2" default="$3" h="${4:-8}" w="${5:-60}"
|
|
local val
|
|
if [[ -t 0 ]] && command -v whiptail >/dev/null 2>&1; then
|
|
val=$(whiptail --title "Busbar Designer" --inputbox "$prompt" "$h" "$w" "$default" \
|
|
3>&1 1>&2 2>&3) || die "Cancelled."
|
|
else
|
|
read -rp "$prompt [$default]: " val
|
|
val="${val:-$default}"
|
|
fi
|
|
printf -v "$var" '%s' "$val"
|
|
}
|
|
|
|
yesno() {
|
|
local prompt="$1" default="${2:-no}"
|
|
if [[ -t 0 ]] && command -v whiptail >/dev/null 2>&1; then
|
|
if [[ "$default" == "yes" ]]; then
|
|
whiptail --title "Busbar Designer" --yesno "$prompt" 8 60
|
|
else
|
|
whiptail --title "Busbar Designer" --yesno "$prompt" --defaultno 8 60
|
|
fi
|
|
else
|
|
read -rp "$prompt [$default]: " val
|
|
[[ "${val:-$default}" =~ ^(y|yes)$ ]]
|
|
fi
|
|
}
|
|
|
|
if [[ -z "$REPO_URL" ]] || [[ -t 0 ]]; then
|
|
ask CTID "Container ID" "$CTID"
|
|
ask HOSTNAME "Hostname" "$HOSTNAME"
|
|
ask DISK_SIZE "Root disk size (GB)" "$DISK_SIZE"
|
|
ask CORES "CPU cores" "$CORES"
|
|
ask RAM "RAM (MB)" "$RAM"
|
|
ask STORAGE "Storage pool for rootfs (e.g. local-lvm, local-zfs)" "$STORAGE" 8 70
|
|
ask BRIDGE "Network bridge" "$BRIDGE"
|
|
ask IP "IP config: 'dhcp' or 'a.b.c.d/24,gw=a.b.c.1'" "$IP" 8 70
|
|
ask REPO_URL "Git URL of busbar-designer repo (your Gitea / GitHub)" \
|
|
"${REPO_URL:-https://gitea.local/me/busbar-designer.git}" 10 70
|
|
ask BRANCH "Branch" "$BRANCH"
|
|
if yesno "Skip TLS verification for git? (only if your Gitea uses a self-signed cert)"; then
|
|
GIT_SSL_NO_VERIFY=1
|
|
fi
|
|
fi
|
|
|
|
[[ -n "$REPO_URL" ]] || die "REPO_URL is required."
|
|
|
|
# ---- template --------------------------------------------------------------
|
|
log "Looking for a Debian 12 template..."
|
|
TEMPLATE=$(pveam available --section system 2>/dev/null \
|
|
| awk '/debian-12-standard/ {print $2}' | sort -r | head -n 1)
|
|
[[ -n "$TEMPLATE" ]] || die "Couldn't find debian-12-standard in 'pveam available'. Run 'pveam update' first."
|
|
|
|
LOCAL_TEMPLATE="/var/lib/vz/template/cache/$TEMPLATE"
|
|
if [[ ! -f "$LOCAL_TEMPLATE" ]]; then
|
|
log "Downloading template $TEMPLATE..."
|
|
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
|
|
fi
|
|
|
|
# ---- create LXC ------------------------------------------------------------
|
|
if pct status "$CTID" >/dev/null 2>&1; then
|
|
die "Container $CTID already exists. Pick a different CTID."
|
|
fi
|
|
|
|
PASSWORD="$(openssl rand -base64 12 | tr -d '/+=' | cut -c1-16)"
|
|
|
|
if [[ "$IP" == "dhcp" ]]; then
|
|
NET="name=eth0,bridge=$BRIDGE,ip=dhcp"
|
|
else
|
|
NET="name=eth0,bridge=$BRIDGE,ip=$IP"
|
|
fi
|
|
|
|
log "Creating LXC $CTID ($HOSTNAME)..."
|
|
pct create "$CTID" "$TEMPLATE_STORAGE:vztmpl/$TEMPLATE" \
|
|
--hostname "$HOSTNAME" \
|
|
--cores "$CORES" \
|
|
--memory "$RAM" \
|
|
--swap "$SWAP" \
|
|
--rootfs "$STORAGE:$DISK_SIZE" \
|
|
--net0 "$NET" \
|
|
--password "$PASSWORD" \
|
|
--features nesting=1 \
|
|
--unprivileged 1 \
|
|
--onboot 1 \
|
|
--start 1 \
|
|
--description "Busbar Designer · $REPO_URL ($BRANCH)" >/dev/null
|
|
|
|
# ---- wait for network ------------------------------------------------------
|
|
log "Waiting for network in CT $CTID..."
|
|
for i in {1..30}; do
|
|
if pct exec "$CTID" -- bash -c "getent hosts deb.debian.org >/dev/null" 2>/dev/null; then
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
# ---- run installer inside the LXC ------------------------------------------
|
|
log "Bootstrapping git + curl in the container..."
|
|
pct exec "$CTID" -- bash -c "
|
|
set -e
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq
|
|
apt-get install -y -qq git ca-certificates curl
|
|
" || die "Failed to install bootstrap packages in CT."
|
|
|
|
log "Cloning repo and running deploy/install.sh inside CT $CTID..."
|
|
pct exec "$CTID" -- bash -c "
|
|
set -e
|
|
${GIT_SSL_NO_VERIFY:+export GIT_SSL_NO_VERIFY=true}
|
|
rm -rf /opt/busbar-designer
|
|
git clone --depth 1 -b '$BRANCH' '$REPO_URL' /opt/busbar-designer
|
|
REPO_URL='$REPO_URL' BRANCH='$BRANCH' \
|
|
${GIT_SSL_NO_VERIFY:+GIT_SSL_NO_VERIFY=1} \
|
|
bash /opt/busbar-designer/deploy/install.sh
|
|
" || die "Installer failed. Inspect with: pct enter $CTID"
|
|
|
|
# ---- report ---------------------------------------------------------------
|
|
IP_ADDR=$(pct exec "$CTID" -- bash -c "hostname -I | awk '{print \$1}'" 2>/dev/null || true)
|
|
[[ -n "$IP_ADDR" ]] || IP_ADDR="<unknown — check 'pct exec $CTID -- ip a'>"
|
|
|
|
echo
|
|
log "================================================================"
|
|
log " ${BOLD}✓ Busbar Designer LXC ready${NC}"
|
|
log ""
|
|
log " Container ID: $CTID"
|
|
log " Hostname: $HOSTNAME"
|
|
log " Root password: $PASSWORD"
|
|
log " URL: http://$IP_ADDR:5000"
|
|
log ""
|
|
log " Update: pct exec $CTID -- bash /opt/busbar-designer/deploy/update.sh"
|
|
log " Logs: pct exec $CTID -- journalctl -u busbar-designer -f"
|
|
log " Enter: pct enter $CTID"
|
|
log " Backup: pct exec $CTID -- cat /opt/busbar-designer/data/busbar.db > backup.db"
|
|
log "================================================================"
|