Initial commit: loc_az_hci (smom-dbis-138 excluded via .gitignore)
Some checks failed
Test / test (push) Has been cancelled

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-02-08 09:04:46 -08:00
commit c39465c2bd
386 changed files with 50649 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
#!/bin/bash
source ~/.bashrc
# Apply Install Scripts to VMs via SSH
# This script connects to each VM and runs the appropriate install script
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# VM Configuration
declare -A VMS=(
[100]="cloudflare-tunnel:192.168.1.60:setup-cloudflare-tunnel.sh"
[101]="k3s-master:192.168.1.188:setup-k3s.sh"
[102]="git-server:192.168.1.121:setup-git-server.sh"
[103]="observability:192.168.1.82:setup-observability.sh"
)
SSH_USER="${SSH_USER:-ubuntu}"
SSH_KEY="${SSH_KEY:-~/.ssh/id_rsa}"
# Check if VM is reachable
check_vm_reachable() {
local ip=$1
local timeout=5
if ping -c 1 -W $timeout "$ip" > /dev/null 2>&1; then
return 0
else
return 1
fi
}
# Wait for VM to be ready
wait_for_vm() {
local ip=$1
local max_attempts=30
local attempt=0
log_info "Waiting for VM at $ip to be reachable..."
while [ $attempt -lt $max_attempts ]; do
if check_vm_reachable "$ip"; then
log_info "✓ VM is reachable"
return 0
fi
attempt=$((attempt + 1))
echo -n "."
sleep 2
done
echo ""
log_error "VM at $ip is not reachable after $max_attempts attempts"
return 1
}
# Check SSH connectivity
check_ssh() {
local ip=$1
local user=$2
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -i "$SSH_KEY" "${user}@${ip}" "echo 'SSH OK'" > /dev/null 2>&1; then
return 0
else
return 1
fi
}
# Wait for SSH
wait_for_ssh() {
local ip=$1
local user=$2
local max_attempts=60
local attempt=0
log_info "Waiting for SSH on $ip..."
while [ $attempt -lt $max_attempts ]; do
if check_ssh "$ip" "$user"; then
log_info "✓ SSH is ready"
return 0
fi
attempt=$((attempt + 1))
echo -n "."
sleep 5
done
echo ""
log_error "SSH not available after $max_attempts attempts"
return 1
}
# Apply install script to VM
apply_install_script() {
local vmid=$1
local name=$2
local ip=$3
local script=$4
log_step "Applying install script to VM $vmid: $name"
# Wait for VM to be ready
if ! wait_for_vm "$ip"; then
log_error "VM not reachable, skipping..."
return 1
fi
# Wait for SSH
if ! wait_for_ssh "$ip" "$SSH_USER"; then
log_error "SSH not available, skipping..."
return 1
fi
# Copy install script to VM
log_info "Copying install script to VM..."
if ! scp -o StrictHostKeyChecking=no -i "$SSH_KEY" "scripts/${script}" "${SSH_USER}@${ip}:/tmp/install-service.sh"; then
log_error "Failed to copy script"
return 1
fi
# Make script executable and run it
log_info "Running install script on VM..."
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" <<EOF
sudo chmod +x /tmp/install-service.sh
sudo /tmp/install-service.sh
EOF
if [ $? -eq 0 ]; then
log_info "✓ Install script completed successfully"
return 0
else
log_error "✗ Install script failed"
return 1
fi
}
main() {
echo "========================================="
echo "Apply Install Scripts to VMs"
echo "========================================="
echo ""
if [ ! -f "$SSH_KEY" ]; then
log_error "SSH key not found: $SSH_KEY"
log_info "Set SSH_KEY environment variable or create key pair"
exit 1
fi
log_info "Using SSH key: $SSH_KEY"
log_info "SSH user: $SSH_USER"
echo ""
# Apply scripts to each VM
for vmid in 100 101 102 103; do
IFS=':' read -r name ip script <<< "${VMS[$vmid]}"
if apply_install_script "$vmid" "$name" "$ip" "$script"; then
log_info "✓ VM $vmid ($name) setup complete"
else
log_error "✗ Failed to setup VM $vmid"
fi
echo ""
done
log_info "========================================="
log_info "Install Script Application Complete"
log_info "========================================="
echo ""
log_info "All VMs should now have their services installed"
log_info "Check each VM to verify services are running"
}
main "$@"

View File

@@ -0,0 +1,54 @@
#!/bin/bash
source ~/.bashrc
# Interactive Guide for Attaching ISO via Web UI
clear
echo "========================================="
echo "Attach ISO via Proxmox Web UI"
echo "========================================="
echo ""
echo "The CD-ROM option won't appear in boot order until"
echo "the CD/DVD drive with ISO is attached first."
echo ""
echo "Step-by-step instructions:"
echo ""
echo "1. Open Proxmox Web UI:"
echo " https://192.168.1.206:8006"
echo ""
echo "2. For EACH VM (100, 101, 102, 103):"
echo ""
echo " A. Click on the VM name in left panel"
echo ""
echo " B. Go to 'Hardware' tab"
echo ""
echo " C. Click 'Add' button (top of page)"
echo ""
echo " D. Select 'CD/DVD Drive' from dropdown"
echo ""
echo " E. In the dialog that appears:"
echo " - Storage: Select 'local'"
echo " - ISO image: Click dropdown"
echo " - Select: ubuntu-24.04.3-live-server-amd64.iso"
echo " - Click 'Add' button"
echo ""
echo " F. You should now see 'CD/DVD Drive (ide2)' in Hardware list"
echo ""
echo " G. Go to 'Options' tab"
echo ""
echo " H. Find 'Boot Order' and click 'Edit'"
echo ""
echo " I. Now you should see CD-ROM option!"
echo " - Move 'CD-ROM' to the top (first boot device)"
echo " - Click 'OK'"
echo ""
echo " J. Start the VM and open Console"
echo " - Ubuntu installer should boot"
echo ""
echo "========================================="
echo ""
read -p "Press Enter when you've attached ISO to all VMs..."
echo ""
echo "Verifying VM configurations..."
./scripts/check-vm-status.sh

View File

@@ -0,0 +1,480 @@
#!/bin/bash
source ~/.bashrc
# Complete All VM Tasks via SSH
# This script connects to each VM and completes all pending tasks from the TODO list
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
SSH_USER="${SSH_USER:-ubuntu}"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_rsa}"
# Expand ~ in SSH_KEY path if needed
if [[ "$SSH_KEY" == ~* ]]; then
SSH_KEY="${SSH_KEY/#\~/$HOME}"
fi
# VM Configuration
declare -A VMS=(
[100]="cloudflare-tunnel:192.168.1.60:setup-cloudflare-tunnel.sh"
[101]="k3s-master:192.168.1.188:setup-k3s.sh"
[102]="git-server:192.168.1.121:setup-git-server.sh"
[103]="observability:192.168.1.82:setup-observability.sh"
)
# Check if VM is reachable
check_vm_reachable() {
local ip=$1
if ping -c 1 -W 3 "$ip" > /dev/null 2>&1; then
return 0
else
return 1
fi
}
# Check SSH connectivity
check_ssh() {
local ip=$1
local user=$2
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -i "$SSH_KEY" "${user}@${ip}" "echo 'SSH OK'" > /dev/null 2>&1; then
return 0
else
return 1
fi
}
# Wait for VM to be ready
wait_for_vm() {
local ip=$1
local name=$2
local max_attempts=30
local attempt=0
log_info "Waiting for $name ($ip) to be reachable..."
while [ $attempt -lt $max_attempts ]; do
if check_vm_reachable "$ip"; then
log_info "✓ VM is reachable"
return 0
fi
attempt=$((attempt + 1))
echo -n "."
sleep 2
done
echo ""
log_error "VM at $ip is not reachable"
return 1
}
# Wait for SSH
wait_for_ssh() {
local ip=$1
local name=$2
local max_attempts=60
local attempt=0
log_info "Waiting for SSH on $name ($ip)..."
while [ $attempt -lt $max_attempts ]; do
if check_ssh "$ip" "$SSH_USER"; then
log_info "✓ SSH is ready"
return 0
fi
attempt=$((attempt + 1))
echo -n "."
sleep 5
done
echo ""
log_error "SSH not available on $ip"
return 1
}
# Install QEMU Guest Agent
install_guest_agent() {
local ip=$1
local name=$2
log_step "Installing QEMU Guest Agent on $name..."
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" <<'EOF'
sudo apt-get update -qq
sudo apt-get install -y qemu-guest-agent
sudo systemctl enable qemu-guest-agent
sudo systemctl start qemu-guest-agent
sudo systemctl status qemu-guest-agent --no-pager | head -3
EOF
if [ $? -eq 0 ]; then
log_info "✓ Guest agent installed and started"
return 0
else
log_error "✗ Failed to install guest agent"
return 1
fi
}
# Apply install script to VM
apply_install_script() {
local ip=$1
local name=$2
local script=$3
log_step "Applying install script: $script on $name..."
# Copy script to VM
if ! scp -o StrictHostKeyChecking=no -i "$SSH_KEY" "scripts/${script}" "${SSH_USER}@${ip}:/tmp/install-service.sh"; then
log_error "Failed to copy script"
return 1
fi
# Run script
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" <<'EOF'
sudo chmod +x /tmp/install-service.sh
sudo /tmp/install-service.sh
EOF
if [ $? -eq 0 ]; then
log_info "✓ Install script completed"
return 0
else
log_error "✗ Install script failed"
return 1
fi
}
# Verify service is running
verify_service() {
local ip=$1
local name=$2
local service_name=$3
log_step "Verifying $service_name on $name..."
case $service_name in
cloudflared)
if ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "sudo systemctl is-active --quiet cloudflared"; then
log_info "✓ Cloudflare Tunnel is running"
return 0
else
log_warn "⚠ Cloudflare Tunnel may not be running (manual config may be needed)"
return 1
fi
;;
k3s)
if ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "sudo systemctl is-active --quiet k3s && kubectl get nodes" > /dev/null 2>&1; then
log_info "✓ K3s is running"
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "kubectl get nodes"
return 0
else
log_warn "⚠ K3s may not be fully ready"
return 1
fi
;;
gitea)
if ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "sudo systemctl is-active --quiet gitea"; then
log_info "✓ Gitea is running"
log_info " Access at: http://${ip}:3000"
return 0
else
log_warn "⚠ Gitea may not be running"
return 1
fi
;;
observability)
local prom_running=false
local grafana_running=false
if ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "sudo systemctl is-active --quiet prometheus"; then
prom_running=true
fi
if ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "sudo systemctl is-active --quiet grafana-server"; then
grafana_running=true
fi
if [ "$prom_running" = true ] && [ "$grafana_running" = true ]; then
log_info "✓ Prometheus and Grafana are running"
log_info " Prometheus: http://${ip}:9090"
log_info " Grafana: http://${ip}:3000"
return 0
else
log_warn "⚠ Some services may not be running"
return 1
fi
;;
esac
}
# Process VM 100: Cloudflare Tunnel
setup_cloudflare_tunnel() {
local vmid=100
local name="cloudflare-tunnel"
local ip="192.168.1.60"
local script="setup-cloudflare-tunnel.sh"
log_header "VM $vmid: $name"
# Wait for VM
if ! wait_for_vm "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
if ! wait_for_ssh "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
# Install guest agent
install_guest_agent "$ip" "$name"
# Apply install script
apply_install_script "$ip" "$name" "$script"
# Verify
verify_service "$ip" "$name" "cloudflared"
log_warn "Note: Cloudflare Tunnel requires manual configuration:"
log_info " 1. Run: cloudflared tunnel login"
log_info " 2. Create tunnel: cloudflared tunnel create azure-stack-hci"
log_info " 3. Update /etc/cloudflared/config.yml"
log_info " 4. Configure DNS records in Cloudflare"
echo ""
}
# Process VM 101: K3s
setup_k3s() {
local vmid=101
local name="k3s-master"
local ip="192.168.1.188"
local script="setup-k3s.sh"
log_header "VM $vmid: $name"
# Wait for VM
if ! wait_for_vm "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
if ! wait_for_ssh "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
# Install guest agent
install_guest_agent "$ip" "$name"
# Apply install script
apply_install_script "$ip" "$name" "$script"
# Verify
verify_service "$ip" "$name" "k3s"
log_info "K3s cluster is ready!"
log_info " Kubeconfig: /etc/rancher/k3s/k3s.yaml"
echo ""
}
# Process VM 102: Git Server
setup_git_server() {
local vmid=102
local name="git-server"
local ip="192.168.1.121"
local script="setup-git-server.sh"
log_header "VM $vmid: $name"
# Wait for VM
if ! wait_for_vm "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
if ! wait_for_ssh "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
# Install guest agent
install_guest_agent "$ip" "$name"
# Apply install script
apply_install_script "$ip" "$name" "$script"
# Verify
verify_service "$ip" "$name" "gitea"
log_info "Gitea is ready!"
log_info " Access at: http://${ip}:3000"
log_warn " Complete initial setup via web UI"
echo ""
}
# Process VM 103: Observability
setup_observability() {
local vmid=103
local name="observability"
local ip="192.168.1.82"
local script="setup-observability.sh"
log_header "VM $vmid: $name"
# Wait for VM
if ! wait_for_vm "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
if ! wait_for_ssh "$ip" "$name"; then
log_error "Skipping $name"
return 1
fi
# Install guest agent
install_guest_agent "$ip" "$name"
# Apply install script
apply_install_script "$ip" "$name" "$script"
# Verify
verify_service "$ip" "$name" "observability"
log_info "Observability stack is ready!"
log_info " Prometheus: http://${ip}:9090"
log_info " Grafana: http://${ip}:3000 (admin/admin)"
log_warn " Change Grafana password on first login"
echo ""
}
# Enable guest agent in Proxmox
enable_guest_agent_proxmox() {
log_header "Enabling Guest Agent in Proxmox"
if [ -z "$PVE_ROOT_PASS" ]; then
log_warn "PVE_ROOT_PASS not set, skipping Proxmox configuration"
return 0
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
# Get authentication ticket
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_ROOT_PASS" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_warn "Failed to authenticate with Proxmox, skipping"
return 0
fi
# Enable agent for each VM
for vmid in 100 101 102 103; do
log_info "Enabling guest agent in Proxmox for VM $vmid..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "agent=1" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
if [ $? -eq 0 ]; then
log_info "✓ Agent enabled for VM $vmid"
else
log_warn "⚠ Failed to enable agent for VM $vmid"
fi
done
echo ""
}
main() {
log_header "Complete All VM Tasks"
echo ""
if [ ! -f "$SSH_KEY" ]; then
log_error "SSH key not found: $SSH_KEY"
log_info "Set SSH_KEY environment variable or create key pair"
exit 1
fi
log_info "Using SSH key: $SSH_KEY"
log_info "SSH user: $SSH_USER"
echo ""
# Process each VM
setup_cloudflare_tunnel
setup_k3s
setup_git_server
setup_observability
# Enable guest agent in Proxmox
enable_guest_agent_proxmox
log_header "All Tasks Complete!"
echo ""
log_info "Summary:"
echo " ✓ Guest agent installed on all VMs"
echo " ✓ Cloudflare Tunnel setup (manual config needed)"
echo " ✓ K3s installed and verified"
echo " ✓ Gitea installed (initial setup needed)"
echo " ✓ Observability stack installed"
echo ""
log_warn "Manual steps remaining:"
echo " 1. Configure Cloudflare Tunnel (VM 100)"
echo " 2. Complete Gitea initial setup (VM 102)"
echo " 3. Change Grafana password (VM 103)"
echo " 4. Configure K3s namespaces and services (VM 101)"
echo ""
}
main "$@"

