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

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

View File

@@ -0,0 +1,74 @@
#!/bin/bash
source ~/.bashrc
# Add SSH key to R630 (192.168.1.49) to enable key-based authentication
# This script attempts to add the SSH key via Proxmox API or provides instructions
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source <(grep -v '^#' "$PROJECT_ROOT/.env" | grep -v '^$' | sed 's/#.*$//' | grep '=')
set +a
fi
# 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"; }
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_proxmox}"
SSH_KEY_PUB="${SSH_KEY}.pub"
R630_IP="192.168.1.49"
if [ ! -f "$SSH_KEY_PUB" ]; then
log_error "SSH public key not found: $SSH_KEY_PUB"
exit 1
fi
SSH_KEY_CONTENT=$(cat "$SSH_KEY_PUB")
log_info "Adding SSH key to R630 (192.168.1.49)..."
log_info "SSH Key: $SSH_KEY_PUB"
echo ""
# Try to add key via ssh-copy-id if password auth works
log_info "Attempting to add SSH key using ssh-copy-id..."
if ssh-copy-id -i "$SSH_KEY_PUB" -o StrictHostKeyChecking=no "root@${R630_IP}" 2>/dev/null; then
log_info "✓ SSH key added successfully via ssh-copy-id"
log_info "Testing SSH connection..."
if ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no -o ConnectTimeout=5 "root@${R630_IP}" "echo 'SSH key authentication working!'" 2>/dev/null; then
log_info "✓ SSH key authentication confirmed!"
exit 0
fi
fi
# If ssh-copy-id failed, provide manual instructions
log_warn "ssh-copy-id failed (password auth may be disabled)"
echo ""
log_info "Manual steps to add SSH key:"
echo ""
log_info "1. Access R630 console/web terminal:"
log_info " - Open https://192.168.1.49:8006"
log_info " - Go to: Shell (or use console)"
echo ""
log_info "2. Run this command on R630:"
echo ""
echo "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '${SSH_KEY_CONTENT}' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && echo 'SSH key added'"
echo ""
log_info "3. Or copy this one-liner and paste on R630:"
echo ""
echo "echo '${SSH_KEY_CONTENT}' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh"
echo ""
log_info "4. After adding the key, test connection:"
log_info " ssh -i $SSH_KEY root@${R630_IP}"

View File

@@ -0,0 +1,126 @@
#!/bin/bash
source ~/.bashrc
# Auto-Complete Template Setup and VM Recreation
# Monitors for template creation and automatically recreates VMs
set -e
# Colors
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_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_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)
# Check if it exists and is a template
if echo "$config" | grep -q '"name"' && echo "$config" | grep -q '"template".*1'; then
return 0
else
return 1
fi
}
main() {
log_header "Auto-Complete Template Setup"
echo ""
log_step "Step 1: Template Creation (Manual - Required)"
echo ""
log_info "Please complete these steps in Proxmox Web UI:"
echo ""
echo "1. Upload Cloud Image:"
echo " • Proxmox → Storage → local → Upload"
echo " • File: ./downloads/ubuntu-24.04-server-cloudimg-amd64.img"
echo ""
echo "2. Create VM 9000:"
echo " • Create VM (ID: 9000, Name: ubuntu-24.04-cloudinit)"
echo " • Import disk from uploaded image"
echo " • Configure Cloud-Init (User: ubuntu, 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 steps"
echo ""
log_step "Step 2: Monitoring for Template"
log_info "Checking every 10 seconds for template creation..."
echo ""
local check_count=0
local max_checks=180 # 30 minutes
while [ $check_count -lt $max_checks ]; do
check_count=$((check_count + 1))
if check_template; then
echo ""
log_info "✓ Template detected! Proceeding with VM recreation..."
echo ""
# Run VM recreation
export SSH_KEY="$HOME/.ssh/id_rsa"
export SSH_USER="ubuntu"
./scripts/recreate-vms-from-template.sh
exit $?
fi
if [ $((check_count % 6)) -eq 0 ]; then
echo -n "."
fi
sleep 10
done
echo ""
log_info "Template not detected after 30 minutes"
log_info "Please create template manually, then run:"
echo " ./scripts/check-and-recreate.sh"
}
main "$@"

View File

@@ -0,0 +1,174 @@
#!/bin/bash
source ~/.bashrc
# Complete Automation Script
# Handles all setup steps with prerequisite checking
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}"
}
# 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"
)
# Check VM is ready
check_vm_ready() {
local ip=$1
local name=$2
# Ping test
if ! ping -c 1 -W 2 "$ip" >/dev/null 2>&1; then
return 1
fi
# SSH test
if ! timeout 2 bash -c "echo >/dev/tcp/$ip/22" 2>/dev/null; then
return 1
fi
return 0
}
# Setup VM service
setup_vm_service() {
local name=$1
local ip=$2
local script=$3
log_step "Setting up $name on $ip..."
# Check if VM is ready
if ! check_vm_ready "$ip" "$name"; then
log_warn "$name ($ip) is not ready yet. Skipping..."
return 1
fi
log_info "Copying setup script to $name..."
# Try to copy script (may need password or SSH key)
if scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$script" "ubuntu@$ip:/tmp/setup.sh" 2>/dev/null; then
log_info "Running setup script on $name..."
ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no "ubuntu@$ip" "sudo bash /tmp/setup.sh" 2>&1 | while read line; do
log_info " $line"
done
if [ ${PIPESTATUS[0]} -eq 0 ]; then
log_info "$name setup completed"
return 0
else
log_error "Setup failed on $name"
return 1
fi
else
log_warn "Could not copy script to $name"
log_info "Manual steps for $name:"
echo " 1. SSH to $name: ssh ubuntu@$ip"
echo " 2. Copy $script to VM"
echo " 3. Run: sudo bash /path/to/script"
return 1
fi
}
main() {
log_header "Complete Setup Automation"
echo ""
log_step "Phase 1: Checking Prerequisites"
echo ""
# Check VM configurations
log_info "Verifying VM configurations..."
if ! ./scripts/check-vm-status.sh > /dev/null 2>&1; then
log_warn "Some VMs may not be fully configured"
fi
echo ""
log_step "Phase 2: Checking VM Readiness"
echo ""
local all_ready=true
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name ip script <<< "${VMS[$vmid]}"
if check_vm_ready "$ip" "$name"; then
log_info "$name is ready"
else
log_warn "$name is not ready (Ubuntu may not be installed)"
all_ready=false
fi
done
echo ""
if [ "$all_ready" != true ]; then
log_error "Not all VMs are ready. Please:"
echo " 1. Complete Ubuntu installation on all VMs"
echo " 2. Ensure static IPs are configured"
echo " 3. Ensure SSH access works"
echo " 4. Run this script again"
exit 1
fi
log_step "Phase 3: Running Setup Scripts"
echo ""
local success_count=0
for vmid in "${!VMS[@]}"; do
IFS=':' read -r name ip script <<< "${VMS[$vmid]}"
if setup_vm_service "$name" "$ip" "$script"; then
success_count=$((success_count + 1))
fi
echo ""
done
log_header "Setup Complete"
echo ""
log_info "Successfully configured: $success_count/4 VMs"
echo ""
if [ $success_count -eq 4 ]; then
log_info "✅ All services are set up!"
echo ""
log_info "Next steps:"
echo " - Configure Cloudflare Tunnel (see docs/cloudflare-integration.md)"
echo " - Deploy services to K3s cluster"
echo " - Configure GitOps repository"
echo " - Set up monitoring dashboards"
else
log_warn "Some services need manual setup"
log_info "See VM_STATUS_REPORT.md for details"
fi
}
main "$@"

View File

