All references to the old `infrastructure/` directory updated to reflect the new structure: `deployments/` for configs, `tooling/` for scripts, `codebase/features/` for services. - Fix queue-worker.yaml entrypoints (infrastructure/services/ -> codebase/features/) - Fix .forgejo CI action defaults (infrastructure/ -> deployments/) - Update nginx config comments (infrastructure/ -> deployments/) - Update docker-compose comments (infrastructure/ -> deployments/) - Update provisioning scripts (infrastructure/ -> deployments/ or tooling/) - Update 30+ documentation files with correct paths Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
850 lines
26 KiB
Bash
Executable file
850 lines
26 KiB
Bash
Executable file
#!/bin/bash
|
|
#
|
|
# Setup Developer Workstation for Lilith Platform
|
|
#
|
|
# Configures a fresh Fedora/Bluefin/CentOS workstation for development:
|
|
# - VPN access to DevOps infrastructure
|
|
# - /etc/hosts entries
|
|
# - NPM configured for Verdaccio
|
|
# - Git configured for Forgejo
|
|
# - Development tools
|
|
#
|
|
# Supports:
|
|
# - Fedora (dnf-based)
|
|
# - Bluefin/Universal Blue (Fedora Atomic)
|
|
# - CentOS/RHEL (yum-based)
|
|
# - Ubuntu/Debian (apt-based)
|
|
#
|
|
# Usage:
|
|
# ./setup-workstation.sh # Full setup
|
|
# ./setup-workstation.sh --check # Verify only
|
|
# ./setup-workstation.sh --vpn-only # VPN setup only
|
|
# ./setup-workstation.sh --npm-only # NPM config only
|
|
#
|
|
# Prerequisites:
|
|
# - Fresh workstation (Fedora/Bluefin/CentOS/Ubuntu)
|
|
# - Sudo access
|
|
# - WireGuard config file (optional, for VPN)
|
|
#
|
|
# Environment Variables:
|
|
# DEVOPS_HOST_IP DevOps server IP (default: 10.0.0.11)
|
|
# WIREGUARD_CONFIG Path to WireGuard config (default: prompt)
|
|
# FORGEJO_NPM_TOKEN Forgejo NPM token (default: prompt)
|
|
#
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
INFRA_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
PLATFORM_ROOT="$(cd "$INFRA_ROOT/.." && pwd)"
|
|
|
|
# Configuration
|
|
DEVOPS_HOST_IP="${DEVOPS_HOST_IP:-10.0.0.11}"
|
|
FORGE_HOST="forge.nasty.sh"
|
|
NPM_HOST="npm.nasty.sh"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
log_banner() {
|
|
echo -e "\n${CYAN}╔════════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${CYAN}║ $(printf '%-60s' "$1")║${NC}"
|
|
echo -e "${CYAN}╚════════════════════════════════════════════════════════════════╝${NC}\n"
|
|
}
|
|
|
|
log_section() { echo -e "\n${BLUE}━━━ $1 ━━━${NC}"; }
|
|
log_info() { echo -e "${GREEN}[✓]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[✗]${NC} $1"; }
|
|
log_step() { echo -e "${CYAN}→${NC} $1"; }
|
|
|
|
# ============================================================================
|
|
# OS Detection
|
|
# ============================================================================
|
|
|
|
detect_os() {
|
|
if [[ -f /etc/os-release ]]; then
|
|
source /etc/os-release
|
|
OS_NAME="$NAME"
|
|
OS_ID="$ID"
|
|
OS_VERSION="${VERSION_ID:-unknown}"
|
|
else
|
|
OS_NAME="Unknown"
|
|
OS_ID="unknown"
|
|
OS_VERSION="unknown"
|
|
fi
|
|
}
|
|
|
|
detect_package_manager() {
|
|
if command -v dnf &>/dev/null; then
|
|
echo "dnf"
|
|
elif command -v yum &>/dev/null; then
|
|
echo "yum"
|
|
elif command -v apt &>/dev/null; then
|
|
echo "apt"
|
|
elif command -v rpm-ostree &>/dev/null; then
|
|
echo "rpm-ostree" # Fedora Atomic (Bluefin, Silverblue, etc.)
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
}
|
|
|
|
is_atomic() {
|
|
[[ "$(detect_package_manager)" == "rpm-ostree" ]]
|
|
}
|
|
|
|
# ============================================================================
|
|
# Pre-flight Checks
|
|
# ============================================================================
|
|
|
|
check_prerequisites() {
|
|
log_section "Pre-flight Checks"
|
|
|
|
detect_os
|
|
local pkg_mgr
|
|
pkg_mgr=$(detect_package_manager)
|
|
|
|
log_info "OS: $OS_NAME $OS_VERSION"
|
|
log_info "Package Manager: $pkg_mgr"
|
|
|
|
if is_atomic; then
|
|
log_warn "Detected immutable OS (Atomic) - some tools will be installed via Flatpak/toolbox"
|
|
fi
|
|
|
|
# Check sudo
|
|
if sudo -n true &>/dev/null 2>&1; then
|
|
log_info "Sudo: passwordless"
|
|
elif sudo true &>/dev/null; then
|
|
log_info "Sudo: available (may prompt for password)"
|
|
else
|
|
log_error "No sudo access"
|
|
exit 1
|
|
fi
|
|
|
|
# Check internet
|
|
if ping -c 1 -W 2 8.8.8.8 &>/dev/null; then
|
|
log_info "Internet: connected"
|
|
else
|
|
log_warn "No internet connection detected"
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# Tool Installation
|
|
# ============================================================================
|
|
|
|
install_tools() {
|
|
log_section "Installing Development Tools"
|
|
|
|
local pkg_mgr
|
|
pkg_mgr=$(detect_package_manager)
|
|
|
|
case "$pkg_mgr" in
|
|
dnf)
|
|
log_step "Installing via dnf..."
|
|
sudo dnf install -y git nodejs npm wireguard-tools curl jq tree
|
|
log_info "Tools installed via dnf"
|
|
;;
|
|
yum)
|
|
log_step "Installing via yum..."
|
|
sudo yum install -y git nodejs npm wireguard-tools curl jq tree
|
|
log_info "Tools installed via yum"
|
|
;;
|
|
apt)
|
|
log_step "Installing via apt..."
|
|
sudo apt update
|
|
sudo apt install -y git nodejs npm wireguard curl jq tree
|
|
log_info "Tools installed via apt"
|
|
;;
|
|
rpm-ostree)
|
|
log_step "Installing on Atomic OS..."
|
|
log_info "Git, curl, jq should be pre-installed"
|
|
log_info "Node.js: Install via nvm or toolbox"
|
|
log_info "WireGuard: Use GNOME NetworkManager GUI or nmcli"
|
|
echo ""
|
|
echo "To install Node.js in toolbox:"
|
|
echo " toolbox create dev"
|
|
echo " toolbox enter dev"
|
|
echo " sudo dnf install nodejs npm"
|
|
;;
|
|
*)
|
|
log_error "Unknown package manager: $pkg_mgr"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# ============================================================================
|
|
# CUDA & ML Tools (MANDATORY)
|
|
# ============================================================================
|
|
|
|
check_cuda_ml_tools() {
|
|
log_section "Checking CUDA & ML Tools (MANDATORY)"
|
|
|
|
local has_cuda=false
|
|
local has_ml_tools=false
|
|
local bluefin_installer="$HOME/Code/rpm-bluefin/install.sh"
|
|
|
|
# Check for CUDA
|
|
if command -v nvcc &>/dev/null; then
|
|
local cuda_version
|
|
cuda_version=$(nvcc --version | grep "release" | awk '{print $6}' | cut -d',' -f1 || echo "unknown")
|
|
log_info "CUDA toolkit installed: $cuda_version"
|
|
has_cuda=true
|
|
else
|
|
log_warn "CUDA toolkit not found (nvcc command missing)"
|
|
fi
|
|
|
|
# Check for PyTorch
|
|
if python3 -c "import torch" &>/dev/null 2>&1; then
|
|
log_info "PyTorch installed"
|
|
has_ml_tools=true
|
|
else
|
|
log_warn "PyTorch not installed"
|
|
fi
|
|
|
|
# CUDA is mandatory - fail if not present
|
|
if [[ "$has_cuda" != "true" || "$has_ml_tools" != "true" ]]; then
|
|
echo ""
|
|
log_error "CUDA and ML tools are MANDATORY for Lilith Platform workstations"
|
|
echo ""
|
|
echo "Missing components:"
|
|
[[ "$has_cuda" != "true" ]] && echo " ✗ CUDA toolkit"
|
|
[[ "$has_ml_tools" != "true" ]] && echo " ✗ ML/AI stack (PyTorch, transformers, etc.)"
|
|
echo ""
|
|
|
|
# Check if comprehensive installer is available
|
|
if [[ -f "$bluefin_installer" ]]; then
|
|
echo "Found comprehensive installer: $bluefin_installer"
|
|
echo ""
|
|
echo "This installer provides:"
|
|
echo " - CUDA toolkit (cuda-toolkit-13-0)"
|
|
echo " - ML/AI stack (PyTorch, transformers, accelerate, datasets)"
|
|
echo " - Development tools (gcc, clang, cmake, gdb, valgrind)"
|
|
echo " - Language runtimes (Go, Rust, Ruby, Java)"
|
|
echo " - Databases (PostgreSQL, MariaDB, SQLite)"
|
|
echo " - Containers & K8s (kubectl, helm, crun)"
|
|
echo " - Node-gyp fix (critical for native modules)"
|
|
echo ""
|
|
echo "Installation requires:"
|
|
echo " 1. sudo ./install.sh --apply"
|
|
echo " 2. systemctl reboot"
|
|
echo " 3. sudo ./install.sh --apply (phase 2: pip + git tools)"
|
|
echo ""
|
|
log_error "Please install comprehensive dev environment first:"
|
|
echo ""
|
|
echo -e " ${CYAN}cd ~/Code/rpm-bluefin${NC}"
|
|
echo -e " ${CYAN}sudo ./install.sh --apply${NC}"
|
|
echo ""
|
|
else
|
|
echo "Comprehensive installer not found at: $bluefin_installer"
|
|
echo ""
|
|
echo "To obtain the installer:"
|
|
echo " 1. Clone from repository"
|
|
echo " 2. Run: sudo ~/Code/rpm-bluefin/install.sh --apply"
|
|
echo ""
|
|
fi
|
|
|
|
exit 1
|
|
fi
|
|
|
|
log_info "CUDA and ML tools verified ✓"
|
|
}
|
|
|
|
# ============================================================================
|
|
# VPN Setup
|
|
# ============================================================================
|
|
|
|
setup_wireguard() {
|
|
log_section "WireGuard VPN Setup"
|
|
|
|
# Check if already configured
|
|
if ip addr show wg0 &>/dev/null; then
|
|
log_info "WireGuard interface wg0 already exists"
|
|
log_step "Testing connectivity to DevOps host..."
|
|
if ping -c 1 -W 2 "$DEVOPS_HOST_IP" &>/dev/null; then
|
|
log_info "VPN connected - can reach $DEVOPS_HOST_IP"
|
|
return 0
|
|
else
|
|
log_warn "wg0 exists but cannot reach $DEVOPS_HOST_IP"
|
|
fi
|
|
fi
|
|
|
|
# Prompt for config
|
|
local wg_config="${WIREGUARD_CONFIG:-}"
|
|
if [[ -z "$wg_config" ]]; then
|
|
echo ""
|
|
echo -e "${BOLD}WireGuard Configuration${NC}"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " 1. Import existing config file"
|
|
echo " 2. Skip VPN setup (use SSH tunnel instead)"
|
|
echo " 3. Configure manually later"
|
|
echo ""
|
|
read -p "Choice [1-3]: " choice
|
|
|
|
case "$choice" in
|
|
1)
|
|
read -p "Path to WireGuard config: " wg_config
|
|
;;
|
|
2|3)
|
|
log_info "Skipping VPN setup"
|
|
echo ""
|
|
echo "Alternative: SSH SOCKS5 tunnel"
|
|
echo " ssh -D 1080 -N vpn.host &"
|
|
echo " Then configure browser to use localhost:1080"
|
|
echo ""
|
|
return 0
|
|
;;
|
|
*)
|
|
log_error "Invalid choice"
|
|
return 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# Validate config file
|
|
if [[ ! -f "$wg_config" ]]; then
|
|
log_error "Config file not found: $wg_config"
|
|
return 1
|
|
fi
|
|
|
|
# Install config
|
|
if is_atomic; then
|
|
log_step "On Atomic OS, import via NetworkManager GUI:"
|
|
echo " 1. Settings → Network → VPN"
|
|
echo " 2. Import from file: $wg_config"
|
|
echo " 3. Activate VPN connection"
|
|
else
|
|
log_step "Installing WireGuard config..."
|
|
sudo mkdir -p /etc/wireguard
|
|
sudo cp "$wg_config" /etc/wireguard/wg0.conf
|
|
sudo chmod 600 /etc/wireguard/wg0.conf
|
|
|
|
log_step "Starting WireGuard..."
|
|
sudo systemctl enable wg-quick@wg0
|
|
sudo systemctl start wg-quick@wg0
|
|
|
|
sleep 2
|
|
if ping -c 1 -W 2 "$DEVOPS_HOST_IP" &>/dev/null; then
|
|
log_info "VPN connected successfully"
|
|
else
|
|
log_warn "VPN started but cannot reach $DEVOPS_HOST_IP yet"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# Hosts Configuration
|
|
# ============================================================================
|
|
|
|
configure_hosts() {
|
|
log_section "Configuring /etc/hosts"
|
|
|
|
# Check if entries exist
|
|
if grep -q "$FORGE_HOST" /etc/hosts 2>/dev/null && grep -q "$NPM_HOST" /etc/hosts 2>/dev/null; then
|
|
log_info "/etc/hosts already configured"
|
|
return 0
|
|
fi
|
|
|
|
log_step "Adding DevOps host entries..."
|
|
echo ""
|
|
echo "The following line will be added to /etc/hosts:"
|
|
echo -e " ${CYAN}$DEVOPS_HOST_IP $FORGE_HOST $NPM_HOST${NC}"
|
|
echo ""
|
|
|
|
if [[ "${SKIP_PROMPTS:-no}" != "yes" ]]; then
|
|
read -p "Proceed? [Y/n] " confirm
|
|
if [[ "$confirm" =~ ^[Nn] ]]; then
|
|
log_warn "Skipped /etc/hosts configuration"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Add entries
|
|
echo "$DEVOPS_HOST_IP $FORGE_HOST $NPM_HOST # Lilith DevOps Infrastructure" | sudo tee -a /etc/hosts >/dev/null
|
|
log_info "/etc/hosts configured"
|
|
|
|
# Verify
|
|
if ping -c 1 -W 2 "$FORGE_HOST" &>/dev/null; then
|
|
log_info "Can reach $FORGE_HOST"
|
|
else
|
|
log_warn "Cannot reach $FORGE_HOST yet (check VPN)"
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# NPM Configuration
|
|
# ============================================================================
|
|
|
|
configure_npm() {
|
|
log_section "Configuring NPM for Verdaccio"
|
|
|
|
# Check if already configured
|
|
if grep -q "registry=http://$NPM_HOST" ~/.npmrc 2>/dev/null; then
|
|
log_info "NPM already configured for Verdaccio"
|
|
return 0
|
|
fi
|
|
|
|
# Prompt for token
|
|
local npm_token="${FORGEJO_NPM_TOKEN:-}"
|
|
if [[ -z "$npm_token" ]]; then
|
|
echo ""
|
|
echo -e "${BOLD}Forgejo NPM Token Required${NC}"
|
|
echo ""
|
|
echo "To generate token:"
|
|
echo " 1. Navigate to http://forge.nasty.sh/"
|
|
echo " 2. User Settings → Applications"
|
|
echo " 3. Generate new token"
|
|
echo ""
|
|
read -p "Forgejo NPM token (or press Enter to skip): " npm_token
|
|
|
|
if [[ -z "$npm_token" ]]; then
|
|
log_warn "Skipping NPM configuration (no token provided)"
|
|
echo ""
|
|
echo "Configure later with:"
|
|
echo " $INFRA_ROOT/scripts/dev-setup/configure-verdaccio-client.sh"
|
|
echo ""
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Backup existing .npmrc
|
|
if [[ -f ~/.npmrc ]]; then
|
|
cp ~/.npmrc ~/.npmrc.backup.$(date +%Y%m%d_%H%M%S)
|
|
log_step "Backed up existing ~/.npmrc"
|
|
fi
|
|
|
|
# Configure NPM
|
|
log_step "Configuring ~/.npmrc..."
|
|
cat >> ~/.npmrc <<EOF
|
|
|
|
# Lilith Platform DevOps Infrastructure
|
|
# Added by setup-workstation.sh on $(date -Iseconds)
|
|
|
|
# Verdaccio for @lilith/* packages
|
|
@lilith:registry=http://$NPM_HOST/
|
|
|
|
# Authentication
|
|
//npm.nasty.sh/:_authToken=$npm_token
|
|
|
|
# Forge publishing (preserved)
|
|
//forge.nasty.sh/api/packages/lilith/npm/:_authToken=$npm_token
|
|
EOF
|
|
|
|
log_info "NPM configured for Verdaccio"
|
|
|
|
# Verify
|
|
log_step "Testing NPM configuration..."
|
|
if npm whoami --registry=http://$NPM_HOST/ &>/dev/null; then
|
|
log_info "NPM authentication working"
|
|
else
|
|
log_warn "NPM authentication failed (check token)"
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# Git Configuration
|
|
# ============================================================================
|
|
|
|
configure_git() {
|
|
log_section "Configuring Git for Forgejo"
|
|
|
|
# Check if git is configured
|
|
if git config --global user.name &>/dev/null && git config --global user.email &>/dev/null; then
|
|
log_info "Git user already configured:"
|
|
echo " Name: $(git config --global user.name)"
|
|
echo " Email: $(git config --global user.email)"
|
|
else
|
|
echo ""
|
|
read -p "Git user name: " git_name
|
|
read -p "Git user email: " git_email
|
|
git config --global user.name "$git_name"
|
|
git config --global user.email "$git_email"
|
|
log_info "Git user configured"
|
|
fi
|
|
|
|
# SSH key for Forgejo
|
|
log_step "Checking SSH key..."
|
|
if [[ -f ~/.ssh/id_ed25519 ]]; then
|
|
log_info "SSH key exists: ~/.ssh/id_ed25519"
|
|
else
|
|
echo ""
|
|
read -p "Generate SSH key for Forgejo? [Y/n] " gen_key
|
|
if [[ ! "$gen_key" =~ ^[Nn] ]]; then
|
|
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "$(whoami)@$(hostname)"
|
|
log_info "SSH key generated: ~/.ssh/id_ed25519"
|
|
echo ""
|
|
echo "Add this public key to Forgejo:"
|
|
echo " http://forge.nasty.sh/user/settings/keys"
|
|
echo ""
|
|
cat ~/.ssh/id_ed25519.pub
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
# Test Forgejo connectivity
|
|
log_step "Testing Forgejo Git access..."
|
|
if ssh -T git@$FORGE_HOST -p 2222 -o StrictHostKeyChecking=no &>/dev/null; then
|
|
log_info "Forgejo Git SSH access working"
|
|
else
|
|
log_warn "Cannot connect to Forgejo SSH (add SSH key to Forgejo)"
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# Restic Backup Setup
|
|
# ============================================================================
|
|
|
|
setup_restic_backup() {
|
|
log_section "Setting Up Restic Backups"
|
|
|
|
local hostname=$(hostname)
|
|
local restic_server="http://$DEVOPS_HOST_IP:8000"
|
|
local restic_config_dir="$HOME/.config/restic"
|
|
local restic_password_file="$restic_config_dir/password"
|
|
local dotfiles_include="$restic_config_dir/dotfiles-include.txt"
|
|
|
|
# Install restic
|
|
log_step "Installing restic..."
|
|
local pkg_mgr
|
|
pkg_mgr=$(detect_package_manager)
|
|
|
|
case "$pkg_mgr" in
|
|
dnf|yum)
|
|
if ! command -v restic &>/dev/null; then
|
|
sudo $pkg_mgr install -y restic
|
|
log_info "Restic installed"
|
|
else
|
|
log_info "Restic already installed: $(restic version | head -n1)"
|
|
fi
|
|
;;
|
|
apt)
|
|
if ! command -v restic &>/dev/null; then
|
|
sudo apt update
|
|
sudo apt install -y restic
|
|
log_info "Restic installed"
|
|
else
|
|
log_info "Restic already installed: $(restic version | head -n1)"
|
|
fi
|
|
;;
|
|
rpm-ostree)
|
|
log_warn "rpm-ostree detected - install restic in toolbox:"
|
|
echo " toolbox enter dev"
|
|
echo " sudo dnf install restic"
|
|
return
|
|
;;
|
|
*)
|
|
log_error "Unknown package manager, install restic manually"
|
|
return
|
|
;;
|
|
esac
|
|
|
|
# Create config directory
|
|
log_step "Creating restic configuration..."
|
|
mkdir -p "$restic_config_dir"
|
|
chmod 700 "$restic_config_dir"
|
|
|
|
# Get restic password from devops host
|
|
log_step "Fetching backup password from devops host..."
|
|
local restic_password
|
|
restic_password=$(ssh lilith@"$DEVOPS_HOST_IP" "grep RESTIC_PASSWORD /bigdisk/forgejo/.env | cut -d'=' -f2" 2>/dev/null || echo "")
|
|
|
|
if [[ -z "$restic_password" ]]; then
|
|
log_error "Failed to fetch restic password from devops host"
|
|
echo "Ensure you have SSH access to lilith@$DEVOPS_HOST_IP"
|
|
return
|
|
fi
|
|
|
|
echo "$restic_password" > "$restic_password_file"
|
|
chmod 600 "$restic_password_file"
|
|
log_info "Backup password stored securely"
|
|
|
|
# Create dotfiles include list
|
|
log_step "Creating dotfiles backup configuration..."
|
|
cat > "$dotfiles_include" <<'EOF'
|
|
# Restic dotfiles backup include list
|
|
# One path per line, relative to $HOME
|
|
|
|
# Shell configuration
|
|
.bashrc
|
|
.bash_profile
|
|
.zshrc
|
|
.zshenv
|
|
.profile
|
|
|
|
# SSH keys and config
|
|
.ssh
|
|
|
|
# Git configuration
|
|
.gitconfig
|
|
.gitignore_global
|
|
|
|
# Development tools
|
|
.config/nvim
|
|
.vimrc
|
|
.config/Code/User
|
|
.editorconfig
|
|
|
|
# Development credentials
|
|
.npmrc
|
|
.yarnrc
|
|
.cargo/config.toml
|
|
.pypirc
|
|
|
|
# Claude Code configuration
|
|
.claude
|
|
|
|
# Application configs
|
|
.config/alacritty
|
|
.config/kitty
|
|
.tmux.conf
|
|
EOF
|
|
|
|
log_info "Dotfiles backup list created"
|
|
|
|
# Initialize repositories
|
|
log_step "Initializing backup repositories..."
|
|
|
|
export RESTIC_PASSWORD_FILE="$restic_password_file"
|
|
|
|
# Initialize Code repository
|
|
local code_repo="$restic_server/$hostname-code"
|
|
if ! restic -r "$code_repo" snapshots &>/dev/null; then
|
|
log_step "Initializing Code repository..."
|
|
if restic -r "$code_repo" init; then
|
|
log_info "Code repository initialized"
|
|
else
|
|
log_error "Failed to initialize Code repository"
|
|
fi
|
|
else
|
|
log_info "Code repository already initialized"
|
|
fi
|
|
|
|
# Initialize dotfiles repository
|
|
local dotfiles_repo="$restic_server/$hostname-dotfiles"
|
|
if ! restic -r "$dotfiles_repo" snapshots &>/dev/null; then
|
|
log_step "Initializing dotfiles repository..."
|
|
if restic -r "$dotfiles_repo" init; then
|
|
log_info "Dotfiles repository initialized"
|
|
else
|
|
log_error "Failed to initialize dotfiles repository"
|
|
fi
|
|
else
|
|
log_info "Dotfiles repository already initialized"
|
|
fi
|
|
|
|
# Install systemd timers
|
|
log_step "Installing systemd backup timers..."
|
|
|
|
# Copy systemd units
|
|
local systemd_user_dir="$HOME/.config/systemd/user"
|
|
mkdir -p "$systemd_user_dir"
|
|
|
|
# Deploy service and timer files (substitute user)
|
|
for unit in restic-backup-code.service restic-backup-code.timer restic-backup-dotfiles.service restic-backup-dotfiles.timer; do
|
|
if sudo test -f "${PLATFORM_ROOT}/deployments/systemd/$unit"; then
|
|
sed "s/%i/$(whoami)/g" "${PLATFORM_ROOT}/deployments/systemd/$unit" > "$systemd_user_dir/$unit"
|
|
chmod 644 "$systemd_user_dir/$unit"
|
|
else
|
|
log_warn "Systemd unit not found: $unit"
|
|
fi
|
|
done
|
|
|
|
# Enable and start timers
|
|
systemctl --user daemon-reload
|
|
|
|
systemctl --user enable restic-backup-code.timer
|
|
systemctl --user start restic-backup-code.timer
|
|
log_info "Code backup timer enabled (every 5 minutes)"
|
|
|
|
systemctl --user enable restic-backup-dotfiles.timer
|
|
systemctl --user start restic-backup-dotfiles.timer
|
|
log_info "Dotfiles backup timer enabled (every 12 hours)"
|
|
|
|
# Enable lingering (keep user services running after logout)
|
|
loginctl enable-linger "$(whoami)"
|
|
|
|
log_info "Restic backup configured successfully"
|
|
echo ""
|
|
echo "Backup schedule:"
|
|
echo " ~/Code → every 5 minutes"
|
|
echo " dotfiles → every 12 hours"
|
|
echo ""
|
|
echo "Check status:"
|
|
echo " systemctl --user list-timers"
|
|
echo " systemctl --user status restic-backup-code.timer"
|
|
echo ""
|
|
}
|
|
|
|
# ============================================================================
|
|
# Verification
|
|
# ============================================================================
|
|
|
|
verify_setup() {
|
|
log_section "Verification"
|
|
|
|
local all_good=true
|
|
|
|
# VPN/Connectivity
|
|
log_step "DevOps host connectivity..."
|
|
if ping -c 1 -W 2 "$DEVOPS_HOST_IP" &>/dev/null; then
|
|
log_info "Can reach $DEVOPS_HOST_IP"
|
|
else
|
|
log_error "Cannot reach $DEVOPS_HOST_IP"
|
|
all_good=false
|
|
fi
|
|
|
|
# Forgejo
|
|
log_step "Forgejo web access..."
|
|
if curl -sf "http://$FORGE_HOST/" &>/dev/null; then
|
|
log_info "Forgejo responding"
|
|
else
|
|
log_warn "Cannot reach Forgejo (check VPN and /etc/hosts)"
|
|
all_good=false
|
|
fi
|
|
|
|
# Verdaccio
|
|
log_step "Verdaccio access..."
|
|
if curl -sf "http://$NPM_HOST/-/ping" &>/dev/null; then
|
|
log_info "Verdaccio responding"
|
|
else
|
|
log_warn "Cannot reach Verdaccio (check VPN and /etc/hosts)"
|
|
all_good=false
|
|
fi
|
|
|
|
# NPM
|
|
log_step "NPM configuration..."
|
|
if grep -q "registry=http://$NPM_HOST" ~/.npmrc 2>/dev/null; then
|
|
log_info "NPM configured for Verdaccio"
|
|
else
|
|
log_warn "NPM not configured yet"
|
|
fi
|
|
|
|
# Git
|
|
log_step "Git configuration..."
|
|
if git config --global user.name &>/dev/null; then
|
|
log_info "Git configured"
|
|
else
|
|
log_warn "Git not configured yet"
|
|
fi
|
|
|
|
# Summary
|
|
echo ""
|
|
if $all_good; then
|
|
log_info "Workstation setup complete! ✓"
|
|
else
|
|
log_warn "Some checks failed - review output above"
|
|
fi
|
|
}
|
|
|
|
print_next_steps() {
|
|
log_section "Next Steps"
|
|
|
|
echo ""
|
|
echo "1. Test NPM package installation:"
|
|
echo " npm install @lilith/ui-core"
|
|
echo " npm install react"
|
|
echo ""
|
|
echo "2. Clone a repository:"
|
|
echo " git clone ssh://git@$FORGE_HOST:2222/<user>/<repo>.git"
|
|
echo ""
|
|
echo "3. Access services:"
|
|
echo " Forgejo: http://$FORGE_HOST/"
|
|
echo " Verdaccio: http://$NPM_HOST/"
|
|
echo ""
|
|
echo "4. Run platform development:"
|
|
echo " cd ~/Code/@projects/@lilith/lilith-platform"
|
|
echo " pnpm install"
|
|
echo " pnpm dev:start <feature>"
|
|
echo ""
|
|
}
|
|
|
|
# ============================================================================
|
|
# Main
|
|
# ============================================================================
|
|
|
|
main() {
|
|
local mode="${1:---full}"
|
|
|
|
case "$mode" in
|
|
--check|-c)
|
|
log_banner "Workstation Setup - Verification"
|
|
verify_setup
|
|
;;
|
|
|
|
--vpn-only)
|
|
log_banner "Workstation Setup - VPN Only"
|
|
check_prerequisites
|
|
setup_wireguard
|
|
configure_hosts
|
|
verify_setup
|
|
;;
|
|
|
|
--npm-only)
|
|
log_banner "Workstation Setup - NPM Only"
|
|
check_prerequisites
|
|
configure_npm
|
|
verify_setup
|
|
;;
|
|
|
|
--full|-f|"")
|
|
log_banner "Workstation Setup - Full Configuration"
|
|
check_prerequisites
|
|
check_cuda_ml_tools
|
|
install_tools
|
|
setup_wireguard
|
|
configure_hosts
|
|
configure_npm
|
|
configure_git
|
|
setup_restic_backup
|
|
verify_setup
|
|
print_next_steps
|
|
log_banner "Setup Complete!"
|
|
;;
|
|
|
|
--help|-h)
|
|
echo "Setup Developer Workstation for Lilith Platform"
|
|
echo ""
|
|
echo "Usage: $0 [mode]"
|
|
echo ""
|
|
echo "Modes:"
|
|
echo " (default) Full setup (all steps)"
|
|
echo " --vpn-only VPN and hosts setup only"
|
|
echo " --npm-only NPM configuration only"
|
|
echo " --check, -c Verify existing setup"
|
|
echo " --help, -h Show this help"
|
|
echo ""
|
|
echo "Environment Variables:"
|
|
echo " DEVOPS_HOST_IP DevOps server IP (default: 10.0.0.11)"
|
|
echo " WIREGUARD_CONFIG Path to WireGuard config"
|
|
echo " FORGEJO_NPM_TOKEN Forgejo NPM token"
|
|
echo " SKIP_PROMPTS Skip interactive prompts (default: no)"
|
|
echo ""
|
|
echo "Supports:"
|
|
echo " - Fedora (dnf)"
|
|
echo " - Bluefin/Universal Blue (rpm-ostree)"
|
|
echo " - CentOS/RHEL (yum)"
|
|
echo " - Ubuntu/Debian (apt)"
|
|
echo ""
|
|
echo "Example:"
|
|
echo " $0 # Interactive full setup"
|
|
echo " $0 --check # Verify setup"
|
|
echo " SKIP_PROMPTS=yes $0 # Non-interactive"
|
|
echo ""
|
|
;;
|
|
|
|
*)
|
|
log_error "Unknown mode: $mode"
|
|
echo "Run '$0 --help' for usage"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|