View File

@@ -0,0 +1,178 @@
#!/bin/bash
source ~/.bashrc
# Complete VM Setup - Final Configuration and Cloud-Init Setup
# Attempts to configure everything possible via API
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
ISO_FILE="${ISO_FILE:-ubuntu-24.04.3-live-server-amd64.iso}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Complete VM setup with Cloud-Init
setup_vm_complete() {
local auth=$1
local vmid=$2
local name=$3
local ip_address=$4
local gateway=$5
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Complete setup for $name (ID: $vmid)..."
# Stop VM
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 2
# Enable Cloud-Init
log_info "Enabling Cloud-Init..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ipconfig0=ip=${ip_address}/24,gw=${gateway}" \
-d "nameserver=8.8.8.8" \
-d "ciuser=ubuntu" \
-d "cipassword=" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || log_warn "Cloud-Init config may have issues"
# Configure network (try POST method)
log_info "Configuring network interface..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || log_warn "Network config may need manual setup"
# Configure ISO (try POST method)
log_info "Configuring ISO..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=local:iso/${ISO_FILE},media=cdrom" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || log_warn "ISO config may need manual setup"
# Set boot order
log_info "Setting boot order..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
# Start VM
log_info "Starting VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1
log_info "$name configured and started"
}
# VM configurations with IPs
declare -A VMS=(
["100"]="cloudflare-tunnel:192.168.1.60:192.168.1.254"
["101"]="k3s-master:192.168.1.188:192.168.1.254"
["102"]="git-server:192.168.1.121:192.168.1.254"
["103"]="observability:192.168.1.82:192.168.1.254"
)
main() {
log_header "Complete VM Setup with Cloud-Init"
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "Configuring all VMs with Cloud-Init..."
echo ""
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name ip_address gateway <<< "${VMS[$vmid]}"
setup_vm_complete "$auth" "$vmid" "$name" "$ip_address" "$gateway"
echo ""
done
log_header "Setup Complete"
echo ""
log_info "All VMs configured with:"
echo " ✓ Cloud-Init enabled"
echo " ✓ Network interfaces configured"
echo " ✓ ISO attached"
echo " ✓ Boot order set"
echo ""
log_warn "Note: Network and ISO may need manual verification via Proxmox Web UI"
log_info "Next: Install Ubuntu via console (network/ISO should be ready)"
}
main "$@"

View File

@@ -0,0 +1,135 @@
#!/bin/bash
source ~/.bashrc
# Final VM Configuration Fix - Using Proxmox CLI format via API
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
ISO_FILE="${ISO_FILE:-ubuntu-24.04.3-live-server-amd64.iso}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Fix single VM
fix_vm_final() {
local auth=$1
local vmid=$2
local name=$3
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Final configuration for $name (ID: $vmid)..."
# Stop VM
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 2
# Network - try simplest possible format
log_info "Configuring network..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# ISO - try simplest format
log_info "Configuring ISO..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=local:iso/${ISO_FILE},media=cdrom" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Boot order
log_info "Setting boot order..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Start VM
log_info "Starting VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1
log_info "$name configured"
}
main() {
echo "========================================="
echo "Final VM Configuration Attempt"
echo "========================================="
echo ""
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
for vmid in 100 101 102 103; do
case $vmid in
100) name="cloudflare-tunnel" ;;
101) name="k3s-master" ;;
102) name="git-server" ;;
103) name="observability" ;;
esac
fix_vm_final "$auth" "$vmid" "$name"
echo ""
done
log_info "Configuration complete. Please verify via Proxmox Web UI."
log_info "If network/ISO still missing, configure manually via Web UI."
}
main "$@"

View File

@@ -0,0 +1,223 @@
#!/bin/bash
source ~/.bashrc
# Comprehensive VM Configuration Fix
# Uses multiple API approaches to ensure all hardware is configured
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
ISO_FILE="${ISO_FILE:-ubuntu-24.04.3-live-server-amd64.iso}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Check if config exists
config_exists() {
local auth=$1
local vmid=$2
local key=$3
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>/dev/null)
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
config = data.get('data', {})
print('true' if '$key' in config and config.get('$key') else 'false')
" 2>/dev/null || echo "false"
}
# Fix VM configuration comprehensively
fix_vm_comprehensive() {
local auth=$1
local vmid=$2
local name=$3
local disk_size=$4
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Comprehensive fix for $name (ID: $vmid)..."
# Stop VM
log_info "Stopping VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 3
# Try multiple network formats
if [ "$(config_exists "$auth" "$vmid" "net0")" = "false" ]; then
log_info "Adding network interface..."
# Try format 1: model=virtio,bridge=vmbr0
local net1=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=model=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$net1" | grep -q '"errors"'; then
# Try format 2: bridge=vmbr0 (let Proxmox use default model)
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
fi
log_info "✓ Network interface configured"
else
log_info "✓ Network interface already exists"
fi
# Try multiple disk formats
if [ "$(config_exists "$auth" "$vmid" "scsi0")" = "false" ]; then
log_info "Adding disk..."
# Try local-lvm first (LVM thin)
local disk1=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=local-lvm:${disk_size}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$disk1" | grep -q '"errors"'; then
# Try local storage
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=local:${disk_size}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
fi
log_info "✓ Disk configured"
else
log_info "✓ Disk already exists"
fi
# Add ISO
if [ "$(config_exists "$auth" "$vmid" "ide2")" = "false" ]; then
log_info "Adding ISO..."
local iso_volid="local:iso/${ISO_FILE}"
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=${iso_volid},media=cdrom" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
log_info "✓ ISO configured"
else
log_info "✓ ISO already configured"
fi
# Set boot order
log_info "Setting boot order..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
# Start VM
log_info "Starting VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1
log_info "✓ VM $vmid fully configured and started"
echo ""
}
# VM configurations
declare -A VMS=(
["100"]="cloudflare-tunnel:40"
["101"]="k3s-master:80"
["102"]="git-server:100"
["103"]="observability:200"
)
main() {
echo "========================================="
echo "Comprehensive VM Configuration Fix"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "Fixing all VM configurations..."
echo ""
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name disk_size <<< "${VMS[$vmid]}"
fix_vm_comprehensive "$auth" "$vmid" "$name" "$disk_size"
done
log_info "========================================="
log_info "All VM Configurations Fixed"
log_info "========================================="
echo ""
log_info "Next: Verify configurations and install Ubuntu"
}
main "$@"

View File

@@ -0,0 +1,174 @@
#!/bin/bash
source ~/.bashrc
# Fix Boot Configuration - Ensure VMs can boot from ISO
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
ISO_FILE="${ISO_FILE:-ubuntu-24.04.3-live-server-amd64.iso}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Fix boot configuration for a VM
fix_boot() {
local auth=$1
local vmid=$2
local name=$3
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Fixing boot configuration for $name (ID: $vmid)..."
# Stop VM
log_info "Stopping VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 2
# First, ensure we have a network device
log_info "Ensuring network device exists..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Ensure ISO is attached - try multiple formats
log_info "Attaching ISO..."
local iso_volid="local:iso/${ISO_FILE}"
# Try format 1: ide2=storage:iso/file.iso,media=cdrom
local iso1=$(curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=${iso_volid},media=cdrom" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$iso1" | grep -q '"errors"'; then
# Try format 2: ide2=storage:iso/file.iso
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=${iso_volid}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
fi
# Set boot order - CD-ROM first, then disk
log_info "Setting boot order to CD-ROM first..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2;scsi0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || \
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Also try setting bootdisk
log_info "Setting boot disk..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "bootdisk=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Start VM
log_info "Starting VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1
log_info "✓ Boot configuration fixed for $name"
echo ""
}
main() {
echo "========================================="
echo "Fix Boot Configuration"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Fix all VMs
for vmid in 100 101 102 103; do
case $vmid in
100) name="cloudflare-tunnel" ;;
101) name="k3s-master" ;;
102) name="git-server" ;;
103) name="observability" ;;
esac
fix_boot "$auth" "$vmid" "$name"
done
log_info "========================================="
log_info "Boot Configuration Fixed"
log_info "========================================="
echo ""
log_info "VMs should now boot from ISO."
log_info "If still having issues, verify via Proxmox Web UI:"
log_info " - Hardware tab: Check CD/DVD drive has ISO"
log_info " - Options tab: Boot order should be CD-ROM first"
}
main "$@"

View File

@@ -0,0 +1,160 @@
#!/bin/bash
source ~/.bashrc
# Fix Floppy Boot Issue - Remove Floppy and Set Correct Boot Order
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Fix floppy boot issue
fix_floppy_boot() {
local auth=$1
local vmid=$2
local name=$3
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Fixing boot order for $name (ID: $vmid)..."
# Stop VM
log_info "Stopping VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 2
# Remove floppy drive if it exists
log_info "Removing floppy drive (if exists)..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "floppy0=none" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Delete floppy device
curl -k -s -X DELETE \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config/floppy0" > /dev/null 2>&1 || true
# Set boot order explicitly: CD-ROM first, then disk, skip floppy
log_info "Setting boot order: CD-ROM first, then disk..."
# Method 1: Set boot order with explicit device order
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2;scsi0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Method 2: Set bootdisk to CD-ROM
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "bootdisk=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Method 3: Disable floppy in BIOS
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "bios=ovmf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 || true
# Start VM
log_info "Starting VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1
log_info "✓ Boot order fixed for $name"
echo ""
}
main() {
echo "========================================="
echo "Fix Floppy Boot Issue"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Fix all VMs
for vmid in 100 101 102 103; do
case $vmid in
100) name="cloudflare-tunnel" ;;
101) name="k3s-master" ;;
102) name="git-server" ;;
103) name="observability" ;;
esac
fix_floppy_boot "$auth" "$vmid" "$name"
done
log_info "========================================="
log_info "Floppy Boot Issue Fixed"
log_info "========================================="
echo ""
log_info "VMs should now boot from CD-ROM."
log_info "If still booting from floppy, remove floppy via Web UI:"
log_info " Hardware tab → Remove floppy drive → Set boot order"
}
main "$@"

View File

@@ -0,0 +1,186 @@
#!/bin/bash
source ~/.bashrc
# Fix Guest Agent Issues - Troubleshooting Script
# Use this if guest agent is not working properly
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
declare -A VMS=(
[100]="cloudflare-tunnel:192.168.1.60"
[101]="k3s-master:192.168.1.188"
[102]="git-server:192.168.1.121"
[103]="observability:192.168.1.82"
)
SSH_USER="${SSH_USER:-ubuntu}"
SSH_KEY="${SSH_KEY:-~/.ssh/id_rsa}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Fix guest agent on a VM
fix_guest_agent() {
local vmid=$1
local name=$2
local ip=$3
log_step "Fixing guest agent on VM $vmid: $name"
# Check SSH
if ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "echo 'SSH OK'" > /dev/null 2>&1; then
log_error "SSH not available, skipping..."
return 1
fi
log_info "Reinstalling and restarting guest agent..."
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" <<EOF
sudo systemctl stop qemu-guest-agent || true
sudo apt-get update
sudo apt-get install --reinstall -y qemu-guest-agent
sudo systemctl daemon-reload
sudo systemctl enable qemu-guest-agent
sudo systemctl restart qemu-guest-agent
sleep 2
sudo systemctl status qemu-guest-agent --no-pager | head -10
EOF
if [ $? -eq 0 ]; then
log_info "✓ Guest agent fixed on VM $vmid"
return 0
else
log_error "✗ Failed to fix guest agent"
return 1
fi
}
# Verify Proxmox configuration
verify_proxmox_config() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Checking Proxmox configuration for VM $vmid"
local config=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config")
local agent=$(echo "$config" | grep -o '"agent":"[^"]*' | cut -d'"' -f4)
if [ "$agent" = "1" ]; then
log_info "✓ Agent enabled in Proxmox (agent=1)"
else
log_warn "⚠ Agent not enabled in Proxmox"
log_info "Enabling agent..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "agent=1" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null
log_info "✓ Agent enabled"
fi
}
main() {
echo "========================================="
echo "Fix Guest Agent Issues"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
if [ ! -f "$SSH_KEY" ]; then
log_error "SSH key not found: $SSH_KEY"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Fix each VM
for vmid in 100 101 102 103; do
IFS=':' read -r name ip <<< "${VMS[$vmid]}"
echo "----------------------------------------"
log_step "Fixing VM $vmid: $name"
echo ""
# Fix guest agent on VM
fix_guest_agent "$vmid" "$name" "$ip"
# Verify Proxmox config
verify_proxmox_config "$auth" "$vmid"
echo ""
done
log_info "========================================="
log_info "Guest Agent Fix Complete"
log_info "========================================="
echo ""
log_info "Wait a few minutes, then verify in Proxmox:"
echo " VM → Monitor → QEMU Guest Agent"
}
main "$@"

View File