@@ -0,0 +1,107 @@
#!/bin/bash
source ~/.bashrc
# Complete R630 Cluster Join
# This script provides instructions and attempts automated join
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source <(grep -v '^#' "$PROJECT_ROOT/.env" | grep -v '^$' | sed 's/#.*$//' | grep '=')
set +a
fi
# 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 "\n${BLUE}=== $1 ===${NC}"; }
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_proxmox}"
SSH_OPTS="-i $SSH_KEY -o StrictHostKeyChecking=no"
ML110_IP="192.168.1.206"
R630_IP="192.168.1.49"
ROOT_PASS="${PVE_ROOT_PASS:-L@kers2010}"
log_step "Completing R630 Cluster Join"
# Check current cluster status
log_info "Checking cluster status on ML110..."
ML110_STATUS=$(ssh $SSH_OPTS "root@${ML110_IP}" "pvecm nodes 2>&1" || echo "")
echo "$ML110_STATUS"
log_info "Checking cluster status on R630..."
R630_STATUS=$(ssh $SSH_OPTS "root@${R630_IP}" "pvecm status 2>&1" || echo "")
echo "$R630_STATUS"
if echo "$R630_STATUS" | grep -q "hc-cluster"; then
log_info "✓ R630 is already in the cluster!"
exit 0
fi
log_step "Method 1: Join via Proxmox Web UI (Recommended)"
log_info "1. Open https://${ML110_IP}:8006"
log_info "2. Login as root"
log_info "3. Go to: Datacenter → Cluster → Join Information"
log_info "4. Copy the join command"
log_info "5. Or go to: Datacenter → Cluster → Add"
log_info "6. Enter R630 IP: ${R630_IP}"
log_info "7. Enter root password: ${ROOT_PASS}"
log_info "8. Click 'Join'"
log_step "Method 2: Join via SSH (Manual)"
log_info "SSH to R630 and run:"
echo ""
echo "ssh -i $SSH_KEY root@${R630_IP}"
echo "pvecm add ${ML110_IP}"
echo "# Enter password when prompted: ${ROOT_PASS}"
echo ""
log_step "Method 3: Automated Join Attempt"
log_info "Attempting automated join..."
# Try using expect or similar approach
if command -v expect &>/dev/null; then
log_info "Using expect for password automation..."
expect <<EOF
spawn ssh $SSH_OPTS root@${R630_IP} "pvecm add ${ML110_IP}"
expect {
"password:" {
send "${ROOT_PASS}\r"
exp_continue
}
"yes/no" {
send "yes\r"
exp_continue
}
eof
}
EOF
else
log_warn "expect not installed. Install with: sudo apt-get install expect"
log_info "Or use Method 1 (Web UI) or Method 2 (Manual SSH)"
fi
# Verify join
sleep 10
log_info "Verifying cluster join..."
if ssh $SSH_OPTS "root@${R630_IP}" "pvecm status 2>&1" | grep -q "hc-cluster"; then
log_info "✓ R630 successfully joined the cluster!"
ssh $SSH_OPTS "root@${ML110_IP}" "pvecm nodes"
else
log_warn "Cluster join may still be in progress or needs manual approval"
log_info "Check cluster status:"
log_info " ssh root@${ML110_IP} 'pvecm nodes'"
log_info " ssh root@${R630_IP} 'pvecm status'"
fi

View File

@@ -0,0 +1,88 @@
#!/bin/bash
source ~/.bashrc
# Download Ubuntu Cloud-Init Image for Proxmox Template
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"
}
# Ubuntu versions
UBUNTU_24_04_URL="https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
UBUNTU_22_04_URL="https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"
VERSION="${1:-24.04}"
DOWNLOAD_DIR="${2:-./downloads}"
main() {
echo "========================================="
echo "Download Ubuntu Cloud-Init Image"
echo "========================================="
echo ""
case "$VERSION" in
24.04)
URL="$UBUNTU_24_04_URL"
FILENAME="ubuntu-24.04-server-cloudimg-amd64.img"
;;
22.04)
URL="$UBUNTU_22_04_URL"
FILENAME="ubuntu-22.04-server-cloudimg-amd64.img"
;;
*)
echo "Error: Unsupported version. Use 22.04 or 24.04"
exit 1
;;
esac
mkdir -p "$DOWNLOAD_DIR"
OUTPUT="$DOWNLOAD_DIR/$FILENAME"
log_step "Downloading Ubuntu $VERSION Cloud Image..."
log_info "URL: $URL"
log_info "Output: $OUTPUT"
echo ""
if [ -f "$OUTPUT" ]; then
log_info "File already exists: $OUTPUT"
read -p "Overwrite? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Skipping download"
exit 0
fi
fi
# Download with progress
if command -v wget &> /dev/null; then
wget --progress=bar:force -O "$OUTPUT" "$URL"
elif command -v curl &> /dev/null; then
curl -L --progress-bar -o "$OUTPUT" "$URL"
else
log_error "Neither wget nor curl found"
exit 1
fi
log_info "✓ Download complete: $OUTPUT"
echo ""
log_info "Next steps:"
log_info " 1. Upload to Proxmox storage"
log_info " 2. Convert to template"
log_info " 3. Use for cloning VMs"
echo ""
log_info "See: docs/proxmox-ubuntu-images.md for details"
}
main "$@"

View File

@@ -0,0 +1,109 @@
#!/bin/bash
source ~/.bashrc
# Enable SSH on R630 Proxmox Host (192.168.1.49)
# This script attempts to enable SSH via Proxmox API
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source <(grep -v '^#' "$PROJECT_ROOT/.env" | grep -v '^$' | sed 's/#.*$//' | grep '=')
set +a
fi
# 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"; }
PROXMOX_URL="${PROXMOX_R630_URL:-https://192.168.1.49:8006}"
PROXMOX_USER="${PVE_USERNAME:-root@pam}"
PROXMOX_PASS="${PVE_ROOT_PASS:-}"
PROXMOX_NODE="${PROXMOX_R630_NODE:-pve}"
if [ -z "$PROXMOX_PASS" ]; then
log_error "PVE_ROOT_PASS not set in .env file"
log_info "Please set PVE_ROOT_PASS in .env or provide password:"
read -sp "Password: " PROXMOX_PASS
echo ""
fi
log_info "Attempting to enable SSH on R630 (192.168.1.49) via Proxmox API..."
# Get API token
log_info "Authenticating with Proxmox API..."
RESPONSE=$(curl -s -k --connect-timeout 10 --max-time 15 \
-d "username=${PROXMOX_USER}&password=${PROXMOX_PASS}" \
"${PROXMOX_URL}/api2/json/access/ticket" 2>&1)
if ! echo "$RESPONSE" | grep -q '"data"'; then
log_error "Failed to authenticate with Proxmox API"
log_warn "Response: $RESPONSE"
log_info ""
log_info "Alternative: Enable SSH via Proxmox Web UI:"
log_info " 1. Open ${PROXMOX_URL} in browser"
log_info " 2. Login as root"
log_info " 3. Go to: System → Services → ssh"
log_info " 4. Click 'Enable' and 'Start'"
exit 1
fi
TICKET=$(echo "$RESPONSE" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4)
CSRF=$(echo "$RESPONSE" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4)
if [ -z "$TICKET" ] || [ -z "$CSRF" ]; then
log_error "Failed to get API token"
exit 1
fi
log_info "✓ Authenticated successfully"
# Enable SSH service
log_info "Enabling SSH service..."
SSH_RESPONSE=$(curl -s -k -X POST \
-H "Cookie: PVEAuthCookie=${TICKET}" \
-H "CSRFPreventionToken: ${CSRF}" \
"${PROXMOX_URL}/api2/json/nodes/${PROXMOX_NODE}/services/ssh/start" 2>&1)
if echo "$SSH_RESPONSE" | grep -q '"data"'; then
log_info "✓ SSH service started"
else
log_warn "SSH service start response: $SSH_RESPONSE"
fi
# Enable SSH on boot
log_info "Enabling SSH on boot..."
ENABLE_RESPONSE=$(curl -s -k -X POST \
-H "Cookie: PVEAuthCookie=${TICKET}" \
-H "CSRFPreventionToken: ${CSRF}" \
-d "enable=1" \
"${PROXMOX_URL}/api2/json/nodes/${PROXMOX_NODE}/services/ssh" 2>&1)
if echo "$ENABLE_RESPONSE" | grep -q '"data"'; then
log_info "✓ SSH service enabled on boot"
else
log_warn "SSH enable response: $ENABLE_RESPONSE"
fi
# Test SSH access
log_info "Testing SSH access..."
sleep 2
if ssh -i "${SSH_KEY:-$HOME/.ssh/id_ed25519_proxmox}" -o StrictHostKeyChecking=no -o ConnectTimeout=5 "root@192.168.1.49" "echo 'SSH OK'" &>/dev/null; then
log_info "✓ SSH access confirmed!"
log_info "You can now SSH to R630:"
log_info " ssh -i ~/.ssh/id_ed25519_proxmox root@192.168.1.49"
else
log_warn "SSH test failed. SSH may need a moment to start."
log_info "Try manually: ssh root@192.168.1.49"
fi

