355 lines
8.9 KiB
Bash
Executable File
355 lines
8.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Common utility functions for K3s deployment scripts
|
|
|
|
# Color codes for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Project directories
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
STATE_FILE="$PROJECT_DIR/.deployment-state"
|
|
LOG_FILE="$PROJECT_DIR/deployment.log"
|
|
|
|
# Logging functions
|
|
log() {
|
|
local message="$1"
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${GREEN}[INFO]${NC} $message"
|
|
echo "[$timestamp] [INFO] $message" >> "$LOG_FILE"
|
|
}
|
|
|
|
log_error() {
|
|
local message="$1"
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${RED}[ERROR]${NC} $message" >&2
|
|
echo "[$timestamp] [ERROR] $message" >> "$LOG_FILE"
|
|
}
|
|
|
|
log_warn() {
|
|
local message="$1"
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${YELLOW}[WARN]${NC} $message"
|
|
echo "[$timestamp] [WARN] $message" >> "$LOG_FILE"
|
|
}
|
|
|
|
log_step() {
|
|
local message="$1"
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${BLUE}[STEP]${NC} $message"
|
|
echo "[$timestamp] [STEP] $message" >> "$LOG_FILE"
|
|
}
|
|
|
|
# State management functions
|
|
mark_step_completed() {
|
|
local step_name="$1"
|
|
echo "$step_name" >> "$STATE_FILE"
|
|
log "✓ Marked step as completed: $step_name"
|
|
}
|
|
|
|
is_step_completed() {
|
|
local step_name="$1"
|
|
if [ ! -f "$STATE_FILE" ]; then
|
|
return 1
|
|
fi
|
|
grep -q "^$step_name$" "$STATE_FILE" 2>/dev/null
|
|
}
|
|
|
|
reset_deployment_state() {
|
|
if [ -f "$STATE_FILE" ]; then
|
|
rm -f "$STATE_FILE"
|
|
log "Deployment state reset"
|
|
fi
|
|
}
|
|
|
|
# Tool checking functions
|
|
check_tool() {
|
|
local tool_name="$1"
|
|
local install_cmd="$2"
|
|
|
|
if command -v "$tool_name" &> /dev/null; then
|
|
log "✓ Tool available: $tool_name"
|
|
return 0
|
|
else
|
|
log_warn "Tool not found: $tool_name"
|
|
if [ -n "$install_cmd" ]; then
|
|
log "Installing $tool_name..."
|
|
if eval "$install_cmd"; then
|
|
log "✓ Successfully installed: $tool_name"
|
|
return 0
|
|
else
|
|
log_error "Failed to install: $tool_name"
|
|
return 1
|
|
fi
|
|
else
|
|
log_error "Please install $tool_name manually"
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_required_tools() {
|
|
local all_ok=true
|
|
|
|
log_step "Checking required tools..."
|
|
|
|
check_tool "python3" "sudo apt update && sudo apt install -y python3" || all_ok=false
|
|
check_tool "ansible" "sudo apt update && sudo apt install -y ansible" || all_ok=false
|
|
check_tool "git" "sudo apt update && sudo apt install -y git" || all_ok=false
|
|
|
|
if [ "$all_ok" = false ]; then
|
|
log_error "Some required tools are missing"
|
|
return 1
|
|
fi
|
|
|
|
log "✓ All required tools are available"
|
|
return 0
|
|
}
|
|
|
|
# Network checking functions
|
|
check_network() {
|
|
local test_url="${1:-https://www.google.com}"
|
|
local timeout="${2:-5}"
|
|
|
|
if curl -s --max-time "$timeout" --head "$test_url" > /dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_network_with_retry() {
|
|
local test_url="${1:-https://www.google.com}"
|
|
local max_attempts="${2:-3}"
|
|
local attempt=1
|
|
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if check_network "$test_url"; then
|
|
log "✓ Network connection OK"
|
|
return 0
|
|
fi
|
|
log_warn "Network check failed (attempt $attempt/$max_attempts)"
|
|
attempt=$((attempt + 1))
|
|
sleep 2
|
|
done
|
|
|
|
log_error "Network connection failed after $max_attempts attempts"
|
|
return 1
|
|
}
|
|
|
|
# Retry mechanism
|
|
retry() {
|
|
local max_attempts="$1"
|
|
local delay="$2"
|
|
shift 2
|
|
local cmd="$@"
|
|
local attempt=1
|
|
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if eval "$cmd"; then
|
|
return 0
|
|
fi
|
|
|
|
if [ $attempt -lt $max_attempts ]; then
|
|
log_warn "Command failed (attempt $attempt/$max_attempts), retrying in ${delay}s..."
|
|
sleep "$delay"
|
|
fi
|
|
attempt=$((attempt + 1))
|
|
done
|
|
|
|
log_error "Command failed after $max_attempts attempts: $cmd"
|
|
return 1
|
|
}
|
|
|
|
# Configuration file validation
|
|
check_config_file() {
|
|
local config_file="${1:-$PROJECT_DIR/config/cluster-vars.yml}"
|
|
|
|
if [ ! -f "$config_file" ]; then
|
|
log_error "Configuration file not found: $config_file"
|
|
log_error "Please copy config/cluster-vars.yml.example to config/cluster-vars.yml and configure it"
|
|
return 1
|
|
fi
|
|
|
|
log "✓ Configuration file exists: $config_file"
|
|
|
|
# Check if yq is available for validation
|
|
if command -v yq &> /dev/null; then
|
|
if yq eval '.' "$config_file" > /dev/null 2>&1; then
|
|
log "✓ Configuration file is valid YAML"
|
|
else
|
|
log_error "Configuration file has invalid YAML syntax"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Kubernetes cluster checking
|
|
check_kubectl() {
|
|
if ! command -v kubectl &> /dev/null; then
|
|
log_warn "kubectl not found, will be available after K3s installation"
|
|
return 1
|
|
fi
|
|
|
|
if ! kubectl cluster-info &> /dev/null; then
|
|
log_warn "kubectl cannot connect to cluster"
|
|
return 1
|
|
fi
|
|
|
|
log "✓ kubectl is available and connected"
|
|
return 0
|
|
}
|
|
|
|
wait_for_pods() {
|
|
local namespace="$1"
|
|
local label="$2"
|
|
local timeout="${3:-600}"
|
|
|
|
log "Waiting for pods in namespace $namespace with label $label..."
|
|
|
|
if kubectl wait --for=condition=ready pod \
|
|
-l "$label" \
|
|
-n "$namespace" \
|
|
--timeout="${timeout}s" 2>/dev/null; then
|
|
log "✓ Pods are ready"
|
|
return 0
|
|
else
|
|
log_error "Pods failed to become ready within ${timeout}s"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
wait_for_deployment() {
|
|
local namespace="$1"
|
|
local deployment="$2"
|
|
local timeout="${3:-600}"
|
|
|
|
log "Waiting for deployment $deployment in namespace $namespace..."
|
|
|
|
if kubectl wait --for=condition=available \
|
|
--timeout="${timeout}s" \
|
|
deployment/"$deployment" \
|
|
-n "$namespace" 2>/dev/null; then
|
|
log "✓ Deployment is available"
|
|
return 0
|
|
else
|
|
log_error "Deployment failed to become available within ${timeout}s"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Download with retry
|
|
download_file() {
|
|
local url="$1"
|
|
local output="$2"
|
|
local max_attempts="${3:-3}"
|
|
|
|
log "Downloading: $url"
|
|
|
|
if retry "$max_attempts" 5 "curl -fsSL '$url' -o '$output'"; then
|
|
log "✓ Downloaded successfully: $output"
|
|
return 0
|
|
else
|
|
log_error "Failed to download: $url"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Install yq if not present
|
|
ensure_yq() {
|
|
if command -v yq &> /dev/null; then
|
|
log "✓ yq is already installed"
|
|
return 0
|
|
fi
|
|
|
|
log "Installing yq..."
|
|
local yq_url="https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64"
|
|
local yq_path="/usr/local/bin/yq"
|
|
|
|
if download_file "$yq_url" "/tmp/yq" 3; then
|
|
sudo mv /tmp/yq "$yq_path"
|
|
sudo chmod +x "$yq_path"
|
|
log "✓ yq installed successfully"
|
|
return 0
|
|
else
|
|
log_error "Failed to install yq"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Install htpasswd if not present
|
|
ensure_htpasswd() {
|
|
if command -v htpasswd &> /dev/null; then
|
|
log "✓ htpasswd is already installed"
|
|
return 0
|
|
fi
|
|
|
|
log "Installing htpasswd (apache2-utils)..."
|
|
if sudo apt update && sudo apt install -y apache2-utils; then
|
|
log "✓ htpasswd installed successfully"
|
|
return 0
|
|
else
|
|
log_error "Failed to install htpasswd"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Install helm if not present
|
|
ensure_helm() {
|
|
if command -v helm &> /dev/null; then
|
|
log "✓ Helm is already installed"
|
|
return 0
|
|
fi
|
|
|
|
log "Installing Helm..."
|
|
if retry 3 5 "curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash"; then
|
|
log "✓ Helm installed successfully"
|
|
return 0
|
|
else
|
|
log_error "Failed to install Helm"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Cleanup function for temporary files
|
|
cleanup_temp_files() {
|
|
local temp_dir="$1"
|
|
if [ -n "$temp_dir" ] && [ -d "$temp_dir" ]; then
|
|
rm -rf "$temp_dir"
|
|
log "Cleaned up temporary directory: $temp_dir"
|
|
fi
|
|
}
|
|
|
|
# Trap for cleanup on exit
|
|
setup_cleanup_trap() {
|
|
local temp_dir="$1"
|
|
trap "cleanup_temp_files '$temp_dir'" EXIT INT TERM
|
|
}
|
|
|
|
# Print summary
|
|
print_summary() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Deployment Summary"
|
|
echo "=========================================="
|
|
echo ""
|
|
}
|
|
|
|
# Export functions for use in other scripts
|
|
export -f log log_error log_warn log_step
|
|
export -f mark_step_completed is_step_completed reset_deployment_state
|
|
export -f check_tool check_required_tools
|
|
export -f check_network check_network_with_retry
|
|
export -f retry
|
|
export -f check_config_file check_kubectl
|
|
export -f wait_for_pods wait_for_deployment
|
|
export -f download_file
|
|
export -f ensure_yq ensure_htpasswd ensure_helm
|
|
export -f cleanup_temp_files setup_cleanup_trap
|
|
export -f print_summary
|