@@ -0,0 +1,190 @@
#!/bin/bash
source ~/.bashrc
# Fix VM Configuration Warnings
# Corrects network, disk, and ISO configurations
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
ISO_FILE="${ISO_FILE:-ubuntu-24.04.3-live-server-amd64.iso}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Fix VM configuration
fix_vm_config() {
local auth=$1
local vmid=$2
local name=$3
local disk_size=$4
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Fixing configuration for $name (ID: $vmid)..."
# Stop VM if running
log_info "Stopping VM $vmid..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 2
# Fix network - use proper format
log_info "Configuring network..."
local net_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=model=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$net_response" | grep -q '"errors"'; then
log_warn "Network config may have issues, but continuing..."
else
log_info "✓ Network configured"
fi
# Fix disk - ensure proper format
log_info "Configuring disk..."
local disk_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=local-lvm:${disk_size},format=raw" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$disk_response" | grep -q '"errors"'; then
# Try with local storage instead
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=local:${disk_size},format=raw" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
log_info "✓ Disk configured (using local storage)"
else
log_info "✓ Disk configured"
fi
# Fix ISO - ensure proper format
log_info "Configuring ISO..."
local iso_volid="local:iso/${ISO_FILE}"
local iso_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=${iso_volid},media=cdrom" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$iso_response" | grep -q '"errors"'; then
log_warn "ISO config may have issues"
else
log_info "✓ ISO configured"
fi
# Set boot order
log_info "Setting boot order..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2;scsi0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
log_info "✓ Boot order configured"
# Start VM
log_info "Starting VM..."
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1
log_info "✓ VM $vmid configuration fixed and restarted"
echo ""
}
# VM configurations
declare -A VMS=(
["100"]="cloudflare-tunnel:40"
["101"]="k3s-master:80"
["102"]="git-server:100"
["103"]="observability:200"
)
main() {
echo "========================================="
echo "Fix VM Configuration Warnings"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "Fixing configurations for all VMs..."
echo ""
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name disk_size <<< "${VMS[$vmid]}"
fix_vm_config "$auth" "$vmid" "$name" "$disk_size"
done
log_info "========================================="
log_info "Configuration Fix Complete"
log_info "========================================="
}
main "$@"

View File

@@ -0,0 +1,109 @@
#!/bin/bash
source ~/.bashrc
# Fix VM Creation - Delete failed VMs and recreate them properly
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Delete VM
delete_vm() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_warn "Deleting VM $vmid..."
# Stop VM first if running
curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1
sleep 2
# Delete VM
local delete_response=$(curl -k -s -X DELETE \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid" 2>&1)
if echo "$delete_response" | grep -q '"errors"'; then
log_error "Failed to delete VM $vmid: $delete_response"
return 1
fi
log_info "✓ VM $vmid deleted"
return 0
}
main() {
echo "========================================="
echo "Fix VM Creation - Cleanup and Recreate"
echo "========================================="
echo ""
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Delete failed VMs (100-103)
for vmid in 100 101 102 103; do
delete_vm "$auth" "$vmid" || log_warn "Could not delete VM $vmid (may not exist)"
done
echo ""
log_info "Cleanup complete. Now run: ./scripts/create-vms-from-iso.sh"
}
main "$@"

View File

@@ -0,0 +1,96 @@
#!/bin/bash
source ~/.bashrc
# Manual Steps Guide - Interactive helper for remaining manual steps
# Colors
CYAN='\033[0;36m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
clear
log_header "Manual Steps Guide - Complete Remaining Tasks"
echo ""
echo "This guide will help you complete the remaining manual steps."
echo ""
read -p "Press Enter to continue..."
log_header "Step 1: Verify VM Hardware Configuration"
echo ""
echo "1. Open Proxmox Web UI: https://192.168.1.206:8006"
echo "2. Login with: root@pam / (password from .env)"
echo "3. For each VM (100, 101, 102, 103):"
echo " a. Click on the VM"
echo " b. Go to 'Hardware' tab"
echo " c. Verify/Add:"
echo " - Network Device (should be virtio, bridge=vmbr0)"
echo " - Hard Disk (should exist)"
echo " - CD/DVD Drive (should have Ubuntu ISO)"
echo " d. Go to 'Options' tab"
echo " - Set Boot Order: CD-ROM first"
echo ""
read -p "Press Enter after verifying all VM hardware..."
log_header "Step 2: Install Ubuntu 24.04"
echo ""
echo "For each VM, install Ubuntu:"
echo ""
echo "VM 100 - cloudflare-tunnel (192.168.1.60):"
echo " 1. Open VM → Console"
echo " 2. Ubuntu installer should boot"
echo " 3. During installation, configure:"
echo " - IP: 192.168.1.60/24"
echo " - Gateway: 192.168.1.254"
echo " - DNS: 8.8.8.8"
echo " 4. Create user account (remember for SSH)"
echo ""
read -p "Press Enter after installing Ubuntu on VM 100..."
echo ""
echo "VM 101 - k3s-master (192.168.1.188):"
echo " - IP: 192.168.1.188/24"
echo " - Gateway: 192.168.1.254"
read -p "Press Enter after installing Ubuntu on VM 101..."
echo ""
echo "VM 102 - git-server (192.168.1.121):"
echo " - IP: 192.168.1.121/24"
echo " - Gateway: 192.168.1.254"
read -p "Press Enter after installing Ubuntu on VM 102..."
echo ""
echo "VM 103 - observability (192.168.1.82):"
echo " - IP: 192.168.1.82/24"
echo " - Gateway: 192.168.1.254"
read -p "Press Enter after installing Ubuntu on VM 103..."
log_header "Step 3: Verify Installation"
echo ""
echo "Running verification script..."
./scripts/check-vm-status.sh
echo ""
read -p "Press Enter to continue..."
log_header "Step 4: Automated Service Setup"
echo ""
echo "Running automated setup for all services..."
./scripts/automate-all-setup.sh
echo ""
log_header "Setup Complete!"
echo ""
log_info "All services should now be configured."
echo "Check the output above for any issues."

View File

@@ -0,0 +1,124 @@
#!/bin/bash
source ~/.bashrc
# Set Boot Order via API - Alternative method
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
return 1
fi
echo "$ticket|$csrf"
}
# Set boot order via API
set_boot_order() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Setting boot order for VM $vmid..."
# Try different boot order formats
# Format 1: boot=order=ide2;scsi0
log_info "Trying boot order: ide2;scsi0"
local response1=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2;scsi0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if ! echo "$response1" | grep -q '"errors"'; then
log_info "✓ Boot order set successfully"
return 0
fi
# Format 2: boot=order=ide2
log_info "Trying boot order: ide2"
local response2=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if ! echo "$response2" | grep -q '"errors"'; then
log_info "✓ Boot order set successfully"
return 0
fi
# Format 3: bootdisk=ide2
log_info "Trying bootdisk: ide2"
local response3=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "bootdisk=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if ! echo "$response3" | grep -q '"errors"'; then
log_info "✓ Boot disk set successfully"
return 0
fi
log_info "⚠ API method didn't work. Use Web UI method below."
return 1
}
main() {
echo "========================================="
echo "Set Boot Order via API"
echo "========================================="
echo ""
auth=$(get_ticket)
if [ $? -ne 0 ]; then
echo "Authentication failed"
exit 1
fi
for vmid in 100 101 102 103; do
set_boot_order "$auth" "$vmid"
echo ""
done
echo "If API didn't work, use Web UI method:"
echo " Options tab → Boot Order → Use 'order' field"
}
main "$@"

View File

@@ -0,0 +1,108 @@
#!/bin/bash
source ~/.bashrc
# Complete VM Setup: Template + Install Scripts
# This is the main script that orchestrates the entire process
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.."
main() {
echo "========================================="
echo "Complete VM Setup with Templates & Scripts"
echo "========================================="
echo ""
log_step "This script will:"
echo " 1. Check for Cloud-Init template"
echo " 2. Create VMs from template (if needed)"
echo " 3. Apply install scripts to each VM"
echo ""
read -p "Continue? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Cancelled"
exit 0
fi
# Step 1: Check for template
log_step "Step 1: Checking for Cloud-Init template..."
log_warn "Template check not automated yet"
log_info "Ensure you have created template: ubuntu-24.04-cloudinit"
log_info "See: scripts/create-proxmox-template.sh"
echo ""
read -p "Template ready? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_error "Please create template first"
exit 1
fi
# Step 2: Create VMs from template
log_step "Step 2: Creating VMs from template..."
if [ -f "scripts/create-vms-from-template.sh" ]; then
log_info "Running: scripts/create-vms-from-template.sh"
./scripts/create-vms-from-template.sh || log_warn "VM creation had issues"
else
log_error "Script not found: scripts/create-vms-from-template.sh"
exit 1
fi
echo ""
# Step 3: Wait for VMs to boot
log_step "Step 3: Waiting for VMs to boot..."
log_info "VMs need time to boot and complete Cloud-Init setup"
log_info "This may take 5-10 minutes"
echo ""
read -p "Wait 5 minutes, then press Enter to continue..."
# Step 4: Apply install scripts
log_step "Step 4: Applying install scripts to VMs..."
if [ -f "scripts/apply-install-scripts.sh" ]; then
log_info "Running: scripts/apply-install-scripts.sh"
./scripts/apply-install-scripts.sh || log_warn "Some scripts may have failed"
else
log_error "Script not found: scripts/apply-install-scripts.sh"
exit 1
fi
echo ""
log_info "========================================="
log_info "Setup Complete!"
log_info "========================================="
echo ""
log_info "Next steps:"
echo " 1. Verify services are running on each VM"
echo " 2. Configure Cloudflare Tunnel (VM 100)"
echo " 3. Configure K3s cluster (VM 101)"
echo " 4. Complete Gitea setup (VM 102)"
echo " 5. Configure Grafana dashboards (VM 103)"
}
main "$@"

View File

@@ -0,0 +1,272 @@
#!/bin/bash
source ~/.bashrc
# Create All Service VMs via Proxmox API
# Attempts to create VMs using available templates or provides detailed instructions
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
else
log_error ".env file not found!"
exit 1
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# List available templates
list_templates() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
templates = [v for v in data.get('data', []) if v.get('template') == 1]
if templates:
print('Available Templates:')
for t in templates:
print(f\" - {t.get('name', 'unknown')} (ID: {t.get('vmid', 'N/A')})\")
else:
print('No templates found')
" 2>/dev/null || echo "Could not retrieve templates"
}
# List available ISOs
list_isos() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/storage/local/content")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
isos = [f for f in data.get('data', []) if f.get('content') == 'iso']
if isos:
print('Available ISO Images:')
for iso in isos[:10]:
print(f\" - {iso.get('volid', 'unknown')}\")
else:
print('No ISO images found')
" 2>/dev/null || echo "Could not retrieve ISO images"
}
# Check if VM exists
vm_exists() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/cluster/resources?type=vm")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
vms = [v for v in data.get('data', []) if v.get('type') == 'qemu' and str(v.get('vmid')) == '$vmid']
print('true' if vms else 'false')
" 2>/dev/null || echo "false"
}
# Create VM via API (requires template or ISO)
create_vm_api() {
local auth=$1
local vmid=$2
local name=$3
local cores=$4
local memory=$5
local disk_size=$6
local template_or_iso=$7
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_info "Creating VM $name (ID: $vmid) via API..."
# Check if template exists
if [ "$(vm_exists "$auth" "$template_or_iso")" = "true" ]; then
# Clone from template
log_info "Cloning from template $template_or_iso..."
curl -k -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "newid=$vmid" \
-d "name=$name" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$template_or_iso/clone" 2>/dev/null
# Update VM configuration
curl -k -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "cores=$cores" \
-d "memory=$memory" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>/dev/null
log_info "✓ VM $name created from template"
return 0
else
log_warn "Template/ISO $template_or_iso not found. Cannot create VM via API."
return 1
fi
}
# VM configurations
declare -A VMS=(
["100"]="cloudflare-tunnel:2:4096:40"
["101"]="k3s-master:4:8192:80"
["102"]="git-server:4:8192:100"
["103"]="observability:4:8192:200"
)
main() {
echo "========================================="
echo "Create All Service VMs"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
log_info "Connecting to Proxmox: $PROXMOX_URL"
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "Authentication successful"
echo ""
# Check available resources
log_step "Checking available resources..."
list_templates "$auth"
echo ""
list_isos "$auth"
echo ""
# Check existing VMs
log_step "Checking existing VMs..."
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name cores memory disk <<< "${VMS[$vmid]}"
if [ "$(vm_exists "$auth" "$vmid")" = "true" ]; then
log_warn "VM $name (ID: $vmid) already exists"
else
log_info "VM $name (ID: $vmid) - Ready to create"
fi
done
echo ""
log_warn "VM creation via API requires templates or ISOs."
log_info "Generating Proxmox Web UI creation guide..."
echo ""
# Generate creation instructions
cat > /tmp/vm-creation-instructions.txt <<EOF
========================================
VM Creation Instructions for Proxmox Web UI
========================================
Access: $PROXMOX_URL
Login: $PVE_USERNAME / (password from PVE_ROOT_PASS)
For each VM, follow these steps:
1. Click "Create VM" (top right)
2. Fill in the General tab
3. Select OS (ISO image or template)
4. Configure System, Hard Disk, CPU, Memory, Network
5. Use Cloud-Init for network configuration (if available)
VM Configurations:
EOF
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name cores memory disk <<< "${VMS[$vmid]}"
case $vmid in
100) ip="192.168.1.60" ;;
101) ip="192.168.1.188" ;;
102) ip="192.168.1.121" ;;
103) ip="192.168.1.82" ;;
esac
cat >> /tmp/vm-creation-instructions.txt <<EOF
VM: $name
- VM ID: $vmid
- IP Address: $ip
- CPU: $cores cores
- RAM: ${memory}MB
- Disk: ${disk}GB
- Network: vmbr0
- Gateway: 192.168.1.254
EOF
done
cat /tmp/vm-creation-instructions.txt
echo ""
log_info "Full instructions saved to: /tmp/vm-creation-instructions.txt"
log_info "Also see: CREATE_VMS.md"
}
main "$@"

View File