View File

@@ -0,0 +1,172 @@
#!/bin/bash
source ~/.bashrc
# Fix Corrupted Proxmox Cloud Image
# This script removes corrupted images and helps re-upload a fresh copy
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_warn() {
echo -e "${YELLOW}[WARN]${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="${PROXMOX_ML110_URL#https://}"
PROXMOX_HOST="${PROXMOX_HOST%%:*}"
IMAGE_NAME="ubuntu-24.04-server-cloudimg-amd64.img"
LOCAL_IMAGE="${1:-./downloads/${IMAGE_NAME}}"
REMOTE_PATH="/var/lib/vz/template/iso/${IMAGE_NAME}"
REMOTE_IMPORT_PATH="/var/lib/vz/import/${IMAGE_NAME}.raw"
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
main() {
echo "========================================="
echo "Fix Corrupted Proxmox Cloud Image"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
if [ -z "$PROXMOX_HOST" ]; then
log_error "PROXMOX_ML110_URL not set in .env"
exit 1
fi
log_step "Target Proxmox host: $PROXMOX_HOST"
log_info "Image name: $IMAGE_NAME"
echo ""
# Check if local image exists
if [ ! -f "$LOCAL_IMAGE" ]; then
log_warn "Local image not found: $LOCAL_IMAGE"
log_info "Downloading image..."
./scripts/download-ubuntu-cloud-image.sh 24.04
LOCAL_IMAGE="./downloads/${IMAGE_NAME}"
if [ ! -f "$LOCAL_IMAGE" ]; then
log_error "Failed to download image"
exit 1
fi
fi
# Verify local image
log_step "1. Verifying local image..."
if qemu-img info "$LOCAL_IMAGE" > /dev/null 2>&1; then
IMAGE_SIZE=$(du -h "$LOCAL_IMAGE" | cut -f1)
log_info "✓ Local image is valid (Size: $IMAGE_SIZE)"
else
log_error "✗ Local image appears corrupted"
log_info "Re-downloading..."
rm -f "$LOCAL_IMAGE"
./scripts/download-ubuntu-cloud-image.sh 24.04
fi
# Check SSH access
log_step "2. Testing SSH access to Proxmox host..."
if ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@$PROXMOX_HOST "echo 'Connected'" > /dev/null 2>&1; then
log_info "✓ SSH access confirmed"
else
log_error "✗ Cannot connect to Proxmox host via SSH"
log_info "Make sure:"
log_info " 1. SSH is enabled on Proxmox host"
log_info " 2. Root login is allowed (or use SSH keys)"
log_info " 3. Host is reachable from this machine"
exit 1
fi
# Remove corrupted remote files
log_step "3. Removing corrupted image files on Proxmox host..."
ssh root@$PROXMOX_HOST "
if [ -f '$REMOTE_PATH' ]; then
echo 'Removing: $REMOTE_PATH'
rm -f '$REMOTE_PATH'
fi
if [ -f '$REMOTE_IMPORT_PATH' ]; then
echo 'Removing: $REMOTE_IMPORT_PATH'
rm -f '$REMOTE_IMPORT_PATH'
fi
echo 'Cleanup complete'
"
# Upload fresh image
log_step "4. Uploading fresh image to Proxmox host..."
log_info "This may take several minutes depending on your network speed..."
log_info "Uploading: $LOCAL_IMAGE"
log_info "To: root@$PROXMOX_HOST:$REMOTE_PATH"
echo ""
# Create directory if it doesn't exist
ssh root@$PROXMOX_HOST "mkdir -p /var/lib/vz/template/iso"
# Upload with progress
if command -v rsync &> /dev/null; then
log_info "Using rsync (with progress)..."
rsync -avz --progress "$LOCAL_IMAGE" root@$PROXMOX_HOST:"$REMOTE_PATH"
else
log_info "Using scp..."
scp "$LOCAL_IMAGE" root@$PROXMOX_HOST:"$REMOTE_PATH"
fi
# Verify uploaded image
log_step "5. Verifying uploaded image on Proxmox host..."
if ssh root@$PROXMOX_HOST "qemu-img info '$REMOTE_PATH' > /dev/null 2>&1"; then
REMOTE_SIZE=$(ssh root@$PROXMOX_HOST "du -h '$REMOTE_PATH' | cut -f1")
log_info "✓ Image uploaded successfully (Size: $REMOTE_SIZE)"
else
log_error "✗ Uploaded image verification failed"
log_warn "The file may still be uploading or there may be storage issues"
exit 1
fi
# Set proper permissions
log_step "6. Setting file permissions..."
ssh root@$PROXMOX_HOST "chmod 644 '$REMOTE_PATH'"
log_info "✓ Permissions set"
echo ""
log_info "========================================="
log_info "Image Fix Complete!"
log_info "========================================="
log_info ""
log_info "The image has been successfully uploaded to:"
log_info " $REMOTE_PATH"
log_info ""
log_info "Next steps:"
log_info " 1. Verify the image in Proxmox Web UI:"
log_info " Storage → local → Content"
log_info " 2. Follow CREATE_VM_9000_STEPS.md to create VM 9000"
log_info " 3. Or run: ./scripts/verify-proxmox-image.sh"
echo ""
}
main "$@"

View File

@@ -0,0 +1,336 @@
#!/bin/bash
source ~/.bashrc
# Improve Template VM 9000 with Recommended Enhancements
# This script applies all recommended improvements to template 9000
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source <(grep -v '^#' "$PROJECT_ROOT/.env" | grep -v '^$' | sed 's/#.*$//' | grep '=')
set +a
fi
# 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 ""
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
}
PROXMOX_HOST="${PROXMOX_ML110_IP:-192.168.1.206}"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_proxmox}"
SSH_OPTS="-i $SSH_KEY -o StrictHostKeyChecking=no"
TEMPLATE_VMID=9000
TEMP_VMID=9999
TEMP_VM_NAME="template-update-temp"
VM_USER="${VM_USER:-ubuntu}"
# Check if running on Proxmox host or remotely
if command -v qm >/dev/null 2>&1; then
RUN_LOCAL=true
PROXMOX_CMD=""
else
RUN_LOCAL=false
PROXMOX_CMD="ssh $SSH_OPTS root@$PROXMOX_HOST"
fi
run_proxmox_cmd() {
if [ "$RUN_LOCAL" = true ]; then
eval "$1"
else
ssh $SSH_OPTS "root@$PROXMOX_HOST" "$1"
fi
}
wait_for_ssh() {
local ip="$1"
local max_attempts=30
local attempt=0
log_info "Waiting for SSH to be available on $ip..."
while [ $attempt -lt $max_attempts ]; do
if ssh $SSH_OPTS -o ConnectTimeout=5 "${VM_USER}@${ip}" "echo 'SSH ready'" &>/dev/null; then
log_info "✓ SSH is ready"
return 0
fi
attempt=$((attempt + 1))
sleep 2
done
log_error "SSH not available after $max_attempts attempts"
return 1
}
get_vm_ip() {
local vmid="$1"
local ip=""
# Try to use helper library if available (when running on Proxmox host)
if [ "$RUN_LOCAL" = true ] && [ -f "$PROJECT_ROOT/scripts/lib/proxmox_vm_helpers.sh" ]; then
source "$PROJECT_ROOT/scripts/lib/proxmox_vm_helpers.sh" 2>/dev/null || true
if command -v get_vm_ip_from_guest_agent &>/dev/null; then
ip=$(get_vm_ip_from_guest_agent "$vmid" 2>/dev/null || echo "")
if [[ -n "$ip" && "$ip" != "null" ]]; then
echo "$ip"
return 0
fi
fi
fi
# Try to get IP from guest agent using jq directly (suppress errors)
if run_proxmox_cmd "command -v jq >/dev/null 2>&1" 2>/dev/null; then
ip=$(run_proxmox_cmd "qm guest cmd $vmid network-get-interfaces 2>/dev/null | jq -r '.[]?.\"ip-addresses\"[]? | select(.[\"ip-address-type\"] == \"ipv4\" and .\"ip-address\" != \"127.0.0.1\") | .\"ip-address\"' | head -n1" 2>/dev/null || echo "")
if [[ -n "$ip" && "$ip" != "null" && "$ip" != "" ]]; then
echo "$ip"
return 0
fi
fi
# Try MAC-based discovery: get VM MAC and match with ARP table
local mac
mac=$(run_proxmox_cmd "qm config $vmid 2>/dev/null | grep -E '^net0:' | cut -d',' -f1 | cut -d'=' -f2 | tr '[:upper:]' '[:lower:]' | tr -d ':'" 2>/dev/null || echo "")
if [[ -n "$mac" ]]; then
# Format MAC for matching (with colons)
local mac_formatted="${mac:0:2}:${mac:2:2}:${mac:4:2}:${mac:6:2}:${mac:8:2}:${mac:10:2}"
# Try to find IP in ARP table
ip=$(run_proxmox_cmd "ip neigh show 2>/dev/null | grep -i '$mac_formatted' | grep -oE '192\.168\.1\.[0-9]+' | head -n1" 2>/dev/null || echo "")
if [[ -n "$ip" ]]; then
echo "$ip"
return 0
fi
fi
# Return empty string (not a warning message)
echo ""
return 1
}
main() {
log_step "Template 9000 Improvement Script"
log_warn "This script will:"
log_warn " 1. Clone template 9000 to temporary VM 9999"
log_warn " 2. Boot the temporary VM"
log_warn " 3. Apply all recommended improvements"
log_warn " 4. Convert back to template"
log_warn " 5. Replace original template 9000"
echo ""
# Check if template exists
if ! run_proxmox_cmd "qm config $TEMPLATE_VMID &>/dev/null"; then
log_error "Template VM $TEMPLATE_VMID not found"
exit 1
fi
# Check if temp VM already exists
if run_proxmox_cmd "qm config $TEMP_VMID &>/dev/null" 2>/dev/null; then
log_warn "Temporary VM $TEMP_VMID already exists. Destroying it..."
run_proxmox_cmd "qm stop $TEMP_VMID" 2>/dev/null || true
sleep 2
run_proxmox_cmd "qm destroy $TEMP_VMID --purge" 2>/dev/null || true
sleep 2
fi
# Step 1: Clone template
log_step "Step 1: Cloning Template to Temporary VM"
log_info "Cloning template $TEMPLATE_VMID to VM $TEMP_VMID..."
run_proxmox_cmd "qm clone $TEMPLATE_VMID $TEMP_VMID --name $TEMP_VM_NAME"
log_info "✓ Template cloned"
# Step 2: Boot temporary VM
log_step "Step 2: Booting Temporary VM"
log_info "Starting VM $TEMP_VMID..."
run_proxmox_cmd "qm start $TEMP_VMID"
log_info "Waiting for VM to boot and get DHCP IP (this may take 60-90 seconds)..."
sleep 60
# Step 3: Get IP and wait for SSH
log_step "Step 3: Getting VM IP and Waiting for SSH"
local vm_ip=""
# Try multiple times to get IP (VM may still be booting)
log_info "Attempting to discover VM IP (may take a few attempts)..."
for attempt in {1..10}; do
vm_ip=$(get_vm_ip "$TEMP_VMID" 2>/dev/null || echo "")
if [[ -n "$vm_ip" ]]; then
log_info "✓ Discovered IP: $vm_ip"
break
fi
if [ $attempt -lt 10 ]; then
log_info "Attempt $attempt/10: Waiting for VM to finish booting..."
sleep 10
fi
done
# If still no IP, try to get from Proxmox API or prompt user
if [[ -z "$vm_ip" ]]; then
log_warn "Could not automatically discover IP via guest agent."
log_info "Please check Proxmox web UI or router DHCP leases for VM $TEMP_VMID IP address."
log_info "You can also check with: ssh root@$PROXMOX_HOST 'qm config $TEMP_VMID'"
echo ""
read -p "Enter the VM IP address (or press Enter to skip and try again later): " vm_ip
if [[ -z "$vm_ip" ]]; then
log_error "IP address required. Exiting."
log_info "VM $TEMP_VMID is running. You can manually:"
log_info " 1. Get the IP from Proxmox UI or router"
log_info " 2. SSH into the VM and apply improvements manually"
log_info " 3. Run this script again with the IP"
exit 1
fi
fi
wait_for_ssh "$vm_ip" || {
log_error "Failed to connect to VM. Please check:"
log_error " 1. VM is booted: qm status $TEMP_VMID"
log_error " 2. IP address is correct: $vm_ip"
log_error " 3. SSH key is correct: $SSH_KEY"
exit 1
}
# Step 4: Apply improvements
log_step "Step 4: Applying Template Improvements"
log_info "Installing essential packages and QEMU Guest Agent..."
ssh $SSH_OPTS "${VM_USER}@${vm_ip}" <<'EOF'
set -e
sudo apt-get update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq
# Install essential packages
sudo apt-get install -y \
jq \
curl \
wget \
git \
vim \
nano \
net-tools \
htop \
unattended-upgrades \
apt-transport-https \
ca-certificates \
qemu-guest-agent \
ufw
# Enable and start QEMU Guest Agent
sudo systemctl enable qemu-guest-agent
sudo systemctl start qemu-guest-agent
# Configure automatic security updates
echo 'Unattended-Upgrade::Automatic-Reboot "false";' | sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades > /dev/null
echo 'Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";' | sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades > /dev/null
# Set timezone
sudo timedatectl set-timezone UTC
# Configure locale
sudo locale-gen en_US.UTF-8
sudo update-locale LANG=en_US.UTF-8
# SSH hardening (disable root login, password auth)
sudo sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/#PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Install UFW (firewall) but don't enable it - let VMs configure as needed
# UFW is installed but not enabled, so VMs can configure firewall rules per their needs
# Clean up disk
sudo apt-get autoremove -y -qq
sudo apt-get autoclean -qq
sudo rm -rf /tmp/*
sudo rm -rf /var/tmp/*
sudo truncate -s 0 /var/log/*.log 2>/dev/null || true
sudo journalctl --vacuum-time=1d --quiet
# Create template version file
echo "template-9000-v1.1.0-$(date +%Y%m%d)" | sudo tee /etc/template-version > /dev/null
echo "✓ All improvements applied"
EOF
if [ $? -ne 0 ]; then
log_error "Failed to apply improvements"
exit 1
fi
log_info "✓ All improvements applied successfully"
# Step 5: Stop VM and convert to template
log_step "Step 5: Converting Back to Template"
log_info "Stopping VM $TEMP_VMID..."
run_proxmox_cmd "qm stop $TEMP_VMID"
sleep 5
log_info "Converting VM $TEMP_VMID to template..."
run_proxmox_cmd "qm template $TEMP_VMID"
log_info "✓ VM converted to template"
# Step 6: Replace original template
log_step "Step 6: Replacing Original Template"
log_warn "This will destroy the original template 9000 and replace it with the improved version"
echo ""
if [ -t 0 ]; then
read -p "Continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
log_info "Cancelled. Improved template is available as VM $TEMP_VMID"
log_info "You can manually:"
log_info " 1. Destroy template 9000: qm destroy 9000"
log_info " 2. Change VMID: qm set $TEMP_VMID --vmid 9000"
exit 0
fi
else
log_info "Non-interactive mode: auto-confirming"
fi
log_info "Destroying original template 9000..."
run_proxmox_cmd "qm destroy $TEMPLATE_VMID --purge" 2>/dev/null || true
sleep 2
log_info "Changing VMID from $TEMP_VMID to $TEMPLATE_VMID..."
run_proxmox_cmd "qm set $TEMP_VMID --vmid $TEMPLATE_VMID"
log_step "Template Improvement Complete!"
log_info "✓ Template 9000 has been improved with:"
log_info " - QEMU Guest Agent pre-installed and enabled"
log_info " - Essential utilities (jq, curl, wget, git, vim, nano, htop, net-tools, etc.)"
log_info " - Automatic security updates configured (unattended-upgrades)"
log_info " - Timezone set to UTC"
log_info " - Locale configured (en_US.UTF-8)"
log_info " - SSH hardened (no root login, no password auth, pubkey only)"
log_info " - UFW firewall installed (not enabled - VMs configure as needed)"
log_info " - Disk optimized and cleaned"
log_info " - Template version tracking (/etc/template-version)"
log_info ""
log_info "You can now clone VMs from template 9000 and they will have all these improvements!"
}
main "$@"

View File

@@ -0,0 +1,117 @@
#!/bin/bash
source ~/.bashrc
# Install QEMU Guest Agent in All VMs
# Uses guest-agent IP discovery (with fallback for bootstrap)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source <(grep -v '^#' "$PROJECT_ROOT/.env" | grep -v '^$' | sed 's/#.*$//' | grep '=')
set +a
fi
# 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"
}
VM_USER="${VM_USER:-ubuntu}"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_proxmox}"
PROXMOX_HOST="${PROXMOX_ML110_IP:-192.168.1.206}"
# VMID NAME (no IP - discovered via guest agent)
VMS=(
"100 cloudflare-tunnel"
"101 k3s-master"
"102 git-server"
"103 observability"
)
# Fallback IPs for bootstrap (when guest agent not yet installed)
# Format: VMID:IP
declare -A FALLBACK_IPS=(
["100"]="192.168.1.60"
["101"]="192.168.1.188"
["102"]="192.168.1.121"
["103"]="192.168.1.82"
)
# Import helper library
if [ -f "$PROJECT_ROOT/scripts/lib/proxmox_vm_helpers.sh" ]; then
source "$PROJECT_ROOT/scripts/lib/proxmox_vm_helpers.sh"
else
log_error "Helper library not found. Run this script on Proxmox host or via SSH."
exit 1
fi
main() {
log_info "Installing QEMU Guest Agent in all VMs"
echo ""
for vm_spec in "${VMS[@]}"; do
read -r vmid name <<< "$vm_spec"
echo "=== VM $vmid: $name ==="
# Make sure agent is enabled in Proxmox VM config
ensure_guest_agent_enabled "$vmid" || true
# Get IP - try guest agent first, fallback to hardcoded for bootstrap
local ip
ip="$(get_vm_ip_or_fallback "$vmid" "$name" "${FALLBACK_IPS[$vmid]:-}" || true)"
if [[ -z "$ip" ]]; then
log_warn "Skipping: no IP available for VM $vmid ($name)"
echo
continue
fi
echo " Using IP: $ip installing qemu-guest-agent inside guest (idempotent)..."
if ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 "${VM_USER}@${ip}" <<'EOF'
set -e
sudo apt-get update -qq
sudo apt-get install -y qemu-guest-agent > /dev/null 2>&1
sudo systemctl enable --now qemu-guest-agent
systemctl is-active qemu-guest-agent && echo "✓ QEMU Guest Agent is running"
EOF
then
log_info " ✓ QEMU Guest Agent installed and started"
# Wait a moment for agent to be ready, then verify
sleep 3
local discovered_ip
discovered_ip="$(get_vm_ip_from_guest_agent "$vmid" || true)"
if [[ -n "$discovered_ip" ]]; then
log_info " ✓ Guest agent IP discovery working: $discovered_ip"
fi
else
log_error " ✗ Failed to install QEMU Guest Agent"
fi
echo
done
log_info "Done. All VMs should now support guest-agent IP discovery."
}
main "$@"

View File

@@ -0,0 +1,354 @@
#!/bin/bash
source ~/.bashrc
# Destroy Existing VMs and Recreate from Ubuntu Cloud-Init Template
# This script creates a template from Ubuntu Cloud Image and recreates all VMs
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-lvm}"
TEMPLATE_ID=9000
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"
[101]="k3s-master:4:8192:80G:192.168.1.188:192.168.1.1"
[102]="git-server:2:4096:100G:192.168.1.121:192.168.1.1"
[103]="observability:4:8192:200G:192.168.1.82:192.168.1.1"
)
# 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 template exists
template_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/qemu/$TEMPLATE_ID/config" 2>&1)
if echo "$response" | grep -q '"name"'; then
return 0
else
return 1
fi
}
# Download Ubuntu Cloud Image
download_cloud_image() {
local image_url="https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
local image_file="/tmp/ubuntu-24.04-server-cloudimg-amd64.img"
log_step "Downloading Ubuntu 24.04 Cloud Image..."
if [ -f "$image_file" ]; then
log_info "Cloud image already exists: $image_file"
return 0
fi
log_info "Downloading from: $image_url"
log_warn "This may take several minutes (image is ~2GB)..."
if command -v wget &> /dev/null; then
wget --progress=bar:force -O "$image_file" "$image_url" || return 1
elif command -v curl &> /dev/null; then
curl -L --progress-bar -o "$image_file" "$image_url" || return 1
else
log_error "Neither wget nor curl found"
return 1
fi
log_info "✓ Cloud image downloaded"
echo "$image_file"
}
# Create template from cloud image
create_template() {
local auth=$1
local image_file=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Creating template from cloud image..."
# Check if template already exists
if template_exists "$auth"; then
log_info "Template $TEMPLATE_ID already exists, skipping creation"
return 0
fi
log_warn "Template creation requires manual steps in Proxmox Web UI:"
echo ""
log_info "1. Upload cloud image to Proxmox:"
log_info " - Go to: Datacenter → $PROXMOX_NODE → Storage → local"
log_info " - Click 'Upload' → Select: $image_file"
log_info " - Wait for upload to complete"
echo ""
log_info "2. Create VM from image:"
log_info " - Create VM (ID: $TEMPLATE_ID)"
log_info " - Import disk from uploaded image"
log_info " - Set CPU: 2, Memory: 2048MB"
log_info " - Add network device"
log_info " - Enable Cloud-Init in Options"
log_info " - Convert to template"
echo ""
log_warn "After template is created, press Enter to continue..."
read -p "Press Enter when template is ready..."
}
# Destroy existing VM
destroy_vm() {
local auth=$1
local vmid=$2
local ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Destroying VM $vmid..."
# Stop VM 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 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 "$response" | grep -q '"errors"'; then
log_error "Failed to destroy VM: $response"
return 1
fi
log_info "✓ VM $vmid destroyed"
return 0
}
# 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 ticket=$(echo "$auth" | cut -d'|' -f1)
local csrf=$(echo "$auth" | cut -d'|' -f2)
log_step "Creating VM $vmid: $name from template..."
# Clone template
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_ID/clone" 2>&1)
if echo "$clone_response" | grep -q '"errors"'; then
log_error "Failed to clone template: $clone_response"
return 1
fi
log_info "Template cloned, waiting for completion..."
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" \
-d "agent=1" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
# Resize disk if needed
local current_disk=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" | \
grep -o '"scsi0":"[^"]*' | cut -d'"' -f4 | cut -d',' -f2 | cut -d'=' -f2)
if [ "$current_disk" != "$disk_size" ]; then
log_info "Resizing disk to $disk_size..."
curl -k -s -X PUT \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
-d "scsi0=${STORAGE}:${disk_size}" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/resize" > /dev/null 2>&1
fi
# Configure Cloud-Init
log_info "Configuring 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" \
-d "cipassword=" \
-d "sshkeys=$(cat ~/.ssh/id_rsa.pub 2>/dev/null | base64 -w 0 || echo '')" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1
log_info "✓ VM $vmid created and configured"
return 0
}
main() {
log_header "Recreate VMs from Cloud-Init Template"
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
exit 1
fi
log_warn "This will DESTROY existing VMs (100, 101, 102, 103)"
log_warn "And recreate them from a Cloud-Init template"
echo ""
read -p "Continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
log_info "Cancelled"
exit 0
fi
# Authenticate
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Step 1: Download cloud image
image_file=$(download_cloud_image)
if [ $? -ne 0 ]; then
log_error "Failed to download cloud image"
exit 1
fi
# Step 2: Create template (manual steps required)
create_template "$auth" "$image_file"
# Verify template exists
if ! template_exists "$auth"; then
log_error "Template does not exist. Please create it first."
exit 1
fi
# Step 3: Destroy existing VMs
log_header "Destroying Existing VMs"
for vmid in 100 101 102 103; do
destroy_vm "$auth" "$vmid" || log_warn "Failed to destroy VM $vmid"
done
sleep 3
# Step 4: Create VMs from template
log_header "Creating VMs from Template"
for vmid in 100 101 102 103; do
IFS=':' read -r name cores memory disk_size ip_address gateway <<< "${VMS[$vmid]}"
if create_vm_from_template "$auth" "$vmid" "$name" "$cores" "$memory" "$disk_size" "$ip_address" "$gateway"; then
log_info "✓ VM $vmid created"
else
log_error "✗ Failed to create VM $vmid"
fi
echo ""
done
# Step 5: Start VMs
log_header "Starting VMs"
for vmid in 100 101 102 103; do
log_info "Starting VM $vmid..."
ticket=$(echo "$auth" | cut -d'|' -f1)
csrf=$(echo "$auth" | cut -d'|' -f2)
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 started"
done
log_header "VM Recreation Complete!"
echo ""
log_info "VMs are being created from template with Cloud-Init"
log_info "They will boot automatically and configure themselves"
log_info "No manual installation required!"
echo ""
log_info "Next steps:"
echo " 1. Wait 2-3 minutes for VMs to boot"
echo " 2. Check readiness: ./scripts/check-vm-readiness.sh"
echo " 3. Run tasks: ./scripts/complete-all-vm-tasks.sh"
}
main "$@"

View File

@@ -0,0 +1,164 @@
#!/bin/bash
source ~/.bashrc
# Complete Cloudflare Tunnel Setup Script
# Run this on the Cloudflare Tunnel VM after OS installation
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"
}
# Check if running as root
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use sudo)"
exit 1
fi
log_step "Step 1: Installing cloudflared..."
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared
cloudflared --version
log_info "cloudflared installed successfully"
log_step "Step 2: Creating cloudflared user..."
useradd -r -s /bin/false cloudflared || log_warn "User cloudflared may already exist"
mkdir -p /etc/cloudflared
chown cloudflared:cloudflared /etc/cloudflared
log_step "Step 3: Authenticating cloudflared..."
log_warn "You need to authenticate cloudflared manually:"
echo ""
echo "Run this command:"
echo " cloudflared tunnel login"
echo ""
echo "This will open a browser for authentication."
echo "After authentication, press Enter to continue..."
read -p "Press Enter after completing authentication..."
log_step "Step 4: Creating tunnel..."
log_warn "Creating tunnel 'azure-stack-hci'..."
log_warn "If tunnel already exists, you can skip this step."
read -p "Create new tunnel? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
cloudflared tunnel create azure-stack-hci || log_warn "Tunnel may already exist"
fi
# Get tunnel ID
TUNNEL_ID=$(cloudflared tunnel list | grep azure-stack-hci | awk '{print $1}' | head -1)
if [ -z "$TUNNEL_ID" ]; then
log_error "Could not find tunnel ID. Please create tunnel manually."
exit 1
fi
log_info "Tunnel ID: $TUNNEL_ID"
log_step "Step 5: Creating tunnel configuration..."
cat > /etc/cloudflared/config.yml <<EOF
tunnel: $TUNNEL_ID
credentials-file: /etc/cloudflared/$TUNNEL_ID.json
ingress:
# Proxmox UI
- hostname: proxmox.yourdomain.com
service: https://192.168.1.206:8006
originRequest:
noHappyEyeballs: true
tcpKeepAlive: 30
connectTimeout: 30s
# Proxmox R630
- hostname: proxmox-r630.yourdomain.com
service: https://192.168.1.49:8006
originRequest:
noHappyEyeballs: true
tcpKeepAlive: 30
connectTimeout: 30s
# Grafana Dashboard
- hostname: grafana.yourdomain.com
service: http://192.168.1.82:3000
originRequest:
connectTimeout: 30s
# Git Server
- hostname: git.yourdomain.com
service: https://192.168.1.121:443
originRequest:
noHappyEyeballs: true
tcpKeepAlive: 30
connectTimeout: 30s
# K3s Dashboard (if exposed)
- hostname: k3s.yourdomain.com
service: https://192.168.1.188:6443
originRequest:
noHappyEyeballs: true
tcpKeepAlive: 30
connectTimeout: 30s
# Catch-all (must be last)
- service: http_status:404
EOF
chmod 600 /etc/cloudflared/config.yml
chown cloudflared:cloudflared /etc/cloudflared/config.yml
log_info "Configuration file created: /etc/cloudflared/config.yml"
log_warn "Update hostnames in config.yml to match your domain!"
log_step "Step 6: Creating systemd service..."
cat > /etc/systemd/system/cloudflared.service <<EOF
[Unit]
Description=Cloudflare Tunnel
After=network.target
[Service]
Type=simple
User=cloudflared
ExecStart=/usr/local/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
log_step "Step 7: Enabling and starting service..."
systemctl daemon-reload
systemctl enable cloudflared
systemctl start cloudflared
sleep 2
systemctl status cloudflared --no-pager
log_info "========================================="
log_info "Cloudflare Tunnel Setup Complete!"
log_info "========================================="
echo ""
log_warn "Next steps:"
echo " 1. Update /etc/cloudflared/config.yml with your actual domain"
echo " 2. Configure DNS records in Cloudflare Dashboard"
echo " 3. Set up Zero Trust policies in Cloudflare Dashboard"
echo " 4. Test tunnel connectivity: cloudflared tunnel info azure-stack-hci"
echo ""
log_info "Tunnel status: systemctl status cloudflared"
log_info "Tunnel logs: journalctl -u cloudflared -f"

View File

@@ -0,0 +1,119 @@
#!/bin/bash
source ~/.bashrc
# Git Server Setup Script (Gitea)
# Run this on the Git Server VM after OS installation
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"
}
# Check if running as root
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use sudo)"
exit 1
fi
GITEA_VERSION="${GITEA_VERSION:-1.21.0}"
GITEA_USER="${GITEA_USER:-git}"
GITEA_HOME="${GITEA_HOME:-/var/lib/gitea}"
GITEA_DOMAIN="${GITEA_DOMAIN:-192.168.1.121}"
GITEA_PORT="${GITEA_PORT:-3000}"
log_step "Step 1: Installing dependencies..."
apt-get update
apt-get install -y git sqlite3
log_step "Step 2: Creating Gitea user..."
useradd -r -s /bin/bash -m -d "$GITEA_HOME" "$GITEA_USER" || log_warn "User $GITEA_USER may already exist"
log_step "Step 3: Downloading and installing Gitea..."
mkdir -p "$GITEA_HOME"
cd "$GITEA_HOME"
wget -O gitea "https://dl.gitea.io/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64"
chmod +x gitea
chown -R "$GITEA_USER:$GITEA_USER" "$GITEA_HOME"
log_step "Step 4: Creating systemd service..."
cat > /etc/systemd/system/gitea.service <<EOF
[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target
[Service]
Type=simple
User=$GITEA_USER
Group=$GITEA_USER
WorkingDirectory=$GITEA_HOME
ExecStart=$GITEA_HOME/gitea web --config $GITEA_HOME/custom/conf/app.ini
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
log_step "Step 5: Creating initial configuration..."
mkdir -p "$GITEA_HOME/custom/conf"
cat > "$GITEA_HOME/custom/conf/app.ini" <<EOF
[server]
DOMAIN = $GITEA_DOMAIN
HTTP_PORT = $GITEA_PORT
ROOT_URL = http://$GITEA_DOMAIN:$GITEA_PORT/
DISABLE_SSH = false
SSH_PORT = 22
[database]
DB_TYPE = sqlite3
PATH = $GITEA_HOME/data/gitea.db
[repository]
ROOT = $GITEA_HOME/gitea-repositories
[log]
MODE = file
LEVEL = Info
EOF
chown -R "$GITEA_USER:$GITEA_USER" "$GITEA_HOME"
log_step "Step 6: Enabling and starting Gitea..."
systemctl daemon-reload
systemctl enable gitea
systemctl start gitea
sleep 3
systemctl status gitea --no-pager
log_info "========================================="
log_info "Gitea Installation Complete!"
log_info "========================================="
echo ""
log_info "Access Gitea at: http://$GITEA_DOMAIN:$GITEA_PORT"
log_info "Initial setup will be required on first access"
echo ""
log_info "Next steps:"
echo " 1. Complete initial Gitea setup via web UI"
echo " 2. Create GitOps repository"
echo " 3. Configure SSH keys for Git access"
echo " 4. Set up Flux GitOps (if using)"

View File

@@ -0,0 +1,261 @@
#!/bin/bash
source ~/.bashrc
# Install and Configure QEMU Guest Agent on All VMs
# This script installs qemu-guest-agent on Ubuntu VMs and enables it in Proxmox
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"
# VM Configuration
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"
}
# Check if VM is reachable
check_vm_reachable() {
local ip=$1
if ping -c 1 -W 2 "$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
}
# Install guest agent on VM
install_guest_agent_on_vm() {
local vmid=$1
local name=$2
local ip=$3
log_step "Installing QEMU Guest Agent on VM $vmid: $name"
# Check if VM is reachable
if ! check_vm_reachable "$ip"; then
log_error "VM at $ip is not reachable, skipping..."
return 1
fi
# Check SSH
if ! check_ssh "$ip" "$SSH_USER"; then
log_error "SSH not available on $ip, skipping..."
return 1
fi
log_info "Installing qemu-guest-agent via SSH..."
# Install qemu-guest-agent
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" "${SSH_USER}@${ip}" <<EOF
sudo apt-get update
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 -5
EOF
if [ $? -eq 0 ]; then
log_info "✓ Guest agent installed and started on VM $vmid"
return 0
else
log_error "✗ Failed to install guest agent on VM $vmid"
return 1
fi
}
# Enable guest agent in Proxmox VM configuration
enable_guest_agent_in_proxmox() {
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 "Enabling guest agent in Proxmox for VM $vmid: $name"
# Enable agent in VM config
local response=$(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" 2>&1)
if echo "$response" | grep -q '"errors"'; then
log_error "Failed to enable agent: $response"
return 1
fi
log_info "✓ Guest agent enabled in Proxmox for VM $vmid"
return 0
}
# Verify guest agent is working
verify_guest_agent() {
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 "Verifying guest agent for VM $vmid: $name"
# Check agent status via Proxmox API
local response=$(curl -k -s \
-H "Cookie: PVEAuthCookie=$ticket" \
-H "CSRFPreventionToken: $csrf" \
"$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/agent/get-fsinfo" 2>&1)
if echo "$response" | grep -q '"result"'; then
log_info "✓ Guest agent is responding"
return 0
else
log_warn "⚠ Guest agent may not be fully ready yet"
log_info " This is normal if VM was just configured"
log_info " Agent may take a few minutes to initialize"
return 1
fi
}
main() {
echo "========================================="
echo "Setup QEMU Guest Agent on All VMs"
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"
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 ""
# Authenticate with Proxmox
auth=$(get_ticket)
if [ $? -ne 0 ]; then
exit 1
fi
# Process each VM
for vmid in 100 101 102 103; do
IFS=':' read -r name ip <<< "${VMS[$vmid]}"
echo "----------------------------------------"
log_step "Processing VM $vmid: $name"
echo ""
# Step 1: Install guest agent on VM
if install_guest_agent_on_vm "$vmid" "$name" "$ip"; then
log_info "✓ Guest agent installed on VM"
else
log_error "✗ Failed to install guest agent"
echo ""
continue
fi
# Step 2: Enable agent in Proxmox
if enable_guest_agent_in_proxmox "$auth" "$vmid" "$name"; then
log_info "✓ Agent enabled in Proxmox"
else
log_error "✗ Failed to enable agent in Proxmox"
fi
# Step 3: Verify (optional, may take time)
sleep 2
verify_guest_agent "$auth" "$vmid" "$name" || true
echo ""
done
log_info "========================================="
log_info "Guest Agent Setup Complete"
log_info "========================================="
echo ""
log_info "Benefits of QEMU Guest Agent:"
echo " • Proper VM shutdown/reboot from Proxmox"
echo " • Automatic IP address detection"
echo " • Better VM status reporting"
echo " • File system information"
echo ""
log_warn "Note: Guest agent may take a few minutes to fully initialize"
log_info "You can verify in Proxmox Web UI:"
echo " VM → Monitor → QEMU Guest Agent"
}
main "$@"

View File

@@ -0,0 +1,83 @@
#!/bin/bash
source ~/.bashrc
# K3s Installation Script
# Run this on the K3s VM after OS installation
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"
}
# Check if running as root
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use sudo)"
exit 1
fi
log_step "Step 1: Installing K3s..."
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644" sh -
log_step "Step 2: Verifying K3s installation..."
systemctl status k3s --no-pager || log_error "K3s service not running"
log_step "Step 3: Waiting for K3s to be ready..."
sleep 10
kubectl get nodes || log_warn "K3s may still be initializing"
log_step "Step 4: Installing kubectl (if not present)..."
if ! command -v kubectl &> /dev/null; then
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin/
fi
log_step "Step 5: Configuring kubectl..."
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
mkdir -p ~/.kube
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
chmod 600 ~/.kube/config
log_step "Step 6: Verifying cluster..."
kubectl cluster-info
kubectl get nodes
log_info "========================================="
log_info "K3s Installation Complete!"
log_info "========================================="
echo ""
log_info "K3s is ready to use!"
echo ""
log_info "Useful commands:"
echo " kubectl get nodes"
echo " kubectl get pods --all-namespaces"
echo " kubectl cluster-info"
echo ""
log_warn "Next steps:"
echo " 1. Create namespaces: kubectl create namespace blockchain"
echo " 2. Deploy ingress controller"
echo " 3. Deploy cert-manager"
echo " 4. Deploy HC Stack services"
echo ""
log_info "Kubeconfig location: /etc/rancher/k3s/k3s.yaml"
log_info "Copy this file to access cluster remotely"

View File

@@ -0,0 +1,146 @@
#!/bin/bash
source ~/.bashrc
# Observability Stack Setup Script (Prometheus + Grafana)
# Run this on the Observability VM after OS installation
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"
}
# Check if running as root
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use sudo)"
exit 1
fi
PROMETHEUS_VERSION="${PROMETHEUS_VERSION:-2.45.0}"
GRAFANA_VERSION="${GRAFANA_VERSION:-10.0.0}"
PROMETHEUS_USER="${PROMETHEUS_USER:-prometheus}"
GRAFANA_USER="${GRAFANA_USER:-grafana}"
log_step "Step 1: Installing dependencies..."
apt-get update
apt-get install -y wget curl
log_step "Step 2: Installing Prometheus..."
# Create Prometheus user
useradd -r -s /bin/false "$PROMETHEUS_USER" || log_warn "User $PROMETHEUS_USER may already exist"
# Download and install Prometheus
cd /tmp
wget "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
tar xzf "prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
mv "prometheus-${PROMETHEUS_VERSION}.linux-amd64" /opt/prometheus
mkdir -p /etc/prometheus
mkdir -p /var/lib/prometheus
chown -R "$PROMETHEUS_USER:$PROMETHEUS_USER" /opt/prometheus /etc/prometheus /var/lib/prometheus
# Create Prometheus configuration
cat > /etc/prometheus/prometheus.yml <<EOF
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node-exporter'
static_configs:
- targets: ['localhost:9100']
EOF
# Create systemd service
cat > /etc/systemd/system/prometheus.service <<EOF
[Unit]
Description=Prometheus
After=network.target
[Service]
Type=simple
User=$PROMETHEUS_USER
ExecStart=/opt/prometheus/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/var/lib/prometheus
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
log_step "Step 3: Installing Node Exporter..."
cd /tmp
wget "https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz"
tar xzf node_exporter-1.6.1.linux-amd64.tar.gz
mv node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
chmod +x /usr/local/bin/node_exporter
cat > /etc/systemd/system/node-exporter.service <<EOF
[Unit]
Description=Node Exporter
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/node_exporter
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
log_step "Step 4: Installing Grafana..."
apt-get install -y apt-transport-https software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" > /etc/apt/sources.list.d/grafana.list
apt-get update
apt-get install -y grafana
log_step "Step 5: Starting services..."
systemctl daemon-reload
systemctl enable prometheus node-exporter grafana-server
systemctl start prometheus node-exporter grafana-server
sleep 3
log_info "========================================="
log_info "Observability Stack Installation Complete!"
log_info "========================================="
echo ""
log_info "Services:"
echo " - Prometheus: http://192.168.1.82:9090"
echo " - Grafana: http://192.168.1.82:3000"
echo " - Node Exporter: http://192.168.1.82:9100"
echo ""
log_info "Grafana default credentials:"
echo " Username: admin"
echo " Password: admin (change on first login)"
echo ""
log_info "Next steps:"
echo " 1. Access Grafana and change default password"
echo " 2. Add Prometheus as data source (http://localhost:9090)"
echo " 3. Import dashboards from grafana.com/dashboards"
echo " 4. Configure alerting rules"

View File

@@ -0,0 +1,118 @@
#!/bin/bash
source ~/.bashrc
# Verify Proxmox Cloud Image Integrity
# Usage: ./scripts/verify-proxmox-image.sh [proxmox-host] [image-path]
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_warn() {
echo -e "${YELLOW}[WARN]${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:-${PROXMOX_ML110_URL#https://}}"
PROXMOX_HOST="${PROXMOX_HOST%%:*}"
IMAGE_PATH="${2:-/var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img}"
PVE_USERNAME="${PVE_USERNAME:-root@pam}"
PVE_PASSWORD="${PVE_ROOT_PASS:-}"
main() {
echo "========================================="
echo "Verify Proxmox Cloud Image Integrity"
echo "========================================="
echo ""
if [ -z "$PVE_PASSWORD" ]; then
log_error "PVE_ROOT_PASS not set in .env"
log_info "Set PVE_ROOT_PASS in .env file or pass as argument"
exit 1
fi
log_step "Connecting to Proxmox host: $PROXMOX_HOST"
log_info "Checking image: $IMAGE_PATH"
echo ""
# Check if file exists
log_step "1. Checking if file exists..."
if ssh -o StrictHostKeyChecking=no root@$PROXMOX_HOST "[ -f '$IMAGE_PATH' ]"; then
log_info "✓ File exists"
else
log_error "✗ File not found: $IMAGE_PATH"
log_info "Alternative locations to check:"
log_info " - /var/lib/vz/import/ubuntu-24.04-server-cloudimg-amd64.img.raw"
log_info " - /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img"
exit 1
fi
# Get file size
log_step "2. Checking file size..."
FILE_SIZE=$(ssh root@$PROXMOX_HOST "ls -lh '$IMAGE_PATH' | awk '{print \$5}'")
log_info "File size: $FILE_SIZE"
# Check file type
log_step "3. Checking file type..."
FILE_TYPE=$(ssh root@$PROXMOX_HOST "file '$IMAGE_PATH'")
log_info "$FILE_TYPE"
# Verify with qemu-img
log_step "4. Verifying image with qemu-img..."
if ssh root@$PROXMOX_HOST "qemu-img info '$IMAGE_PATH' 2>&1"; then
log_info "✓ Image appears valid"
else
log_error "✗ Image verification failed"
log_warn "Image may be corrupted. See TROUBLESHOOTING_VM_9000.md"
exit 1
fi
# Check disk space
log_step "5. Checking available disk space..."
ssh root@$PROXMOX_HOST "df -h /var/lib/vz | tail -1"
# Check for I/O errors in dmesg
log_step "6. Checking for recent I/O errors..."
IO_ERRORS=$(ssh root@$PROXMOX_HOST "dmesg | grep -i 'i/o error' | tail -5")
if [ -z "$IO_ERRORS" ]; then
log_info "✓ No recent I/O errors found"
else
log_warn "Recent I/O errors detected:"
echo "$IO_ERRORS"
log_warn "This may indicate storage issues"
fi
echo ""
log_info "========================================="
log_info "Verification Complete"
log_info "========================================="
log_info ""
log_info "If all checks passed, you can proceed with VM creation."
log_info "If errors were found, see TROUBLESHOOTING_VM_9000.md"
}
main "$@"