Files
proxmox/scripts/npmplus/automate-phase1-create-container.sh
defiQUG b3a8fe4496
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
chore: sync all changes to Gitea
- Config, docs, scripts, and backup manifests
- Submodule refs unchanged (m = modified content in submodules)

Made-with: Cursor
2026-03-02 11:37:34 -08:00

198 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Phase 1: Create and configure secondary NPMplus container
set -euo pipefail
# Load IP configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
if [ -f "$PROJECT_ROOT/.env" ]; then
set +euo pipefail
source "$PROJECT_ROOT/.env" 2>/dev/null || true
set -euo pipefail
fi
SECONDARY_HOST="${SECONDARY_HOST:-192.168.11.12}"
SECONDARY_VMID="${SECONDARY_VMID:-10234}"
SECONDARY_IP="${SECONDARY_IP:-${IP_NPMPLUS:-192.168.11.167}}"
HOSTNAME="npmplus-secondary"
TZ="${TZ:-America/New_York}"
ACME_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }
log_info "Creating secondary NPMplus container (VMID $SECONDARY_VMID)..."
# Check if container already exists
if ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct status $SECONDARY_VMID 2>/dev/null" >/dev/null 2>&1; then
log_warn "Container VMID $SECONDARY_VMID already exists"
read -p "Delete and recreate? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log_info "Stopping and destroying existing container..."
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct stop $SECONDARY_VMID 2>/dev/null || true"
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct destroy $SECONDARY_VMID 2>/dev/null || true"
else
log_info "Skipping container creation"
exit 0
fi
fi
# Check for Alpine template
log_info "Checking for Alpine template..."
EXISTING_TEMPLATE=$(ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pveam list local | grep -i 'alpine' | head -1 | awk '{print \$1}'" 2>/dev/null || echo "")
if [ -n "$EXISTING_TEMPLATE" ]; then
# Extract just the template name (remove storage prefix if present)
TEMPLATE=$(echo "$EXISTING_TEMPLATE" | sed 's|.*/||' | sed 's|^local:vztmpl/||')
log_success "Using existing template: $TEMPLATE"
else
log_info "No Alpine template found locally, checking available templates..."
# Get template name (second column, skip header)
TEMPLATE_NAME=$(ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pveam available | grep -i 'alpine.*3.22' | head -1 | awk '{print \$2}'" 2>/dev/null || echo "")
if [ -n "$TEMPLATE_NAME" ] && [ "$TEMPLATE_NAME" != "template" ]; then
log_info "Downloading template: $TEMPLATE_NAME to local storage"
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pveam download local $TEMPLATE_NAME" || {
log_error "Failed to download template"
exit 1
}
TEMPLATE="$TEMPLATE_NAME"
else
# Try any Alpine template
TEMPLATE_NAME=$(ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pveam available | grep -i alpine | head -1 | awk '{print \$2}'" 2>/dev/null || echo "")
if [ -n "$TEMPLATE_NAME" ] && [ "$TEMPLATE_NAME" != "template" ]; then
log_info "Downloading Alpine template: $TEMPLATE_NAME to local storage"
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pveam download local $TEMPLATE_NAME" || {
log_error "Failed to download template"
exit 1
}
TEMPLATE="$TEMPLATE_NAME"
else
log_error "No Alpine template found. Please download one manually."
exit 1
fi
fi
fi
# Determine storage (must be lvmthin for containers, and must be active)
STORAGE=$(ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pvesm status | grep -E 'lvmthin.*active' | grep -v 'inactive' | awk '{print \$1}' | head -1" 2>/dev/null || echo "")
if [ -z "$STORAGE" ]; then
# Try specific thin pools that are known to be active
for thin in thin1-r630-02 thin5 thin6; do
STATUS=$(ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pvesm status | grep '^$thin' | awk '{print \$3}'" 2>/dev/null || echo "")
if [ "$STATUS" = "active" ]; then
STORAGE="$thin"
break
fi
done
fi
if [ -z "$STORAGE" ]; then
log_error "No suitable active LVM thin storage found"
log_info "Available storage:"
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pvesm status" 2>/dev/null || true
exit 1
fi
ROOTFS_STORAGE="$STORAGE"
log_info "Using storage: $ROOTFS_STORAGE"
# Create container
log_info "Creating container..."
# Ensure template path is correct
if [[ "$TEMPLATE" == *"vztmpl/"* ]]; then
TEMPLATE_PATH="$TEMPLATE"
else
TEMPLATE_PATH="local:vztmpl/$TEMPLATE"
fi
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct create $SECONDARY_VMID \
$TEMPLATE_PATH \
--hostname $HOSTNAME \
--memory 1024 \
--cores 2 \
--rootfs $ROOTFS_STORAGE:5 \
--net0 name=eth0,bridge=vmbr0,ip=$SECONDARY_IP/24,gw=${NETWORK_GATEWAY:-192.168.11.1} \
--unprivileged 1 \
--features nesting=1" || {
log_error "Failed to create container"
exit 1
}
log_success "Container created"
# Start container
log_info "Starting container..."
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct start $SECONDARY_VMID" || {
log_error "Failed to start container"
exit 1
}
sleep 10
log_success "Container started"
# Install NPMplus
log_info "Installing NPMplus..."
ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct exec $SECONDARY_VMID -- ash" <<INSTALL_EOF
set -e
apk update
apk add --no-cache tzdata gawk yq docker docker-compose curl bash rsync
rc-service docker start
rc-update add docker default
sleep 5
cd /opt
curl -fsSL "https://raw.githubusercontent.com/ZoeyVid/NPMplus/refs/heads/develop/compose.yaml" -o compose.yaml
yq -i "
.services.npmplus.environment |=
(map(select(. != \"TZ=*\" and . != \"ACME_EMAIL=*\")) +
[\"TZ=$TZ\", \"ACME_EMAIL=$ACME_EMAIL\"])
" compose.yaml
docker compose up -d
# Wait for NPMplus to be ready
for i in {1..60}; do
if docker ps --filter "name=npmplus" --format "{{.Status}}" | grep -qE "healthy|Up"; then
echo "NPMplus is ready"
break
fi
sleep 2
done
INSTALL_EOF
if [ $? -eq 0 ]; then
log_success "NPMplus installed and running"
else
log_error "NPMplus installation failed"
exit 1
fi
# Verify network
log_info "Verifying network configuration..."
ACTUAL_IP=$(ssh -o StrictHostKeyChecking=no root@"$SECONDARY_HOST" "pct exec $SECONDARY_VMID -- hostname -I | awk '{print \$1}'" || echo "")
if [ "$ACTUAL_IP" = "$SECONDARY_IP" ]; then
log_success "Network configured correctly: $ACTUAL_IP"
else
log_warn "IP mismatch: Expected $SECONDARY_IP, got $ACTUAL_IP"
fi
log_success "Phase 1 complete: Secondary container ready"