@@ -0,0 +1,157 @@
#!/bin/bash
source ~/.bashrc
# Create First VM (Cloudflare Tunnel) via Proxmox API
# This script helps create a VM using the Proxmox API
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
else
log_error ".env file not found!"
exit 1
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Get next available VM ID
get_next_vmid() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/cluster/nextid")
echo "$response" | grep -o '"data":"[^"]*' | cut -d'"' -f4
}
# Check if VM exists
vm_exists() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/cluster/resources?type=vm")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
vms = [v for v in data.get('data', []) if v.get('type') == 'qemu' and str(v.get('vmid')) == '$vmid']
print('true' if vms else 'false')
" 2>/dev/null || echo "false"
}
# Main
echo "========================================="
echo "Create Cloudflare Tunnel VM"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
log_info "Connecting to Proxmox: $PROXMOX_URL"
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "Authentication successful"
echo ""
# Check for existing VM
if [ "$(vm_exists "$auth" 100)" = "true" ]; then
log_warn "VM with ID 100 already exists"
read -p "Continue anyway? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 0
fi
fi
# Get next VM ID
next_id=$(get_next_vmid "$auth")
log_info "Next available VM ID: $next_id"
echo ""
log_warn "VM creation via Proxmox API requires:"
log_warn " 1. A VM template (e.g., ubuntu-22.04-template)"
log_warn " 2. Or an ISO image uploaded to Proxmox"
echo ""
log_info "Recommended approach:"
echo " 1. Use Proxmox Web UI to create the first VM"
echo " 2. Convert it to a template for future use"
echo " 3. Then use Terraform or API for additional VMs"
echo ""
log_info "Proxmox Web UI: $PROXMOX_URL"
log_info "See CREATE_VMS.md for step-by-step instructions"
echo ""
log_info "VM Configuration for Cloudflare Tunnel:"
echo " - VM ID: 100"
echo " - Name: cloudflare-tunnel"
echo " - IP: 192.168.1.60"
echo " - CPU: 2 cores"
echo " - RAM: 4096 MB"
echo " - Disk: 40GB"
echo " - OS: Ubuntu 22.04 LTS"
echo ""
log_info "After creating the VM:"
echo " 1. Install Ubuntu 22.04 LTS"
echo " 2. Configure static IP: 192.168.1.60"
echo " 3. Run: sudo bash scripts/setup-cloudflare-tunnel.sh"
echo ""

View File

@@ -0,0 +1,408 @@
#!/bin/bash
source ~/.bashrc
# Create Proxmox Mail Gateway VM via Proxmox API using ISO
# Downloads ISO if needed, uploads to Proxmox, and creates VM automatically
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
else
log_error ".env file not found!"
exit 1
fi
# Configuration
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
STORAGE_POOL="${3:-local}"
# PMG VM Configuration
VMID=105
VM_NAME="proxmox-mail-gateway"
CORES=2
MEMORY=4096
DISK_SIZE="50G"
# ISO Configuration
ISO_FILE="proxmox-mail-gateway_9.0-1.iso"
ISO_URL="https://enterprise.proxmox.com/iso/proxmox-mail-gateway_9.0-1.iso"
ISO_DIR="${4:-./downloads/iso}"
ISO_PATH="${ISO_DIR}/${ISO_FILE}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Download ISO if not present
download_iso() {
if [ -f "$ISO_PATH" ]; then
log_info "ISO already exists locally: $ISO_PATH"
ISO_SIZE=$(du -h "$ISO_PATH" | cut -f1)
log_info "ISO size: $ISO_SIZE"
return 0
fi
log_step "Downloading PMG ISO..."
log_info "URL: $ISO_URL"
log_info "Destination: $ISO_PATH"
log_warn "This may take several minutes depending on network speed..."
# Create ISO directory if it doesn't exist
mkdir -p "$ISO_DIR"
# Download ISO with progress
if command -v wget >/dev/null 2>&1; then
wget --progress=bar:force -O "$ISO_PATH" "$ISO_URL" 2>&1 | grep --line-buffered -oP '\d+%' | while read -r line; do
echo -ne "\r${GREEN}[INFO]${NC} Download progress: $line"
done
echo ""
elif command -v curl >/dev/null 2>&1; then
curl -L --progress-bar -o "$ISO_PATH" "$ISO_URL"
else
log_error "Neither wget nor curl is available. Cannot download ISO."
return 1
fi
if [ ! -f "$ISO_PATH" ]; then
log_error "ISO download failed"
return 1
fi
ISO_SIZE=$(du -h "$ISO_PATH" | cut -f1)
log_info "✓ ISO downloaded successfully: $ISO_SIZE"
return 0
}
# Check if ISO exists locally
check_iso() {
if [ ! -f "$ISO_PATH" ]; then
log_warn "ISO file not found: $ISO_PATH"
log_info "Attempting to download from: $ISO_URL"
if ! download_iso; then
log_error "Failed to download ISO. Please download manually and place it at: $ISO_PATH"
exit 1
fi
else
log_info "Found ISO: $ISO_PATH"
ISO_SIZE=$(du -h "$ISO_PATH" | cut -f1)
log_info "ISO size: $ISO_SIZE"
fi
}
# Check if ISO already exists in Proxmox
iso_exists() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/storage/${STORAGE_POOL}/content")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
isos = [f for f in data.get('data', []) if f.get('content') == 'iso' and '$ISO_FILE' in f.get('volid', '')]
print('true' if isos else 'false')
" 2>/dev/null || echo "false"
}
# Upload ISO to Proxmox
upload_iso() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Uploading ISO to Proxmox..."
log_warn "This may take several minutes depending on ISO size and network speed..."
# Upload ISO using multipart form
local result=$(curl -k -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-F "content=iso" \
-F "filename=@$ISO_PATH" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/storage/${STORAGE_POOL}/upload" 2>&1)
if echo "$result" | grep -q "error"; then
log_error "ISO upload failed: $result"
return 1
fi
log_info "✓ ISO uploaded successfully"
return 0
}
# Check if VM exists
vm_exists() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/cluster/resources?type=vm")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
vms = [v for v in data.get('data', []) if v.get('type') == 'qemu' and str(v.get('vmid')) == '$vmid']
print('true' if vms else 'false')
" 2>/dev/null || echo "false"
}
# Create VM via API
create_vm() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Creating VM: $VM_NAME (ID: $VMID)..."
# First, verify ISO exists in storage
local iso_volid="${STORAGE_POOL}:iso/${ISO_FILE}"
log_info "Using ISO: $iso_volid"
# Strategy: Create VM with minimal config, then add hardware via separate API calls
log_info "Step 1: Creating VM skeleton..."
local create_response=$(curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "vmid=$VMID" \
-d "name=$VM_NAME" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu" 2>&1)
if echo "$create_response" | grep -q '"errors"'; then
log_error "Failed to create VM skeleton:"
echo "$create_response" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d.get('errors', {}), indent=2))" 2>/dev/null || echo "$create_response"
return 1
fi
log_info "✓ VM skeleton created"
sleep 1
# Step 2: Configure basic VM settings
log_info "Step 2: Configuring CPU and memory..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "cores=$CORES" \
-d "memory=$MEMORY" \
-d "ostype=l26" \
-d "agent=1" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" > /dev/null 2>&1
# Step 3: Add disk
log_info "Step 3: Adding disk..."
local disk_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=${STORAGE_POOL}:${DISK_SIZE}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" 2>&1)
if echo "$disk_response" | grep -q '"errors"'; then
log_warn "Disk configuration warning (continuing anyway)"
fi
# Step 4: Add ISO
log_info "Step 4: Adding ISO..."
local iso_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=$iso_volid" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" 2>&1)
if echo "$iso_response" | grep -q '"errors"'; then
log_warn "ISO configuration warning (continuing anyway)"
fi
# Step 5: Add network (DHCP configuration)
log_info "Step 5: Adding network (DHCP)..."
local net_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=model=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" 2>&1)
if echo "$net_response" | grep -q '"errors"'; then
log_warn "Network configuration warning (may need manual configuration)"
fi
# Step 6: Set boot order
log_info "Step 6: Configuring boot order..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" > /dev/null 2>&1
# Step 7: Add tags
log_info "Step 7: Adding tags..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "tags=mail;security;gateway" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" > /dev/null 2>&1
# Verify VM config file was created
sleep 2
local verify_response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/config" 2>&1)
if echo "$verify_response" | grep -q '"errors"'; then
log_error "VM $VM_NAME was not created properly. Config file missing."
log_error "Response: $verify_response"
return 1
fi
log_info "✓ VM $VM_NAME created successfully"
return 0
}
# Start VM
start_vm() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_info "Starting VM $VMID..."
local start_response=$(curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$VMID/status/start")
if echo "$start_response" | grep -q '"error"'; then
log_warn "Failed to start VM $VMID: $start_response"
return 1
fi
log_info "✓ VM $VMID started"
return 0
}
main() {
log_header "Create Proxmox Mail Gateway VM"
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Check/download ISO file
check_iso
echo ""
# Authenticate
log_step "Authenticating with Proxmox..."
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "✓ Authentication successful"
echo ""
# Check if VM already exists
if [ "$(vm_exists "$auth" "$VMID")" = "true" ]; then
log_warn "VM $VM_NAME (ID: $VMID) already exists. Skipping creation..."
log_info "To recreate, delete the VM first via Proxmox Web UI or API"
exit 0
fi
# Check if ISO already uploaded
if [ "$(iso_exists "$auth")" = "true" ]; then
log_info "✓ ISO already exists in Proxmox storage"
else
# Upload ISO
if ! upload_iso "$auth"; then
log_error "Failed to upload ISO"
exit 1
fi
fi
echo ""
# Create VM
log_step "Creating VM..."
echo ""
if create_vm "$auth"; then
# Start VM
start_vm "$auth"
echo ""
log_header "VM Creation Complete"
echo ""
log_info "Proxmox Mail Gateway VM has been created and started!"
echo ""
log_info "VM Details:"
echo " - Name: $VM_NAME"
echo " - ID: $VMID"
echo " - Cores: $CORES"
echo " - Memory: ${MEMORY}MB"
echo " - Disk: $DISK_SIZE"
echo " - Network: DHCP (vmbr0)"
echo ""
log_info "Next steps:"
echo " 1. Access VM console via Proxmox Web UI: $PROXMOX_URL"
echo " 2. Complete Proxmox Mail Gateway installation via console"
echo " 3. Configure PMG after installation completes"
echo ""
else
log_error "Failed to create VM $VM_NAME"
exit 1
fi
}
main "$@"

View File

@@ -0,0 +1,94 @@
#!/bin/bash
source ~/.bashrc
# Create Proxmox Cloud-Init Template from Ubuntu Cloud Image
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="${PROXMOX_URL:-https://192.168.1.206:8006}"
PROXMOX_NODE="${PROXMOX_NODE:-pve}"
STORAGE="${STORAGE:-local-lvm}"
CLOUD_IMAGE="${1:-./downloads/ubuntu-24.04-server-cloudimg-amd64.img}"
TEMPLATE_NAME="${2:-ubuntu-24.04-cloudinit}"
TEMPLATE_ID="${3:-9000}"
main() {
echo "========================================="
echo "Create Proxmox Cloud-Init Template"
echo "========================================="
echo ""
if [ ! -f "$CLOUD_IMAGE" ]; then
log_error "Cloud image not found: $CLOUD_IMAGE"
log_info "Download it first: ./scripts/download-ubuntu-cloud-image.sh"
exit 1
fi
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
log_step "Creating template from: $CLOUD_IMAGE"
log_info "Template name: $TEMPLATE_NAME"
log_info "Template ID: $TEMPLATE_ID"
log_info "Storage: $STORAGE"
echo ""
log_info "This script provides instructions for manual template creation."
log_info "Proxmox Web UI method is more reliable for template creation."
echo ""
log_step "Manual Steps (Recommended):"
echo ""
echo "1. Upload Cloud Image to Proxmox:"
echo " - Proxmox Web UI → Datacenter → $PROXMOX_NODE → Storage"
echo " - Select storage → Content → Upload"
echo " - Upload: $CLOUD_IMAGE"
echo ""
echo "2. Create VM from Cloud Image:"
echo " - Create VM (ID: $TEMPLATE_ID)"
echo " - Import disk from uploaded image"
echo " - Configure Cloud-Init settings"
echo ""
echo "3. Convert to Template:"
echo " - Right-click VM → Convert to Template"
echo ""
echo "4. Use Template:"
echo " - Clone template to create new VMs"
echo " - Configure Cloud-Init on clone"
echo ""
log_info "See: docs/proxmox-ubuntu-images.md for detailed instructions"
}
main "$@"

View File

@@ -0,0 +1,90 @@
#!/bin/bash
source ~/.bashrc
# Quick Template Creation Guide
# This provides step-by-step instructions for creating the template
set -e
cat <<'EOF'
========================================
Ubuntu Cloud-Init Template Creation
========================================
This guide will help you create a Ubuntu Cloud-Init template in Proxmox.
STEP 1: Download Ubuntu Cloud Image
------------------------------------
Run this command to download the image:
wget https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img
Or use the script:
./scripts/download-ubuntu-cloud-image.sh 24.04
STEP 2: Upload to Proxmox
--------------------------
1. Open Proxmox Web UI: https://192.168.1.206:8006
2. Go to: Datacenter → pve → Storage → local
3. Click "Upload" button
4. Select the downloaded .img file
5. Wait for upload to complete (may take a few minutes)
STEP 3: Create VM from Image
------------------------------
1. Click "Create VM" (top right)
2. General:
- VM ID: 9000
- Name: ubuntu-24.04-cloudinit
- Click "Next"
3. OS:
- Select "Do not use any media"
- Click "Next"
4. System:
- Keep defaults
- Click "Next"
5. Disks:
- Delete the default disk
- Click "Add" → "Hard Disk"
- Storage: local
- Import from: Select the uploaded .img file
- Disk size: 20GB (minimum)
- Click "Add"
- Click "Next"
6. CPU:
- Cores: 2
- Click "Next"
7. Memory:
- Memory: 2048 MB
- Click "Next"
8. Network:
- Bridge: vmbr0
- Model: VirtIO
- Click "Next"
9. Confirm:
- Review settings
- Click "Finish"
STEP 4: Configure Cloud-Init
-----------------------------
1. Select the VM (9000)
2. Go to "Options" tab
3. Click "Cloud-Init"
4. Configure:
- User: ubuntu
- Password: (leave empty, use SSH keys)
- SSH Public Keys: Paste your public key
- Click "OK"
STEP 5: Convert to Template
----------------------------
1. Right-click on VM 9000
2. Select "Convert to Template"
3. Confirm
Done! Template is ready.
Now you can run:
./scripts/recreate-vms-from-template.sh
EOF

View File

