402 lines
13 KiB
Bash
402 lines
13 KiB
Bash
|
|
#!/bin/bash
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Layer 1B: Nodito (Proxmox) Setup
|
|||
|
|
#
|
|||
|
|
# This script configures the Nodito Proxmox server.
|
|||
|
|
# Runs independently - can be executed without VPS setup.
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
set -e # Exit on error
|
|||
|
|
|
|||
|
|
# Colors for output
|
|||
|
|
RED='\033[0;31m'
|
|||
|
|
GREEN='\033[0;32m'
|
|||
|
|
YELLOW='\033[1;33m'
|
|||
|
|
BLUE='\033[0;34m'
|
|||
|
|
NC='\033[0m' # No Color
|
|||
|
|
|
|||
|
|
# Project root directory
|
|||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|||
|
|
ANSIBLE_DIR="$PROJECT_ROOT/ansible"
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Helper Functions
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
print_header() {
|
|||
|
|
echo -e "\n${BLUE}========================================${NC}"
|
|||
|
|
echo -e "${BLUE}$1${NC}"
|
|||
|
|
echo -e "${BLUE}========================================${NC}\n"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_success() {
|
|||
|
|
echo -e "${GREEN}✓${NC} $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_error() {
|
|||
|
|
echo -e "${RED}✗${NC} $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_warning() {
|
|||
|
|
echo -e "${YELLOW}⚠${NC} $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
print_info() {
|
|||
|
|
echo -e "${BLUE}ℹ${NC} $1"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
confirm_action() {
|
|||
|
|
local prompt="$1"
|
|||
|
|
local response
|
|||
|
|
|
|||
|
|
read -p "$(echo -e ${YELLOW}${prompt}${NC} [y/N]: )" response
|
|||
|
|
[[ "$response" =~ ^[Yy]$ ]]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Verification Functions
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
check_layer_0_complete() {
|
|||
|
|
print_header "Verifying Layer 0 Prerequisites"
|
|||
|
|
|
|||
|
|
local errors=0
|
|||
|
|
|
|||
|
|
# Check if venv exists
|
|||
|
|
if [ ! -d "$PROJECT_ROOT/venv" ]; then
|
|||
|
|
print_error "Python venv not found. Run Layer 0 first."
|
|||
|
|
((errors++))
|
|||
|
|
else
|
|||
|
|
print_success "Python venv exists"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Check if we're in a venv
|
|||
|
|
if [ -z "$VIRTUAL_ENV" ]; then
|
|||
|
|
print_error "Virtual environment not activated"
|
|||
|
|
echo "Run: source venv/bin/activate"
|
|||
|
|
((errors++))
|
|||
|
|
else
|
|||
|
|
print_success "Virtual environment activated"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Check if Ansible is installed
|
|||
|
|
if ! command -v ansible &> /dev/null; then
|
|||
|
|
print_error "Ansible not found"
|
|||
|
|
((errors++))
|
|||
|
|
else
|
|||
|
|
print_success "Ansible found: $(ansible --version | head -n1)"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Check if inventory.ini exists
|
|||
|
|
if [ ! -f "$ANSIBLE_DIR/inventory.ini" ]; then
|
|||
|
|
print_error "inventory.ini not found"
|
|||
|
|
((errors++))
|
|||
|
|
else
|
|||
|
|
print_success "inventory.ini exists"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if [ $errors -gt 0 ]; then
|
|||
|
|
print_error "Layer 0 is not complete. Please run ./scripts/setup_layer_0.sh first"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
print_success "Layer 0 prerequisites verified"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
get_hosts_from_inventory() {
|
|||
|
|
local group="$1"
|
|||
|
|
cd "$ANSIBLE_DIR"
|
|||
|
|
ansible-inventory -i inventory.ini --list | \
|
|||
|
|
python3 -c "import sys, json; data=json.load(sys.stdin); print(' '.join(data.get('$group', {}).get('hosts', [])))" 2>/dev/null || echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
check_nodito_configured() {
|
|||
|
|
print_header "Checking Nodito Configuration"
|
|||
|
|
|
|||
|
|
local nodito_hosts=$(get_hosts_from_inventory "nodito")
|
|||
|
|
|
|||
|
|
if [ -z "$nodito_hosts" ]; then
|
|||
|
|
print_error "No nodito host configured in inventory.ini"
|
|||
|
|
print_info "Add nodito to [nodito] group in inventory.ini to proceed"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
print_success "Nodito configured: $nodito_hosts"
|
|||
|
|
echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Nodito Setup Functions
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
setup_nodito_bootstrap() {
|
|||
|
|
print_header "Bootstrapping Nodito (Proxmox Server)"
|
|||
|
|
|
|||
|
|
cd "$ANSIBLE_DIR"
|
|||
|
|
|
|||
|
|
print_info "This will:"
|
|||
|
|
echo " • Set up SSH key access for root"
|
|||
|
|
echo " • Create the counterweight user with SSH keys"
|
|||
|
|
echo " • Update and secure the system"
|
|||
|
|
echo " • Disable root login and password authentication"
|
|||
|
|
echo ""
|
|||
|
|
print_info "Running: ansible-playbook -i inventory.ini infra/nodito/30_proxmox_bootstrap_playbook.yml"
|
|||
|
|
print_warning "You will be prompted for the root password"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if ! confirm_action "Proceed with nodito bootstrap?"; then
|
|||
|
|
print_warning "Skipped nodito bootstrap"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Run with root user and ask for password
|
|||
|
|
if ansible-playbook -i inventory.ini infra/nodito/30_proxmox_bootstrap_playbook.yml -e 'ansible_user=root' --ask-pass; then
|
|||
|
|
print_success "Nodito bootstrap complete"
|
|||
|
|
return 0
|
|||
|
|
else
|
|||
|
|
print_error "Nodito bootstrap failed"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setup_nodito_community_repos() {
|
|||
|
|
print_header "Switching Nodito to Community Repositories"
|
|||
|
|
|
|||
|
|
cd "$ANSIBLE_DIR"
|
|||
|
|
|
|||
|
|
print_info "This will:"
|
|||
|
|
echo " • Remove enterprise repository files"
|
|||
|
|
echo " • Add community repository files"
|
|||
|
|
echo " • Disable subscription nag messages"
|
|||
|
|
echo " • Update Proxmox packages"
|
|||
|
|
echo ""
|
|||
|
|
print_info "Running: ansible-playbook -i inventory.ini infra/nodito/31_proxmox_community_repos_playbook.yml"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if ! confirm_action "Proceed with community repos setup?"; then
|
|||
|
|
print_warning "Skipped community repos setup"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if ansible-playbook -i inventory.ini infra/nodito/31_proxmox_community_repos_playbook.yml; then
|
|||
|
|
print_success "Community repositories configured"
|
|||
|
|
print_warning "Clear browser cache before using Proxmox web UI (Ctrl+Shift+R)"
|
|||
|
|
return 0
|
|||
|
|
else
|
|||
|
|
print_error "Community repos setup failed"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setup_nodito_zfs() {
|
|||
|
|
print_header "Setting Up ZFS Storage Pool on Nodito (Optional)"
|
|||
|
|
|
|||
|
|
cd "$ANSIBLE_DIR"
|
|||
|
|
|
|||
|
|
print_warning "⚠️ ZFS setup will DESTROY ALL DATA on the specified disks!"
|
|||
|
|
echo ""
|
|||
|
|
print_info "Before proceeding, you must:"
|
|||
|
|
echo " 1. SSH into nodito: ssh root@<nodito-ip>"
|
|||
|
|
echo " 2. List disks: ls -la /dev/disk/by-id/ | grep -E '(ata-|scsi-|nvme-)'"
|
|||
|
|
echo " 3. Identify the two disk IDs you want to use for RAID 1"
|
|||
|
|
echo " 4. Edit ansible/infra/nodito/nodito_vars.yml"
|
|||
|
|
echo " 5. Set zfs_disk_1 and zfs_disk_2 to your disk IDs"
|
|||
|
|
echo ""
|
|||
|
|
print_info "Example nodito_vars.yml content:"
|
|||
|
|
echo ' zfs_disk_1: "/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-WCC7K1234567"'
|
|||
|
|
echo ' zfs_disk_2: "/dev/disk/by-id/ata-WDC_WD40EFRX-68N32N0_WD-WCC7K7654321"'
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if [ ! -f "$ANSIBLE_DIR/infra/nodito/nodito_vars.yml" ]; then
|
|||
|
|
print_warning "nodito_vars.yml not found"
|
|||
|
|
if confirm_action "Create nodito_vars.yml template?"; then
|
|||
|
|
cat > "$ANSIBLE_DIR/infra/nodito/nodito_vars.yml" << 'EOF'
|
|||
|
|
# Nodito Variables
|
|||
|
|
# Configure these before running ZFS setup
|
|||
|
|
|
|||
|
|
# ZFS Storage Pool Configuration
|
|||
|
|
# Uncomment and configure these lines after identifying your disk IDs:
|
|||
|
|
# zfs_disk_1: "/dev/disk/by-id/ata-YOUR-DISK-1-ID-HERE"
|
|||
|
|
# zfs_disk_2: "/dev/disk/by-id/ata-YOUR-DISK-2-ID-HERE"
|
|||
|
|
# zfs_pool_name: "proxmox-storage"
|
|||
|
|
|
|||
|
|
# CPU Temperature Monitoring
|
|||
|
|
monitoring_script_dir: /opt/cpu-temp-monitor
|
|||
|
|
monitoring_script_path: "{{ monitoring_script_dir }}/cpu_temp_monitor.sh"
|
|||
|
|
log_file: "{{ monitoring_script_dir }}/cpu_temp_monitor.log"
|
|||
|
|
temp_threshold_celsius: 80
|
|||
|
|
EOF
|
|||
|
|
print_success "Created nodito_vars.yml template"
|
|||
|
|
print_info "Edit this file and configure ZFS disks, then re-run this script"
|
|||
|
|
fi
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Check if ZFS disks are configured
|
|||
|
|
if ! grep -q "^zfs_disk_1:" "$ANSIBLE_DIR/infra/nodito/nodito_vars.yml" 2>/dev/null; then
|
|||
|
|
print_info "ZFS disks not configured in nodito_vars.yml"
|
|||
|
|
print_info "Edit ansible/infra/nodito/nodito_vars.yml to configure disk IDs"
|
|||
|
|
if ! confirm_action "Skip ZFS setup for now?"; then
|
|||
|
|
print_info "Please configure ZFS disks first"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
print_warning "Skipped ZFS setup"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
print_info "Running: ansible-playbook -i inventory.ini infra/nodito/32_zfs_pool_setup_playbook.yml"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if ! confirm_action "⚠️ Proceed with ZFS setup? (THIS WILL DESTROY DATA ON CONFIGURED DISKS)"; then
|
|||
|
|
print_warning "Skipped ZFS setup"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if ansible-playbook -i inventory.ini infra/nodito/32_zfs_pool_setup_playbook.yml; then
|
|||
|
|
print_success "ZFS storage pool configured"
|
|||
|
|
return 0
|
|||
|
|
else
|
|||
|
|
print_error "ZFS setup failed"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setup_nodito_cloud_template() {
|
|||
|
|
print_header "Creating Debian Cloud Template on Nodito (Optional)"
|
|||
|
|
|
|||
|
|
cd "$ANSIBLE_DIR"
|
|||
|
|
|
|||
|
|
print_info "This will:"
|
|||
|
|
echo " • Download Debian cloud image"
|
|||
|
|
echo " • Create a VM template (ID 9000)"
|
|||
|
|
echo " • Configure cloud-init for easy VM creation"
|
|||
|
|
echo ""
|
|||
|
|
print_info "Running: ansible-playbook -i inventory.ini infra/nodito/33_proxmox_debian_cloud_template.yml"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if ! confirm_action "Proceed with cloud template creation?"; then
|
|||
|
|
print_warning "Skipped cloud template creation"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if ansible-playbook -i inventory.ini infra/nodito/33_proxmox_debian_cloud_template.yml; then
|
|||
|
|
print_success "Debian cloud template created (VM ID 9000)"
|
|||
|
|
return 0
|
|||
|
|
else
|
|||
|
|
print_error "Cloud template creation failed"
|
|||
|
|
return 1
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Verification Functions
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
verify_layer_1b() {
|
|||
|
|
print_header "Verifying Layer 1B Completion"
|
|||
|
|
|
|||
|
|
cd "$ANSIBLE_DIR"
|
|||
|
|
|
|||
|
|
local ssh_key=$(grep "ansible_ssh_private_key_file" "$ANSIBLE_DIR/inventory.ini" | head -n1 | sed 's/.*ansible_ssh_private_key_file=\([^ ]*\).*/\1/')
|
|||
|
|
ssh_key="${ssh_key/#\~/$HOME}"
|
|||
|
|
|
|||
|
|
local nodito_hosts=$(get_hosts_from_inventory "nodito")
|
|||
|
|
|
|||
|
|
print_info "Testing SSH as counterweight user..."
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
for host in $nodito_hosts; do
|
|||
|
|
if timeout 10 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$host "echo 'SSH OK'" &>/dev/null; then
|
|||
|
|
print_success "SSH to $host as counterweight: OK"
|
|||
|
|
else
|
|||
|
|
print_error "Cannot SSH to $host as counterweight"
|
|||
|
|
print_info "Test manually: ssh -i $ssh_key counterweight@$host"
|
|||
|
|
fi
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Summary Functions
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
print_summary() {
|
|||
|
|
print_header "Layer 1B: Nodito Setup Complete! 🎉"
|
|||
|
|
|
|||
|
|
echo "Summary of what was configured:"
|
|||
|
|
echo ""
|
|||
|
|
print_success "Nodito bootstrapped with SSH keys"
|
|||
|
|
print_success "counterweight user created"
|
|||
|
|
print_success "Community repositories configured"
|
|||
|
|
print_success "Root login and password auth disabled"
|
|||
|
|
|
|||
|
|
if grep -q "^zfs_disk_1:" "$ANSIBLE_DIR/infra/nodito/nodito_vars.yml" 2>/dev/null; then
|
|||
|
|
print_success "ZFS storage pool configured (if you ran it)"
|
|||
|
|
fi
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
print_warning "Important Security Changes:"
|
|||
|
|
echo " • Root SSH login is now disabled"
|
|||
|
|
echo " • Always use 'counterweight' user for SSH access"
|
|||
|
|
echo " • Password authentication is disabled"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
print_info "Proxmox Web UI:"
|
|||
|
|
local nodito_hosts=$(get_hosts_from_inventory "nodito")
|
|||
|
|
echo " • Access at: https://$nodito_hosts:8006"
|
|||
|
|
echo " • Clear browser cache (Ctrl+Shift+R) to avoid UI issues"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
print_info "Next steps:"
|
|||
|
|
echo " 1. Test SSH: ssh -i ~/.ssh/counterganzua counterweight@<nodito-ip>"
|
|||
|
|
echo " 2. Access Proxmox web UI and verify community repos"
|
|||
|
|
echo " 3. Create VMs on Proxmox (if needed)"
|
|||
|
|
echo " 4. Proceed to Layer 2: ./scripts/setup_layer_2.sh"
|
|||
|
|
echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
###############################################################################
|
|||
|
|
# Main Execution
|
|||
|
|
###############################################################################
|
|||
|
|
|
|||
|
|
main() {
|
|||
|
|
clear
|
|||
|
|
|
|||
|
|
print_header "🖥️ Layer 1B: Nodito (Proxmox) Setup"
|
|||
|
|
|
|||
|
|
echo "This script will configure your Nodito Proxmox server."
|
|||
|
|
echo ""
|
|||
|
|
print_info "Target: nodito (Proxmox server)"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
if ! confirm_action "Continue with Layer 1B setup?"; then
|
|||
|
|
echo "Setup cancelled."
|
|||
|
|
exit 0
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
check_layer_0_complete
|
|||
|
|
check_nodito_configured
|
|||
|
|
|
|||
|
|
# Nodito Setup
|
|||
|
|
local setup_failed=false
|
|||
|
|
setup_nodito_bootstrap || setup_failed=true
|
|||
|
|
setup_nodito_community_repos || setup_failed=true
|
|||
|
|
setup_nodito_zfs || setup_failed=true
|
|||
|
|
setup_nodito_cloud_template || setup_failed=true
|
|||
|
|
|
|||
|
|
verify_layer_1b
|
|||
|
|
|
|||
|
|
if [ "$setup_failed" = true ]; then
|
|||
|
|
print_warning "Some optional steps were skipped - this is normal"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
print_summary
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Run main function
|
|||
|
|
main "$@"
|
|||
|
|
|