Initial commit: loc_az_hci (smom-dbis-138 excluded via .gitignore)
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
196
scripts/vm-management/configure/apply-install-scripts.sh
Executable file
196
scripts/vm-management/configure/apply-install-scripts.sh
Executable 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 "$@"
|
||||
|
||||
54
scripts/vm-management/configure/attach-iso-webui-guide.sh
Executable file
54
scripts/vm-management/configure/attach-iso-webui-guide.sh
Executable 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
|
||||
|
||||
480
scripts/vm-management/configure/complete-all-vm-tasks.sh
Executable file
480
scripts/vm-management/configure/complete-all-vm-tasks.sh
Executable 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 "$@"
|
||||
|
||||
178
scripts/vm-management/configure/complete-vm-setup.sh
Executable file
178
scripts/vm-management/configure/complete-vm-setup.sh
Executable 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 "$@"
|
||||
|
||||
135
scripts/vm-management/configure/final-vm-config-fix.sh
Executable file
135
scripts/vm-management/configure/final-vm-config-fix.sh
Executable 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 "$@"
|
||||
|
||||
223
scripts/vm-management/configure/fix-all-vm-configs.sh
Executable file
223
scripts/vm-management/configure/fix-all-vm-configs.sh
Executable 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 "$@"
|
||||
|
||||
174
scripts/vm-management/configure/fix-boot-config.sh
Executable file
174
scripts/vm-management/configure/fix-boot-config.sh
Executable 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 "$@"
|
||||
|
||||
160
scripts/vm-management/configure/fix-floppy-boot.sh
Executable file
160
scripts/vm-management/configure/fix-floppy-boot.sh
Executable 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 "$@"
|
||||
|
||||
186
scripts/vm-management/configure/fix-guest-agent.sh
Executable file
186
scripts/vm-management/configure/fix-guest-agent.sh
Executable 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 "$@"
|
||||
|
||||
190
scripts/vm-management/configure/fix-vm-config.sh
Executable file
190
scripts/vm-management/configure/fix-vm-config.sh
Executable 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 "$@"
|
||||
|
||||
109
scripts/vm-management/configure/fix-vm-creation.sh
Executable file
109
scripts/vm-management/configure/fix-vm-creation.sh
Executable 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 "$@"
|
||||
|
||||
96
scripts/vm-management/configure/manual-steps-guide.sh
Executable file
96
scripts/vm-management/configure/manual-steps-guide.sh
Executable 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."
|
||||
|
||||
124
scripts/vm-management/configure/set-boot-order-api.sh
Executable file
124
scripts/vm-management/configure/set-boot-order-api.sh
Executable 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 "$@"
|
||||
|
||||
108
scripts/vm-management/configure/setup-vms-complete.sh
Executable file
108
scripts/vm-management/configure/setup-vms-complete.sh
Executable 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 "$@"
|
||||
|
||||
272
scripts/vm-management/create/create-all-vms.sh
Executable file
272
scripts/vm-management/create/create-all-vms.sh
Executable 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 "$@"
|
||||
|
||||
157
scripts/vm-management/create/create-first-vm.sh
Executable file
157
scripts/vm-management/create/create-first-vm.sh
Executable 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 ""
|
||||
|
||||
408
scripts/vm-management/create/create-pmg-vm.sh
Executable file
408
scripts/vm-management/create/create-pmg-vm.sh
Executable 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 "$@"
|
||||
|
||||
94
scripts/vm-management/create/create-proxmox-template.sh
Executable file
94
scripts/vm-management/create/create-proxmox-template.sh
Executable 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 "$@"
|
||||
|
||||
90
scripts/vm-management/create/create-template-quick.sh
Executable file
90
scripts/vm-management/create/create-template-quick.sh
Executable 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
|
||||
|
||||
221
scripts/vm-management/create/create-template-via-api.sh
Executable file
221
scripts/vm-management/create/create-template-via-api.sh
Executable 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 "$@"
|
||||
|
||||
722
scripts/vm-management/create/create-vm-from-image.sh
Executable file
722
scripts/vm-management/create/create-vm-from-image.sh
Executable 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 "$@"
|
||||
|
||||
519
scripts/vm-management/create/create-vm-template.sh
Executable file
519
scripts/vm-management/create/create-vm-template.sh
Executable 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 "$@"
|
||||
|
||||
386
scripts/vm-management/create/create-vms-from-iso.sh
Executable file
386
scripts/vm-management/create/create-vms-from-iso.sh
Executable 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 "$@"
|
||||
|
||||
257
scripts/vm-management/create/create-vms-from-template.sh
Executable file
257
scripts/vm-management/create/create-vms-from-template.sh
Executable 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 "$@"
|
||||
|
||||
135
scripts/vm-management/create/create-vms-via-ssh.sh
Executable file
135
scripts/vm-management/create/create-vms-via-ssh.sh
Executable 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 "$@"
|
||||
|
||||
126
scripts/vm-management/monitor/check-and-recreate.sh
Executable file
126
scripts/vm-management/monitor/check-and-recreate.sh
Executable 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 "$@"
|
||||
|
||||
104
scripts/vm-management/monitor/check-vm-disk-sizes.sh
Executable file
104
scripts/vm-management/monitor/check-vm-disk-sizes.sh
Executable 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 "$@"
|
||||
|
||||
98
scripts/vm-management/monitor/check-vm-readiness.sh
Executable file
98
scripts/vm-management/monitor/check-vm-readiness.sh
Executable 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 "$@"
|
||||
|
||||
126
scripts/vm-management/monitor/check-vm-status.sh
Executable file
126
scripts/vm-management/monitor/check-vm-status.sh
Executable 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 "$@"
|
||||
|
||||
116
scripts/vm-management/monitor/monitor-and-complete.sh
Executable file
116
scripts/vm-management/monitor/monitor-and-complete.sh
Executable 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 "$@"
|
||||
|
||||
Reference in New Issue
Block a user