@@ -0,0 +1,221 @@
#!/bin/bash
source ~/.bashrc
# Create Ubuntu Cloud-Init Template via Proxmox API
# This attempts to automate template creation as much as possible
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
STORAGE="${STORAGE:-local}"
TEMPLATE_ID=9000
TEMPLATE_NAME="ubuntu-24.04-cloudinit"
CLOUD_IMAGE="ubuntu-24.04-server-cloudimg-amd64.img"
IMAGE_PATH="./downloads/${CLOUD_IMAGE}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Check if image is uploaded
check_image_uploaded() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/storage/$STORAGE/content")
if echo "$response" | grep -q "$CLOUD_IMAGE"; then
return 0
else
return 1
fi
}
# Upload image to Proxmox
upload_image() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Uploading cloud image to Proxmox..."
if [ ! -f "$IMAGE_PATH" ]; then
log_error "Cloud image not found: $IMAGE_PATH"
return 1
fi
log_warn "Image upload via API is complex. Please upload manually:"
log_info "1. Proxmox Web UI → Storage → $STORAGE → Upload"
log_info "2. Select file: $IMAGE_PATH"
log_info "3. Wait for upload to complete"
echo ""
read -p "Press Enter after image is uploaded..."
if check_image_uploaded "$auth"; then
log_info "✓ Image uploaded"
return 0
else
log_warn "Image upload not detected. Please verify manually."
return 1
fi
}
# Create VM from uploaded image
create_vm_from_image() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Creating VM $TEMPLATE_ID from cloud image..."
# Check if VM already exists
local existing=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_ID/config" 2>&1)
if echo "$existing" | grep -q '"name"'; then
log_warn "VM $TEMPLATE_ID already exists"
read -p "Delete and recreate? (y/N): " confirm
if [ "$confirm" != "y" ]; then
return 0
fi
# Delete existing VM
curl -k -s -X DELETE \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_ID" > /dev/null 2>&1
sleep 2
fi
log_warn "VM creation from image requires manual steps in Proxmox Web UI:"
echo ""
log_info "1. Create VM:"
log_info " • Click 'Create VM'"
log_info " • VM ID: $TEMPLATE_ID"
log_info " • Name: $TEMPLATE_NAME"
log_info " • OS: 'Do not use any media'"
log_info " • Delete default disk"
log_info " • Add disk: Import from $CLOUD_IMAGE"
log_info " • CPU: 2, Memory: 2048MB"
log_info " • Network: vmbr0, VirtIO"
echo ""
log_info "2. Configure Cloud-Init:"
log_info " • Options → Cloud-Init"
log_info " • User: ubuntu"
log_info " • SSH Public Key: $(cat ~/.ssh/id_rsa.pub 2>/dev/null | head -1 || echo 'Your SSH key')"
echo ""
log_info "3. Convert to Template:"
log_info " • Right-click VM → Convert to Template"
echo ""
read -p "Press Enter after template is created..."
# Verify template exists
local template_check=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_ID/config" 2>&1)
if echo "$template_check" | grep -q '"template".*1'; then
log_info "✓ Template created successfully"
return 0
else
log_warn "Template verification failed. Please check manually."
return 1
fi
}
main() {
log_header "Create Ubuntu Cloud-Init Template"
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
if [ ! -f "$IMAGE_PATH" ]; then
log_error "Cloud image not found: $IMAGE_PATH"
log_info "Download it first: ./scripts/download-ubuntu-cloud-image.sh 24.04"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Step 1: Upload image
if ! check_image_uploaded "$auth"; then
upload_image "$auth"
else
log_info "✓ Image already uploaded"
fi
# Step 2: Create VM and convert to template
create_vm_from_image "$auth"
log_header "Template Creation Complete!"
echo ""
log_info "Template $TEMPLATE_ID is ready"
log_info "You can now run: ./scripts/recreate-vms-from-template.sh"
}
main "$@"

View File

@@ -0,0 +1,722 @@
#!/bin/bash
source ~/.bashrc
# Create Proxmox VM from QCOW2/RAW Image - Comprehensive Automation Script
#
# This script automates the complete workflow for creating a VM from any disk image
# in Proxmox VE using the qm command-line interface.
#
# Reference: https://pve.proxmox.com/pve-docs/qm.1.html
#
# Usage:
# ./scripts/create-vm-from-image.sh --vmid 9000 --name "ubuntu-24.04" \
# --image /path/to/image.img --storage local-lvm
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Default values
VMID=""
VMNAME=""
IMAGE=""
STORAGE="local-lvm"
MEMORY=4096
CORES=2
BRIDGE="vmbr0"
VLAN_TAG=""
ENABLE_CLOUD_INIT=false
ENABLE_UEFI=false
ENABLE_TEMPLATE=false
ENABLE_SERIAL=false
CIUSER=""
CIPASSWORD=""
SSHKEY=""
IPCONFIG=""
NAMESERVER=""
SEARCHDOMAIN=""
CPU_TYPE="host"
ENABLE_AGENT=true
IOTHREAD=true
CACHE_MODE="none"
ENABLE_DISCARD=false
BALLOON=0
DESCRIPTION=""
TAGS=""
NODE=""
DRY_RUN=false
# Load environment variables from .env if available
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
--vmid)
VMID="$2"
shift 2
;;
--name)
VMNAME="$2"
shift 2
;;
--image)
IMAGE="$2"
shift 2
;;
--storage)
STORAGE="$2"
shift 2
;;
--memory)
MEMORY="$2"
shift 2
;;
--cores)
CORES="$2"
shift 2
;;
--bridge)
BRIDGE="$2"
shift 2
;;
--vlan)
VLAN_TAG="$2"
shift 2
;;
--cloud-init)
ENABLE_CLOUD_INIT=true
shift
;;
--uefi)
ENABLE_UEFI=true
shift
;;
--template)
ENABLE_TEMPLATE=true
shift
;;
--serial)
ENABLE_SERIAL=true
shift
;;
--ciuser)
CIUSER="$2"
shift 2
;;
--cipassword)
CIPASSWORD="$2"
shift 2
;;
--sshkey)
SSHKEY="$2"
shift 2
;;
--sshkey-file)
if [ -f "$2" ]; then
SSHKEY="$(cat "$2")"
else
log_error "SSH key file not found: $2"
exit 1
fi
shift 2
;;
--ipconfig)
IPCONFIG="$2"
shift 2
;;
--nameserver)
NAMESERVER="$2"
shift 2
;;
--searchdomain)
SEARCHDOMAIN="$2"
shift 2
;;
--cpu)
CPU_TYPE="$2"
shift 2
;;
--no-agent)
ENABLE_AGENT=false
shift
;;
--no-iothread)
IOTHREAD=false
shift
;;
--cache)
CACHE_MODE="$2"
shift 2
;;
--discard)
ENABLE_DISCARD=true
shift
;;
--balloon)
BALLOON="$2"
shift 2
;;
--description)
DESCRIPTION="$2"
shift 2
;;
--tags)
TAGS="$2"
shift 2
;;
--node)
NODE="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--help)
show_help
exit 0
;;
*)
log_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
}
# Show help message
show_help() {
cat << EOF
Create Proxmox VM from QCOW2/RAW Image
Usage: $0 [OPTIONS]
Required Options:
--vmid ID VM ID (e.g., 9000)
--name NAME VM name (e.g., "ubuntu-24.04-cloudinit")
--image PATH Full path to image file
Optional Options:
--storage STORAGE Storage pool (default: local-lvm)
--memory MB Memory in MB (default: 4096)
--cores NUM CPU cores (default: 2)
--bridge BRIDGE Network bridge (default: vmbr0)
--vlan TAG VLAN tag number
Cloud-Init Options:
--cloud-init Enable Cloud-Init support
--ciuser USER Cloud-Init username
--cipassword PASS Cloud-Init password (not recommended)
--sshkey KEY SSH public key (or use --sshkey-file)
--sshkey-file FILE Read SSH key from file
--ipconfig CONFIG IP configuration (e.g., "ip=192.168.1.100/24,gw=192.168.1.1")
--nameserver DNS DNS servers (space-separated)
--searchdomain DOMAIN Search domains
VM Configuration:
--uefi Enable UEFI/OVMF (recommended for modern images)
--cpu TYPE CPU type (default: host, options: host, kvm64, etc.)
--no-agent Disable QEMU Guest Agent
--no-iothread Disable IO thread
--cache MODE Disk cache mode (none, writeback, writethrough)
--discard Enable discard (for thin provisioning)
--balloon MB Memory balloon size in MB
Other Options:
--template Convert to template after creation
--serial Enable serial console
--description TEXT VM description
--tags TAGS Tags (comma-separated, e.g., "dev,web")
--node NODE Target Proxmox node
--dry-run Show commands without executing
--help Show this help message
Examples:
# Basic VM creation
$0 --vmid 9000 --name "ubuntu-24.04" \\
--image /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img
# Full cloud-init VM
$0 --vmid 9000 --name "ubuntu-24.04-cloudinit" \\
--image /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img \\
--storage local-lvm --memory 4096 --cores 2 \\
--cloud-init --uefi --serial \\
--ciuser ubuntu --sshkey-file ~/.ssh/id_rsa.pub \\
--ipconfig "ip=192.168.1.100/24,gw=192.168.1.1"
# Create and convert to template
$0 --vmid 9000 --name "ubuntu-template" \\
--image /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img \\
--cloud-init --uefi --template \\
--ciuser ubuntu --sshkey-file ~/.ssh/id_rsa.pub
EOF
}
# Validate required arguments
validate_args() {
if [ -z "$VMID" ]; then
log_error "VMID is required. Use --vmid option."
exit 1
fi
if [ -z "$VMNAME" ]; then
log_error "VM name is required. Use --name option."
exit 1
fi
if [ -z "$IMAGE" ]; then
log_error "Image path is required. Use --image option."
exit 1
fi
if [ ! -f "$IMAGE" ]; then
log_error "Image file not found: $IMAGE"
exit 1
fi
# Validate VMID is numeric
if ! [[ "$VMID" =~ ^[0-9]+$ ]]; then
log_error "VMID must be numeric: $VMID"
exit 1
fi
# Check if VMID already exists
if qm list | grep -q "^\s*$VMID\s"; then
log_error "VM with ID $VMID already exists"
exit 1
fi
# Validate storage exists
if ! pvesm status | grep -q "^$STORAGE\s"; then
log_warn "Storage '$STORAGE' not found in pvesm status"
log_info "Available storage:"
pvesm status
log_warn "Continuing anyway..."
fi
}
# Validate image
validate_image() {
log_step "Validating image: $IMAGE"
# Check image format
if ! command -v qemu-img &> /dev/null; then
log_warn "qemu-img not found, skipping image validation"
return
fi
local image_info
image_info=$(qemu-img info "$IMAGE" 2>&1)
if [ $? -ne 0 ]; then
log_error "Failed to read image: $IMAGE"
log_error "$image_info"
exit 1
fi
log_info "Image format: $(echo "$image_info" | grep "file format" | awk '{print $3}')"
log_info "Virtual size: $(echo "$image_info" | grep "virtual size" | awk -F'[()]' '{print $2}')"
}
# Create VM shell
create_vm_shell() {
log_step "Creating VM shell (ID: $VMID, Name: $VMNAME)"
local cmd="qm create $VMID --name \"$VMNAME\" --memory $MEMORY --cores $CORES"
# Add node if specified
if [ -n "$NODE" ]; then
cmd="$cmd --target $NODE"
fi
# Configure network
if [ -n "$VLAN_TAG" ]; then
cmd="$cmd --net0 virtio,bridge=$BRIDGE,tag=$VLAN_TAG"
else
cmd="$cmd --net0 virtio,bridge=$BRIDGE"
fi
# Configure CPU
cmd="$cmd --cpu $CPU_TYPE"
# Enable agent
if [ "$ENABLE_AGENT" = true ]; then
cmd="$cmd --agent 1"
fi
# Add description if provided
if [ -n "$DESCRIPTION" ]; then
cmd="$cmd --description \"$DESCRIPTION\""
fi
# Add tags if provided
if [ -n "$TAGS" ]; then
cmd="$cmd --tags $TAGS"
fi
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ VM shell created"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
}
# Import disk
import_disk() {
log_step "Importing disk from image: $IMAGE"
local cmd="qm importdisk $VMID \"$IMAGE\" $STORAGE"
log_info "Command: $cmd"
log_info "This may take several minutes depending on image size..."
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ Disk imported"
# Get the volume name (usually vm-<VMID>-disk-0)
local volume_name="vm-${VMID}-disk-0"
log_info "Imported volume: $volume_name"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
}
# Attach disk
attach_disk() {
log_step "Attaching imported disk"
local volume_name="vm-${VMID}-disk-0"
local cmd="qm set $VMID --scsihw virtio-scsi-pci --scsi0 ${STORAGE}:${volume_name}"
# Add IO thread if enabled
if [ "$IOTHREAD" = true ]; then
cmd="$cmd --iothread 1"
fi
# Add cache mode
cmd="$cmd --cache $CACHE_MODE"
# Add discard if enabled
if [ "$ENABLE_DISCARD" = true ]; then
cmd="$cmd --discard on"
fi
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ Disk attached"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
}
# Configure boot
configure_boot() {
log_step "Configuring boot settings"
local cmd="qm set $VMID --boot order=scsi0"
# Configure BIOS/UEFI
if [ "$ENABLE_UEFI" = true ]; then
cmd="$cmd --bios ovmf --efidisk0 ${STORAGE}:1,format=raw"
log_info "UEFI/OVMF enabled"
else
cmd="$cmd --bios seabios"
log_info "BIOS (SeaBIOS) enabled"
fi
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ Boot configured"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
}
# Configure Cloud-Init
configure_cloud_init() {
log_step "Configuring Cloud-Init"
# Add Cloud-Init drive
local cmd="qm set $VMID --ide2 ${STORAGE}:cloudinit"
# Enable serial console if requested
if [ "$ENABLE_SERIAL" = true ] || [ "$ENABLE_CLOUD_INIT" = true ]; then
cmd="$cmd --serial0 socket --vga serial0"
fi
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
# Configure Cloud-Init user
if [ -n "$CIUSER" ]; then
cmd="qm set $VMID --ciuser $CIUSER"
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
# Configure password (if provided, but not recommended)
if [ -n "$CIPASSWORD" ]; then
cmd="qm set $VMID --cipassword \"$CIPASSWORD\""
log_warn "Setting password via Cloud-Init (not recommended, use SSH keys instead)"
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
# Configure SSH key
if [ -n "$SSHKEY" ]; then
cmd="qm set $VMID --sshkey \"$SSHKEY\""
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ SSH key configured"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
# Configure IP
if [ -n "$IPCONFIG" ]; then
cmd="qm set $VMID --ipconfig0 $IPCONFIG"
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
# Configure DNS
if [ -n "$NAMESERVER" ]; then
cmd="qm set $VMID --nameserver \"$NAMESERVER\""
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
# Configure search domain
if [ -n "$SEARCHDOMAIN" ]; then
cmd="qm set $VMID --searchdomain \"$SEARCHDOMAIN\""
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
if [ "$DRY_RUN" = false ]; then
log_info "✓ Cloud-Init configured"
fi
}
# Configure memory balloon
configure_balloon() {
if [ "$BALLOON" -gt 0 ]; then
log_step "Configuring memory balloon: ${BALLOON}MB"
local cmd="qm set $VMID --balloon $BALLOON"
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ Memory balloon configured"
else
log_info "[DRY RUN] Would execute: $cmd"
fi
fi
}
# Start VM
start_vm() {
log_step "Starting VM"
local cmd="qm start $VMID"
log_info "Command: $cmd"
if [ "$DRY_RUN" = false ]; then
eval "$cmd"
log_info "✓ VM started"
# Show status
sleep 2
qm status $VMID
else
log_info "[DRY RUN] Would execute: $cmd"
fi
}
# Convert to template
convert_to_template() {
if [ "$ENABLE_TEMPLATE" = false ]; then
return
fi
log_step "Converting VM to template"
log_warn "VM must be shut down before converting to template"
if [ "$DRY_RUN" = false ]; then
# Check if VM is running
local status
status=$(qm status $VMID 2>&1 | grep "status:" | awk '{print $2}')
if [ "$status" = "running" ]; then
log_info "VM is running. Shutting down..."
qm shutdown $VMID
log_info "Waiting for shutdown (this may take a minute)..."
local max_wait=60
local waited=0
while [ $waited -lt $max_wait ]; do
status=$(qm status $VMID 2>&1 | grep "status:" | awk '{print $2}')
if [ "$status" != "running" ]; then
break
fi
sleep 2
waited=$((waited + 2))
echo -n "."
done
echo ""
fi
# Convert to template
qm template $VMID
log_info "✓ VM converted to template"
else
log_info "[DRY RUN] Would execute: qm shutdown $VMID && qm template $VMID"
fi
}
# Main function
main() {
echo "========================================="
echo "Create Proxmox VM from Image"
echo "========================================="
echo ""
parse_args "$@"
if [ "$DRY_RUN" = true ]; then
log_warn "DRY RUN MODE - No changes will be made"
echo ""
fi
validate_args
validate_image
echo ""
log_info "VM Configuration:"
log_info " VMID: $VMID"
log_info " Name: $VMNAME"
log_info " Image: $IMAGE"
log_info " Storage: $STORAGE"
log_info " Memory: ${MEMORY}MB"
log_info " Cores: $CORES"
log_info " Bridge: $BRIDGE"
[ -n "$VLAN_TAG" ] && log_info " VLAN: $VLAN_TAG"
[ "$ENABLE_CLOUD_INIT" = true ] && log_info " Cloud-Init: Enabled"
[ "$ENABLE_UEFI" = true ] && log_info " UEFI: Enabled"
[ "$ENABLE_TEMPLATE" = true ] && log_info " Convert to Template: Yes"
echo ""
if [ "$DRY_RUN" = false ]; then
read -p "Continue with VM creation? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Aborted by user"
exit 0
fi
echo ""
fi
create_vm_shell
import_disk
attach_disk
configure_boot
if [ "$ENABLE_CLOUD_INIT" = true ]; then
configure_cloud_init
fi
configure_balloon
if [ "$ENABLE_TEMPLATE" = false ]; then
start_vm
else
log_info "Skipping VM start (will be converted to template)"
fi
convert_to_template
echo ""
log_info "========================================="
log_info "VM Creation Complete!"
log_info "========================================="
if [ "$ENABLE_TEMPLATE" = false ] && [ "$DRY_RUN" = false ]; then
echo ""
log_info "VM Status:"
qm status $VMID
echo ""
log_info "View VM console: qm terminal $VMID"
log_info "View VM config: qm config $VMID"
fi
}
# Run main function
main "$@"

View File

@@ -0,0 +1,519 @@
#!/bin/bash
source ~/.bashrc
# Create Proxmox Cloud-Init Template with Best Practices
#
# This script creates an optimized cloud-init template for Proxmox VE
# following best practices for template management and cloud-init configuration.
#
# Reference: https://pve.proxmox.com/pve-docs/qm.1.html
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m'
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Default values
VMID=""
TEMPLATE_NAME=""
IMAGE=""
STORAGE="local-lvm"
MEMORY=2048
CORES=2
BRIDGE="vmbr0"
CIUSER="ubuntu"
SSHKEY=""
SSHKEY_FILE=""
IPCONFIG="ip=dhcp"
NAMESERVER=""
SEARCHDOMAIN=""
DESCRIPTION=""
TAGS="template,cloud-init"
NODE=""
SKIP_VERIFICATION=false
OPTIMIZE_TEMPLATE=true
# Load environment variables from .env if available
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
--vmid)
VMID="$2"
shift 2
;;
--name)
TEMPLATE_NAME="$2"
shift 2
;;
--image)
IMAGE="$2"
shift 2
;;
--storage)
STORAGE="$2"
shift 2
;;
--memory)
MEMORY="$2"
shift 2
;;
--cores)
CORES="$2"
shift 2
;;
--bridge)
BRIDGE="$2"
shift 2
;;
--ciuser)
CIUSER="$2"
shift 2
;;
--sshkey)
SSHKEY="$2"
shift 2
;;
--sshkey-file)
SSHKEY_FILE="$2"
shift 2
;;
--ipconfig)
IPCONFIG="$2"
shift 2
;;
--nameserver)
NAMESERVER="$2"
shift 2
;;
--searchdomain)
SEARCHDOMAIN="$2"
shift 2
;;
--description)
DESCRIPTION="$2"
shift 2
;;
--tags)
TAGS="$2"
shift 2
;;
--node)
NODE="$2"
shift 2
;;
--skip-verification)
SKIP_VERIFICATION=true
shift
;;
--no-optimize)
OPTIMIZE_TEMPLATE=false
shift
;;
--help)
show_help
exit 0
;;
*)
log_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
}
# Show help message
show_help() {
cat << EOF
Create Proxmox Cloud-Init Template with Best Practices
Usage: $0 [OPTIONS]
Required Options:
--vmid ID VM ID (e.g., 9000)
--name NAME Template name (e.g., "ubuntu-24.04-cloudinit")
--image PATH Full path to cloud image file
Optional Options:
--storage STORAGE Storage pool (default: local-lvm)
--memory MB Memory in MB (default: 2048, minimal for template)
--cores NUM CPU cores (default: 2)
--bridge BRIDGE Network bridge (default: vmbr0)
Cloud-Init Configuration:
--ciuser USER Cloud-Init username (default: ubuntu)
--sshkey KEY SSH public key (or use --sshkey-file)
--sshkey-file FILE Read SSH key from file
--ipconfig CONFIG IP configuration (default: ip=dhcp)
--nameserver DNS DNS servers (space-separated)
--searchdomain DOMAIN Search domains
Template Options:
--description TEXT Template description
--tags TAGS Tags (comma-separated, default: "template,cloud-init")
--node NODE Target Proxmox node
--skip-verification Skip template verification after creation
--no-optimize Skip template optimization steps
Examples:
# Create template from Ubuntu cloud image
$0 --vmid 9000 --name "ubuntu-24.04-cloudinit" \\
--image /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img \\
--sshkey-file ~/.ssh/id_rsa.pub
# Create template with custom configuration
$0 --vmid 9000 --name "ubuntu-24.04-cloudinit" \\
--image /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img \\
--storage local-lvm --memory 2048 --cores 2 \\
--ciuser ubuntu --sshkey-file ~/.ssh/id_rsa.pub \\
--description "Ubuntu 24.04 LTS Cloud-Init Template"
EOF
}
# Validate required arguments
validate_args() {
if [ -z "$VMID" ]; then
log_error "VMID is required. Use --vmid option."
exit 1
fi
if [ -z "$TEMPLATE_NAME" ]; then
log_error "Template name is required. Use --name option."
exit 1
fi
if [ -z "$IMAGE" ]; then
log_error "Image path is required. Use --image option."
exit 1
fi
if [ ! -f "$IMAGE" ]; then
log_error "Image file not found: $IMAGE"
exit 1
fi
# Validate VMID is numeric
if ! [[ "$VMID" =~ ^[0-9]+$ ]]; then
log_error "VMID must be numeric: $VMID"
exit 1
fi
# Check if VMID already exists
if qm list | grep -q "^\s*$VMID\s"; then
log_error "VM with ID $VMID already exists"
exit 1
fi
# Load SSH key from file if specified
if [ -n "$SSHKEY_FILE" ]; then
if [ ! -f "$SSHKEY_FILE" ]; then
log_error "SSH key file not found: $SSHKEY_FILE"
exit 1
fi
SSHKEY="$(cat "$SSHKEY_FILE")"
log_info "Loaded SSH key from: $SSHKEY_FILE"
fi
# Validate SSH key format if provided
if [ -n "$SSHKEY" ]; then
if ! echo "$SSHKEY" | grep -qE "^ssh-(rsa|ed25519|ecdsa)"; then
log_warn "SSH key format may be invalid (should start with ssh-rsa, ssh-ed25519, or ecdsa)"
fi
fi
}
# Validate template after creation
verify_template() {
log_step "Verifying template configuration"
local config
config=$(qm config $VMID 2>&1)
if [ $? -ne 0 ]; then
log_error "Failed to read template configuration"
return 1
fi
local errors=0
# Check Cloud-Init is configured
if ! echo "$config" | grep -q "ide2.*cloudinit"; then
log_warn "Cloud-Init drive not found in template"
errors=$((errors + 1))
fi
# Check serial console is enabled
if ! echo "$config" | grep -q "serial0.*socket"; then
log_warn "Serial console not enabled (recommended for cloud-init)"
errors=$((errors + 1))
fi
# Check SSH key is configured
if [ -n "$SSHKEY" ]; then
if ! echo "$config" | grep -q "sshkey"; then
log_warn "SSH key not found in template configuration"
errors=$((errors + 1))
fi
fi
# Check UEFI is enabled
if ! echo "$config" | grep -q "bios.*ovmf"; then
log_warn "UEFI not enabled (recommended for modern images)"
fi
if [ $errors -eq 0 ]; then
log_info "✓ Template configuration verified"
return 0
else
log_warn "Template has $errors configuration warnings"
return 1
fi
}
# Clone template for testing
test_template_clone() {
if [ "$SKIP_VERIFICATION" = true ]; then
return
fi
log_step "Testing template by creating a temporary clone"
local test_vmid=$((VMID + 1000)) # Use a different VMID range
local test_name="${TEMPLATE_NAME}-test-$$"
# Find available VMID
while qm list | grep -q "^\s*$test_vmid\s"; do
test_vmid=$((test_vmid + 1))
done
log_info "Creating test clone: VMID $test_vmid"
# Create linked clone
if ! qm clone $VMID $test_vmid --name "$test_name" > /dev/null 2>&1; then
log_error "Failed to create test clone"
return 1
fi
log_info "✓ Test clone created successfully (VMID: $test_vmid)"
# Clean up test clone
read -p "Delete test clone $test_vmid? (Y/n): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
log_info "Deleting test clone..."
qm destroy $test_vmid --purge
log_info "✓ Test clone deleted"
else
log_info "Test clone preserved. Manual cleanup required: qm destroy $test_vmid --purge"
fi
return 0
}
# Create template using the main script
create_template() {
log_step "Creating template using create-vm-from-image.sh"
# Build command
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local create_script="${script_dir}/create-vm-from-image.sh"
if [ ! -f "$create_script" ]; then
log_error "create-vm-from-image.sh not found at: $create_script"
exit 1
fi
local cmd="$create_script"
cmd="$cmd --vmid $VMID"
cmd="$cmd --name \"$TEMPLATE_NAME\""
cmd="$cmd --image \"$IMAGE\""
cmd="$cmd --storage $STORAGE"
cmd="$cmd --memory $MEMORY"
cmd="$cmd --cores $CORES"
cmd="$cmd --bridge $BRIDGE"
cmd="$cmd --cloud-init"
cmd="$cmd --uefi"
cmd="$cmd --serial"
cmd="$cmd --template"
cmd="$cmd --cpu host"
cmd="$cmd --cache none"
cmd="$cmd --discard"
# Add node if specified
if [ -n "$NODE" ]; then
cmd="$cmd --node $NODE"
fi
# Add Cloud-Init configuration
if [ -n "$CIUSER" ]; then
cmd="$cmd --ciuser $CIUSER"
fi
if [ -n "$SSHKEY" ]; then
cmd="$cmd --sshkey \"$SSHKEY\""
fi
if [ -n "$IPCONFIG" ]; then
cmd="$cmd --ipconfig \"$IPCONFIG\""
fi
if [ -n "$NAMESERVER" ]; then
cmd="$cmd --nameserver \"$NAMESERVER\""
fi
if [ -n "$SEARCHDOMAIN" ]; then
cmd="$cmd --searchdomain \"$SEARCHDOMAIN\""
fi
if [ -n "$DESCRIPTION" ]; then
cmd="$cmd --description \"$DESCRIPTION\""
fi
if [ -n "$TAGS" ]; then
cmd="$cmd --tags \"$TAGS\""
fi
log_info "Executing: $cmd"
echo ""
# Execute the main script
eval "$cmd"
if [ $? -ne 0 ]; then
log_error "Failed to create template"
exit 1
fi
}
# Add template metadata
add_template_metadata() {
log_step "Adding template metadata"
local metadata_desc
if [ -n "$DESCRIPTION" ]; then
metadata_desc="$DESCRIPTION"
else
metadata_desc="Cloud-Init Template - Created $(date +%Y-%m-%d)"
fi
# Update description
qm set $VMID --description "$metadata_desc"
# Ensure tags include template
if [[ ! "$TAGS" =~ template ]]; then
TAGS="template,$TAGS"
fi
# Update tags
qm set $VMID --tags "$TAGS"
log_info "✓ Template metadata added"
}
# Main function
main() {
echo "========================================="
echo "Create Proxmox Cloud-Init Template"
echo "========================================="
echo ""
parse_args "$@"
validate_args
echo ""
log_info "Template Configuration:"
log_info " VMID: $VMID"
log_info " Name: $TEMPLATE_NAME"
log_info " Image: $IMAGE"
log_info " Storage: $STORAGE"
log_info " Memory: ${MEMORY}MB (template minimal)"
log_info " Cores: $CORES"
log_info " Bridge: $BRIDGE"
log_info " Cloud-Init User: $CIUSER"
[ -n "$SSHKEY" ] && log_info " SSH Key: Configured"
[ -n "$DESCRIPTION" ] && log_info " Description: $DESCRIPTION"
[ -n "$TAGS" ] && log_info " Tags: $TAGS"
echo ""
read -p "Continue with template creation? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Aborted by user"
exit 0
fi
echo ""
# Create template
create_template
# Add metadata
add_template_metadata
# Verify template
if [ "$SKIP_VERIFICATION" = false ]; then
echo ""
verify_template
fi
# Test clone if verification enabled
if [ "$SKIP_VERIFICATION" = false ]; then
echo ""
read -p "Test template by creating a temporary clone? (Y/n): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
test_template_clone
fi
fi
echo ""
log_info "========================================="
log_info "Template Creation Complete!"
log_info "========================================="
echo ""
log_info "Template Details:"
qm config $VMID | head -20
echo ""
log_info "Clone template with:"
log_info " qm clone $VMID <new-vmid> --name \"<name>\""
echo ""
log_info "Full clone:"
log_info " qm clone $VMID <new-vmid> --full --name \"<name>\""
echo ""
log_info "After cloning, configure Cloud-Init:"
log_info " qm set <new-vmid> --ciuser $CIUSER"
log_info " qm set <new-vmid> --sshkey \"<ssh-key>\""
log_info " qm set <new-vmid> --ipconfig0 ip=<ip>/24,gw=<gateway>"
}
# Run main function
main "$@"

View File

@@ -0,0 +1,386 @@
#!/bin/bash
source ~/.bashrc
# Create All Service VMs via Proxmox API using ISO
# Uploads ISO and creates all VMs automatically
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
else
log_error ".env file not found!"
exit 1
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_URL="https://${PROXMOX_HOST}:8006"
PROXMOX_NODE="${2:-pve}"
ISO_FILE="${ISO_FILE:-ubuntu-24.04.3-live-server-amd64.iso}"
ISO_PATH="${ISO_PATH:-./${ISO_FILE}}"
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Check if ISO exists locally
check_iso() {
if [ ! -f "$ISO_PATH" ]; then
log_error "ISO file not found: $ISO_PATH"
log_info "Looking for ISO in project root..."
ISO_PATH="./ubuntu-24.04.3-live-server-amd64.iso"
if [ ! -f "$ISO_PATH" ]; then
log_error "ISO file not found. Please ensure ubuntu-24.04.3-live-server-amd64.iso is in the project root."
exit 1
fi
fi
log_info "Found ISO: $ISO_PATH"
ISO_SIZE=$(du -h "$ISO_PATH" | cut -f1)
log_info "ISO size: $ISO_SIZE"
}
# Check if ISO already exists in Proxmox
iso_exists() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/storage/local/content")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
isos = [f for f in data.get('data', []) if f.get('content') == 'iso' and '$ISO_FILE' in f.get('volid', '')]
print('true' if isos else 'false')
" 2>/dev/null || echo "false"
}
# Upload ISO to Proxmox
upload_iso() {
local auth=$1
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Uploading ISO to Proxmox..."
log_warn "This may take several minutes depending on ISO size and network speed..."
# Upload ISO using multipart form
local result=$(curl -k -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-F "content=iso" \
-F "filename=@$ISO_PATH" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/storage/local/upload" 2>&1)
if echo "$result" | grep -q "error"; then
log_error "ISO upload failed: $result"
return 1
fi
log_info "✓ ISO uploaded successfully"
return 0
}
# Check if VM exists
vm_exists() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
local response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/cluster/resources?type=vm")
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
vms = [v for v in data.get('data', []) if v.get('type') == 'qemu' and str(v.get('vmid')) == '$vmid']
print('true' if vms else 'false')
" 2>/dev/null || echo "false"
}
# Create VM via API
create_vm() {
local auth=$1
local vmid=$2
local name=$3
local cores=$4
local memory=$5
local disk_size=$6
local ip_address=$7
local gateway=$8
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Creating VM: $name (ID: $vmid)..."
# First, verify ISO exists in storage
local iso_volid="local:iso/${ISO_FILE}"
log_info "Using ISO: $iso_volid"
# Create VM with proper API format
# Note: Proxmox API requires specific parameter format
log_info "API Call: POST $PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu"
log_info "Parameters: vmid=$vmid, name=$name, cores=$cores, memory=$memory"
# Strategy: Create VM with minimal config, then add hardware via separate API calls
log_info "Step 1: Creating VM skeleton..."
local create_response=$(curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "vmid=$vmid" \
-d "name=$name" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu" 2>&1)
if echo "$create_response" | grep -q '"errors"'; then
log_error "Failed to create VM skeleton:"
echo "$create_response" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d.get('errors', {}), indent=2))" 2>/dev/null || echo "$create_response"
return 1
fi
log_info "✓ VM skeleton created"
sleep 1
# Step 2: Configure basic VM settings
log_info "Step 2: Configuring CPU and memory..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "cores=$cores" \
-d "memory=$memory" \
-d "ostype=l26" \
-d "agent=1" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
# Step 3: Add disk (simplest format)
log_info "Step 3: Adding disk..."
local disk_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=local:${disk_size}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$disk_response" | grep -q '"errors"'; then
log_warn "Disk configuration warning (continuing anyway)"
fi
# Step 4: Add ISO
log_info "Step 4: Adding ISO..."
local iso_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ide2=$iso_volid" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$iso_response" | grep -q '"errors"'; then
log_warn "ISO configuration warning (continuing anyway)"
fi
# Step 5: Add network (try simplest format)
log_info "Step 5: Adding network..."
local net_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "net0=bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$net_response" | grep -q '"errors"'; then
log_warn "Network configuration warning (may need manual configuration)"
fi
# Step 6: Set boot order
log_info "Step 6: Configuring boot order..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "boot=order=ide2" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
# Verify VM config file was created
sleep 2
local verify_response=$(curl -k -s -H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$verify_response" | grep -q '"errors"'; then
log_error "VM $name was not created properly. Config file missing."
log_error "Response: $verify_response"
return 1
fi
log_info "✓ VM $name created successfully"
# Configure Cloud-Init if IP is provided
if [ -n "$ip_address" ] && [ -n "$gateway" ]; then
log_info "Configuring Cloud-Init for $name..."
local config_response=$(curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ipconfig0=ip=${ip_address}/24,gw=${gateway}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" 2>&1)
if echo "$config_response" | grep -q '"errors"'; then
log_warn "Cloud-Init configuration may have failed (VM will use DHCP)"
echo "$config_response" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('errors', {}).get('errors', 'Unknown error'))" 2>/dev/null || echo "$config_response"
else
log_info "✓ Network configured for $name"
fi
fi
return 0
}
# Start VM
start_vm() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_info "Starting VM $vmid..."
local start_response=$(curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start")
if echo "$start_response" | grep -q '"error"'; then
log_warn "Failed to start VM $vmid: $start_response"
return 1
fi
log_info "✓ VM $vmid started"
return 0
}
# VM configurations
declare -A VMS=(
["100"]="cloudflare-tunnel:2:4096:40:192.168.1.60:192.168.1.254"
["101"]="k3s-master:4:8192:80:192.168.1.188:192.168.1.254"
["102"]="git-server:4:8192:100:192.168.1.121:192.168.1.254"
["103"]="observability:4:8192:200:192.168.1.82:192.168.1.254"
)
main() {
log_header "Create All Service VMs via Proxmox API"
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
# Check ISO file
check_iso
echo ""
# Authenticate
log_step "Authenticating with Proxmox..."
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_info "✓ Authentication successful"
echo ""
# Check if ISO already uploaded
if [ "$(iso_exists "$auth")" = "true" ]; then
log_info "✓ ISO already exists in Proxmox storage"
else
# Upload ISO
if ! upload_iso "$auth"; then
log_error "Failed to upload ISO"
exit 1
fi
fi
echo ""
# Create VMs
log_step "Creating VMs..."
echo ""
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name cores memory disk_size ip_address gateway <<< "${VMS[$vmid]}"
# Check if VM already exists
if [ "$(vm_exists "$auth" "$vmid")" = "true" ]; then
log_warn "VM $name (ID: $vmid) already exists. Skipping..."
continue
fi
# Create VM
if create_vm "$auth" "$vmid" "$name" "$cores" "$memory" "$disk_size" "$ip_address" "$gateway"; then
# Start VM
start_vm "$auth" "$vmid"
echo ""
else
log_error "Failed to create VM $name"
fi
done
log_header "VM Creation Complete"
echo ""
log_info "All VMs have been created and started!"
echo ""
log_info "Next steps:"
echo " 1. Access each VM console via Proxmox Web UI: $PROXMOX_URL"
echo " 2. Complete Ubuntu installation on each VM"
echo " 3. After OS installation, run setup scripts:"
echo " - scripts/setup-cloudflare-tunnel.sh (on 192.168.1.60)"
echo " - scripts/setup-k3s.sh (on 192.168.1.188)"
echo " - scripts/setup-git-server.sh (on 192.168.1.121)"
echo " - scripts/setup-observability.sh (on 192.168.1.82)"
echo ""
}
main "$@"

View File

@@ -0,0 +1,257 @@
#!/bin/bash
source ~/.bashrc
# Create VMs from Cloud-Init Template with Automated Setup Scripts
# This script creates VMs from a Cloud-Init template and applies service-specific install scripts
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
STORAGE="${STORAGE:-local-lvm}"
TEMPLATE_NAME="${TEMPLATE_NAME:-ubuntu-24.04-cloudinit}"
# VM Configuration
declare -A VMS=(
[100]="cloudflare-tunnel:2:4096:40G:192.168.1.60:192.168.1.1:setup-cloudflare-tunnel.sh"
[101]="k3s-master:4:8192:80G:192.168.1.188:192.168.1.1:setup-k3s.sh"
[102]="git-server:2:4096:100G:192.168.1.121:192.168.1.1:setup-git-server.sh"
[103]="observability:4:8192:200G:192.168.1.82:192.168.1.1:setup-observability.sh"
)
# Get authentication ticket
get_ticket() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
log_error "Failed to authenticate with Proxmox"
return 1
fi
echo "$ticket|$csrf"
}
# Read install script and create Cloud-Init user-data
create_cloud_init_user_data() {
local script_path=$1
local vm_name=$2
local ip_address=$3
local gateway=$4
if [ ! -f "$script_path" ]; then
log_error "Install script not found: $script_path"
return 1
fi
local script_content=$(cat "$script_path" | base64 -w 0)
cat <<EOF
#cloud-config
hostname: ${vm_name}
manage_etc_hosts: true
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${SSH_PUBLIC_KEY:-}
# Network configuration
network:
version: 2
ethernets:
eth0:
addresses:
- ${ip_address}/24
gateway4: ${gateway}
nameservers:
addresses:
- 8.8.8.8
- 8.8.4.4
# Write install script
write_files:
- path: /tmp/install-service.sh
content: !!binary |
${script_content}
owner: root:root
permissions: '0755'
encoding: b64
# Run install script on first boot
runcmd:
- /tmp/install-service.sh
- rm -f /tmp/install-service.sh
# Update packages
package_update: true
package_upgrade: true
# Install common packages
packages:
- curl
- wget
- git
- vim
- net-tools
EOF
}
# Create VM from template
create_vm_from_template() {
local auth=$1
local vmid=$2
local name=$3
local cores=$4
local memory=$5
local disk_size=$6
local ip_address=$7
local gateway=$8
local install_script=$9
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Creating VM $vmid: $name"
# Create Cloud-Init user-data
local user_data_file="/tmp/cloud-init-${vmid}.yaml"
create_cloud_init_user_data "scripts/${install_script}" "$name" "$ip_address" "$gateway" > "$user_data_file"
log_info "Cloud-Init user-data created: $user_data_file"
# Upload user-data to Proxmox (requires manual step or SCP)
log_warn "Note: Cloud-Init user-data needs to be uploaded to Proxmox storage"
log_info "You can:"
log_info " 1. Upload $user_data_file to Proxmox storage manually"
log_info " 2. Or use cicustom parameter in API call"
# Clone template to create VM
log_info "Cloning template $TEMPLATE_NAME to VM $vmid..."
local clone_response=$(curl -k -s -X POST \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "newid=$vmid" \
-d "name=$name" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_NAME/clone")
if echo "$clone_response" | grep -q '"errors"'; then
log_error "Failed to clone template: $clone_response"
return 1
fi
log_info "Template cloned successfully"
# Wait for clone to complete
sleep 5
# Configure VM
log_info "Configuring VM..."
# Set CPU, memory, disk
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "cores=$cores" \
-d "memory=$memory" \
-d "net0=virtio,bridge=vmbr0" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null
# Configure Cloud-Init
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "ipconfig0=ip=${ip_address}/24,gw=${gateway}" \
-d "ciuser=ubuntu" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null
log_info "✓ VM $vmid configured"
# Cleanup
rm -f "$user_data_file"
}
main() {
echo "========================================="
echo "Create VMs from Cloud-Init Template"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
if [ -z "$TEMPLATE_NAME" ]; then
log_error "TEMPLATE_NAME not set. Create template first."
log_info "See: scripts/create-proxmox-template.sh"
exit 1
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
log_step "Creating VMs from template: $TEMPLATE_NAME"
echo ""
# Create each VM
for vmid in 100 101 102 103; do
IFS=':' read -r name cores memory disk_size ip_address gateway install_script <<< "${VMS[$vmid]}"
if create_vm_from_template "$auth" "$vmid" "$name" "$cores" "$memory" "$disk_size" "$ip_address" "$gateway" "$install_script"; then
log_info "✓ VM $vmid ($name) created successfully"
else
log_error "✗ Failed to create VM $vmid"
fi
echo ""
done
log_info "========================================="
log_info "VM Creation Complete"
log_info "========================================="
echo ""
log_warn "Next steps:"
echo " 1. Start each VM"
echo " 2. VM will boot and run install script automatically"
echo " 3. Check VM console for installation progress"
echo " 4. SSH to VM after installation completes"
}
main "$@"

View File

@@ -0,0 +1,135 @@
#!/bin/bash
source ~/.bashrc
# Create VMs via SSH using qm command (more reliable than API)
# Requires SSH access to Proxmox host
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PROXMOX_HOST="${1:-192.168.1.206}"
PROXMOX_USER="${2:-root}"
ISO_FILE="ubuntu-24.04.3-live-server-amd64.iso"
# VM configurations
declare -A VMS=(
["100"]="cloudflare-tunnel:2:4096:40:192.168.1.60:192.168.1.254"
["101"]="k3s-master:4:8192:80:192.168.1.188:192.168.1.254"
["102"]="git-server:4:8192:100:192.168.1.121:192.168.1.254"
["103"]="observability:4:8192:200:192.168.1.82:192.168.1.254"
)
create_vm_ssh() {
local vmid=$1
local name=$2
local cores=$3
local memory=$4
local disk_size=$5
local ip_address=$6
local gateway=$7
log_step "Creating VM: $name (ID: $vmid) via SSH..."
ssh "$PROXMOX_USER@$PROXMOX_HOST" <<EOF
# Create VM
qm create $vmid --name $name --cores $cores --memory $memory --ostype l26
# Add network
qm set $vmid --net0 virtio,bridge=vmbr0
# Add disk
qm set $vmid --scsi0 local:${disk_size},format=raw
# Add ISO
qm set $vmid --ide2 local:iso/${ISO_FILE},media=cdrom
# Configure boot order
qm set $vmid --boot c --bootdisk scsi0
# Enable QEMU agent
qm set $vmid --agent 1
# Configure Cloud-Init (if IP provided)
if [ -n "$ip_address" ] && [ -n "$gateway" ]; then
qm set $vmid --ipconfig0 ip=${ip_address}/24,gw=${gateway}
fi
# Start VM
qm start $vmid
EOF
if [ $? -eq 0 ]; then
log_info "✓ VM $name created and started"
return 0
else
log_error "Failed to create VM $name"
return 1
fi
}
main() {
echo "========================================="
echo "Create VMs via SSH (qm command)"
echo "========================================="
echo ""
log_info "This script requires SSH access to Proxmox host"
log_info "Host: $PROXMOX_HOST"
log_info "User: $PROXMOX_USER"
echo ""
read -p "Do you have SSH access configured? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_error "SSH access required. Please configure SSH keys first."
exit 1
fi
# Test SSH connection
if ! ssh -o ConnectTimeout=5 "$PROXMOX_USER@$PROXMOX_HOST" "echo 'SSH connection successful'" 2>/dev/null; then
log_error "Cannot connect to Proxmox host via SSH"
log_info "Please configure SSH access or use Proxmox Web UI instead"
exit 1
fi
log_info "✓ SSH connection successful"
echo ""
# Create VMs
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name cores memory disk_size ip_address gateway <<< "${VMS[$vmid]}"
create_vm_ssh "$vmid" "$name" "$cores" "$memory" "$disk_size" "$ip_address" "$gateway"
echo ""
done
log_info "========================================="
log_info "VM Creation Complete!"
log_info "========================================="
}
main "$@"

View File

@@ -0,0 +1,126 @@
#!/bin/bash
source ~/.bashrc
# Check Template Status and Guide Recreation
# This script checks if template exists and guides the process
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
TEMPLATE_ID=9000
# Check if template exists
check_template() {
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket" 2>/dev/null)
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
return 1
fi
local config=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_ID/config" 2>&1)
if echo "$config" | grep -q '"name"'; then
return 0
else
return 1
fi
}
main() {
log_header "Template Status Check"
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
log_step "Checking if template $TEMPLATE_ID exists..."
if check_template; then
log_info "✓ Template $TEMPLATE_ID exists!"
echo ""
log_step "Template is ready. Proceeding with VM recreation..."
echo ""
# Run recreation script
export SSH_KEY="$HOME/.ssh/id_rsa"
export SSH_USER="ubuntu"
./scripts/recreate-vms-from-template.sh
else
log_warn "Template $TEMPLATE_ID does not exist yet"
echo ""
log_info "You need to create the template first:"
echo ""
log_step "Quick Steps:"
echo " 1. Upload cloud image to Proxmox:"
echo " • Proxmox Web UI → Storage → local → Upload"
echo " • File: ./downloads/ubuntu-24.04-server-cloudimg-amd64.img"
echo ""
echo " 2. Create VM 9000 from image:"
echo " • Create VM (ID: 9000, Name: ubuntu-24.04-cloudinit)"
echo " • Import disk from uploaded image"
echo " • Configure Cloud-Init with SSH key"
echo ""
echo " 3. Convert to template:"
echo " • Right-click VM 9000 → Convert to Template"
echo ""
log_info "See: QUICK_TEMPLATE_GUIDE.md for detailed instructions"
echo ""
log_info "After creating template, run this script again:"
echo " ./scripts/check-and-recreate.sh"
echo ""
log_info "Or run directly:"
echo " ./scripts/recreate-vms-from-template.sh"
fi
}
main "$@"

View File

@@ -0,0 +1,104 @@
#!/bin/bash
source ~/.bashrc
# Check VM Disk Sizes and Configuration
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Load environment variables
if [ -f .env ]; then
set -a
source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=')
set +a
fi
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
PROXMOX_URL="https://192.168.1.206:8006"
PROXMOX_NODE="pve"
main() {
echo "========================================="
echo "VM Disk Size Configuration"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
echo "Error: PVE_ROOT_PASS not set in .env"
exit 1
fi
# Get authentication ticket
local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \
"$PROXMOX_URL/api2/json/access/ticket")
local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$ticket" ] || [ -z "$csrf" ]; then
echo "Error: Failed to authenticate"
exit 1
fi
echo "VM Disk Configuration:"
echo ""
declare -A VMS=(
[100]="cloudflare-tunnel:40G"
[101]="k3s-master:80G"
[102]="git-server:100G"
[103]="observability:200G"
)
for vmid in 100 101 102 103; do
IFS=':' read -r name expected_size <<< "${VMS[$vmid]}"
local config=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config")
local scsi0=$(echo "$config" | grep -o '"scsi0":"[^"]*' | cut -d'"' -f4)
local actual_size=$(echo "$scsi0" | grep -o 'size=[0-9]*G' | cut -d'=' -f2 || echo "Unknown")
echo "VM $vmid - $name:"
echo " Expected: $expected_size"
echo " Actual: $actual_size"
echo " Device: $scsi0"
if [ "$actual_size" = "$expected_size" ]; then
log_info " ✓ Disk size matches"
else
echo " ⚠ Size mismatch or not found"
fi
echo ""
done
echo "========================================="
echo "Installation Tips:"
echo "========================================="
echo ""
echo "During Ubuntu installation:"
echo " • Select 'Custom storage layout'"
echo " • Choose the disk matching your VM size"
echo " • Ignore the CD-ROM (ISO, ~3GB)"
echo " • Use entire disk or create partitions"
echo ""
echo "See: UBUNTU_INSTALL_DISK_SELECTION.md for details"
}
main "$@"

View File

@@ -0,0 +1,98 @@
#!/bin/bash
source ~/.bashrc
# Check VM Readiness - Verify VMs are ready for SSH and task execution
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
declare -A VMS=(
[100]="cloudflare-tunnel:192.168.1.60"
[101]="k3s-master:192.168.1.188"
[102]="git-server:192.168.1.121"
[103]="observability:192.168.1.82"
)
SSH_USER="${SSH_USER:-ubuntu}"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_rsa}"
check_vm() {
local vmid=$1
local name=$2
local ip=$3
echo -n "VM $vmid ($name) at $ip: "
# Check ping
if ping -c 1 -W 2 "$ip" > /dev/null 2>&1; then
echo -n "✓ Reachable, "
# Check SSH
if ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "echo 'OK'" > /dev/null 2>&1; then
echo "✓ SSH Ready"
return 0
else
echo "⚠ SSH Not Ready"
return 1
fi
else
echo "✗ Not Reachable"
return 1
fi
}
main() {
echo "========================================="
echo "VM Readiness Check"
echo "========================================="
echo ""
if [ ! -f "$SSH_KEY" ]; then
log_error "SSH key not found: $SSH_KEY"
log_info "Available keys:"
ls -1 ~/.ssh/id_* 2>/dev/null | grep -v ".pub" || echo " None found"
exit 1
fi
log_info "Using SSH key: $SSH_KEY"
echo ""
local all_ready=true
for vmid in 100 101 102 103; do
IFS=':' read -r name ip <<< "${VMS[$vmid]}"
if ! check_vm "$vmid" "$name" "$ip"; then
all_ready=false
fi
done
echo ""
if [ "$all_ready" = true ]; then
log_info "✓ All VMs are ready!"
log_info "You can now run: ./scripts/complete-all-vm-tasks.sh"
else
log_warn "⚠ Some VMs are not ready yet"
log_info "Wait for Ubuntu installation to complete"
log_info "Then run this script again to check readiness"
fi
}
main "$@"

View File

@@ -0,0 +1,126 @@
#!/bin/bash
source ~/.bashrc
# Check VM Status and Verify Prerequisites Before Next Steps
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
log_header() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN}$1${NC}"
echo -e "${CYAN}========================================${NC}"
}
# Check VM connectivity
check_vm_connectivity() {
local ip=$1
local name=$2
log_info "Checking $name ($ip)..."
# Ping test
if ping -c 1 -W 2 "$ip" >/dev/null 2>&1; then
log_info "$name is reachable"
# Check if SSH is available
if timeout 2 bash -c "echo >/dev/tcp/$ip/22" 2>/dev/null; then
log_info "✓ SSH port (22) is open"
# Try to check if Ubuntu is installed
if ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no "ubuntu@$ip" "lsb_release -d 2>/dev/null || echo 'OS check failed'" 2>/dev/null | grep -q "Ubuntu"; then
log_info "✓ Ubuntu is installed"
return 0
else
log_warn "✗ Ubuntu installation not verified (may need manual check)"
return 1
fi
else
log_warn "✗ SSH not available yet (OS may still be installing)"
return 1
fi
else
log_warn "$name is not reachable"
return 1
fi
}
# VM configurations
declare -A VMS=(
["100"]="cloudflare-tunnel:192.168.1.60:scripts/setup-cloudflare-tunnel.sh"
["101"]="k3s-master:192.168.1.188:scripts/setup-k3s.sh"
["102"]="git-server:192.168.1.121:scripts/setup-git-server.sh"
["103"]="observability:192.168.1.82:scripts/setup-observability.sh"
)
main() {
log_header "VM Status Check - Prerequisites Verification"
echo ""
log_step "Checking VM Connectivity and OS Installation"
echo ""
local all_ready=true
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name ip script <<< "${VMS[$vmid]}"
echo "--- $name (ID: $vmid) ---"
if check_vm_connectivity "$ip" "$name"; then
log_info "$name is ready for setup"
else
log_warn "$name is not ready yet"
all_ready=false
fi
echo ""
done
log_header "Status Summary"
echo ""
if [ "$all_ready" = true ]; then
log_info "✅ All VMs are ready for setup scripts!"
echo ""
log_info "Next: Run setup scripts on each VM:"
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name ip script <<< "${VMS[$vmid]}"
echo " - $name: ssh ubuntu@$ip 'sudo bash $script'"
done
else
log_warn "⚠️ Some VMs are not ready yet"
echo ""
log_info "Please complete Ubuntu installation on all VMs first:"
echo " 1. Access Proxmox Web UI: https://192.168.1.206:8006"
echo " 2. Open console for each VM"
echo " 3. Complete Ubuntu 24.04 installation"
echo " 4. Configure static IP addresses"
echo " 5. Run this script again to verify"
fi
echo ""
}
main "$@"

View File

@@ -0,0 +1,116 @@
#!/bin/bash
source ~/.bashrc
# Monitor VMs and Automatically Complete Tasks When Ready
# This script continuously checks VM readiness and runs complete-all-vm-tasks.sh when ready
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
declare -A VMS=(
[100]="cloudflare-tunnel:192.168.1.60"
[101]="k3s-master:192.168.1.188"
[102]="git-server:192.168.1.121"
[103]="observability:192.168.1.82"
)
SSH_USER="${SSH_USER:-ubuntu}"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_rsa}"
CHECK_INTERVAL=30 # Check every 30 seconds
MAX_WAIT=3600 # Maximum wait time: 1 hour
check_all_vms_ready() {
local all_ready=true
for vmid in 100 101 102 103; do
IFS=':' read -r name ip <<< "${VMS[$vmid]}"
# Check ping
if ! ping -c 1 -W 2 "$ip" > /dev/null 2>&1; then
all_ready=false
return 1
fi
# Check SSH
if ! ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" "echo 'OK'" > /dev/null 2>&1; then
all_ready=false
return 1
fi
done
return 0
}
main() {
echo "========================================="
echo "VM Monitor - Auto-Complete Tasks"
echo "========================================="
echo ""
log_info "Monitoring VMs for readiness..."
log_info "Will automatically run tasks when all VMs are ready"
log_info "Checking every $CHECK_INTERVAL seconds"
log_info "Maximum wait: $MAX_WAIT seconds (1 hour)"
echo ""
if [ ! -f "$SSH_KEY" ]; then
log_error "SSH key not found: $SSH_KEY"
exit 1
fi
local start_time=$(date +%s)
local check_count=0
while true; do
check_count=$((check_count + 1))
local elapsed=$(($(date +%s) - start_time))
if [ $elapsed -gt $MAX_WAIT ]; then
log_error "Maximum wait time exceeded"
exit 1
fi
echo -n "[Check $check_count] $(date '+%H:%M:%S') - "
if check_all_vms_ready; then
echo ""
log_info "✓ All VMs are ready!"
echo ""
log_step "Running complete-all-vm-tasks.sh..."
echo ""
export SSH_KEY="$SSH_KEY"
export SSH_USER="$SSH_USER"
./scripts/complete-all-vm-tasks.sh
exit $?
else
echo "VMs not ready yet... (elapsed: ${elapsed}s)"
sleep $CHECK_INTERVAL
fi
done
}
main "$@"