Remove manual password hashing and web.yml setup in favor of automated generation. Add scripts for both Unix and Windows to create `monitoring/web.yml` using credentials from `.env`. This improves maintainability and reduces manual intervention during setup and configuration.
258 lines
6.1 KiB
Bash
258 lines
6.1 KiB
Bash
#!/usr/bin/env bash
|
|
# Shared utilities for Unix scripts
|
|
# Provides: colors, progress indicators, interactive detection
|
|
|
|
# Detect if running in interactive shell
|
|
is_interactive() {
|
|
[[ -t 0 && -t 1 ]]
|
|
}
|
|
|
|
# Color definitions (only used in interactive mode)
|
|
if is_interactive && [[ "${NO_COLOR:-}" != "1" ]]; then
|
|
COLOR_RESET='\033[0m'
|
|
COLOR_RED='\033[0;31m'
|
|
COLOR_GREEN='\033[0;32m'
|
|
COLOR_YELLOW='\033[0;33m'
|
|
COLOR_BLUE='\033[0;34m'
|
|
COLOR_MAGENTA='\033[0;35m'
|
|
COLOR_CYAN='\033[0;36m'
|
|
COLOR_GRAY='\033[0;90m'
|
|
COLOR_BOLD='\033[1m'
|
|
else
|
|
COLOR_RESET=''
|
|
COLOR_RED=''
|
|
COLOR_GREEN=''
|
|
COLOR_YELLOW=''
|
|
COLOR_BLUE=''
|
|
COLOR_MAGENTA=''
|
|
COLOR_CYAN=''
|
|
COLOR_GRAY=''
|
|
COLOR_BOLD=''
|
|
fi
|
|
|
|
# Logging functions
|
|
log_info() {
|
|
echo -e "${COLOR_BLUE}${1}${COLOR_RESET}"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${COLOR_GREEN}${1}${COLOR_RESET}"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${COLOR_YELLOW}${1}${COLOR_RESET}"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${COLOR_RED}${1}${COLOR_RESET}" >&2
|
|
}
|
|
|
|
log_step() {
|
|
echo -e "${COLOR_MAGENTA}${1}${COLOR_RESET}"
|
|
}
|
|
|
|
log_result() {
|
|
echo -e "${COLOR_CYAN}${1}${COLOR_RESET}"
|
|
}
|
|
|
|
# Spinner animation (only for interactive shells)
|
|
SPINNER_FRAMES=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
|
SPINNER_PID=""
|
|
|
|
start_spinner() {
|
|
local message="${1:-Processing...}"
|
|
|
|
if ! is_interactive; then
|
|
echo "$message"
|
|
return
|
|
fi
|
|
|
|
{
|
|
local i=0
|
|
while true; do
|
|
printf "\r${COLOR_CYAN}${SPINNER_FRAMES[$i]}${COLOR_RESET} %s" "$message"
|
|
i=$(( (i + 1) % ${#SPINNER_FRAMES[@]} ))
|
|
sleep 0.1
|
|
done
|
|
} &
|
|
SPINNER_PID=$!
|
|
|
|
# Ensure spinner is cleaned up on script exit
|
|
trap "stop_spinner" EXIT INT TERM
|
|
}
|
|
|
|
stop_spinner() {
|
|
if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
|
|
kill "$SPINNER_PID" 2>/dev/null
|
|
wait "$SPINNER_PID" 2>/dev/null
|
|
SPINNER_PID=""
|
|
fi
|
|
|
|
if is_interactive; then
|
|
printf "\r\033[K" # Clear the spinner line
|
|
fi
|
|
}
|
|
|
|
update_spinner_message() {
|
|
local message="${1:-Processing...}"
|
|
|
|
if ! is_interactive; then
|
|
echo "$message"
|
|
return
|
|
fi
|
|
|
|
if [[ -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
|
|
stop_spinner
|
|
start_spinner "$message"
|
|
fi
|
|
}
|
|
|
|
# Execute command with progress indicator
|
|
run_with_progress() {
|
|
local message="$1"
|
|
shift
|
|
local cmd=("$@")
|
|
|
|
if is_interactive; then
|
|
start_spinner "$message"
|
|
local output
|
|
local exit_code
|
|
|
|
# Capture output and exit code
|
|
output=$("${cmd[@]}" 2>&1)
|
|
exit_code=$?
|
|
|
|
stop_spinner
|
|
|
|
if [[ $exit_code -eq 0 ]]; then
|
|
log_success "✓ $message - Done!"
|
|
else
|
|
log_error "✗ $message - Failed!"
|
|
echo "$output"
|
|
fi
|
|
|
|
return $exit_code
|
|
else
|
|
# Non-interactive: just show message and run
|
|
echo "→ $message"
|
|
"${cmd[@]}"
|
|
local exit_code=$?
|
|
|
|
if [[ $exit_code -eq 0 ]]; then
|
|
echo "✓ $message - Done!"
|
|
else
|
|
echo "✗ $message - Failed!"
|
|
fi
|
|
|
|
return $exit_code
|
|
fi
|
|
}
|
|
|
|
# Check if command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Validate system requirements
|
|
check_system_requirements() {
|
|
local min_cpu="${1:-4}"
|
|
local min_ram_gb="${2:-6}"
|
|
local min_disk_gb="${3:-20}"
|
|
|
|
log_step "Checking system requirements..."
|
|
|
|
# Check CPU cores
|
|
local cpu_count
|
|
cpu_count=$(getconf _NPROCESSORS_ONLN)
|
|
|
|
if [[ "$cpu_count" -lt "$min_cpu" ]]; then
|
|
log_error "Insufficient CPU cores: $cpu_count (minimum: $min_cpu)"
|
|
return 1
|
|
fi
|
|
|
|
# Check RAM
|
|
local total_mem_gb
|
|
if [[ -f /proc/meminfo ]]; then
|
|
local mem_kb
|
|
mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
|
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $mem_kb/1024/1024}")
|
|
else
|
|
local total_mem_bytes
|
|
total_mem_bytes=$(sysctl -n hw.memsize 2>/dev/null || echo "0")
|
|
total_mem_gb=$(awk "BEGIN {printf \"%.2f\", $total_mem_bytes/1024/1024/1024}")
|
|
fi
|
|
|
|
if ! awk "BEGIN {exit !($total_mem_gb >= $min_ram_gb)}"; then
|
|
log_error "Insufficient RAM: ${total_mem_gb}GB (minimum: ${min_ram_gb}GB)"
|
|
return 1
|
|
fi
|
|
|
|
# Check disk space
|
|
local avail_kb free_gb
|
|
avail_kb=$(df -k . | tail -1 | awk '{print $4}')
|
|
free_gb=$(awk "BEGIN {printf \"%.2f\", $avail_kb/1024/1024}")
|
|
|
|
if ! awk "BEGIN {exit !($free_gb >= $min_disk_gb)}"; then
|
|
log_error "Insufficient disk space: ${free_gb}GB (minimum: ${min_disk_gb}GB)"
|
|
return 1
|
|
fi
|
|
|
|
log_success "System requirements met: CPU cores=$cpu_count, RAM=${total_mem_gb}GB, FreeDisk=${free_gb}GB"
|
|
return 0
|
|
}
|
|
|
|
# Generate monitoring/web.yml from PROMETHEUS_USER and PROMETHEUS_PASSWORD in .env
|
|
generate_prometheus_web_config() {
|
|
if [ ! -f .env ]; then
|
|
return 0
|
|
fi
|
|
|
|
local prom_user prom_password
|
|
prom_user=$(grep '^PROMETHEUS_USER=' .env | head -1 | cut -d= -f2- | tr -d '"')
|
|
prom_password=$(grep '^PROMETHEUS_PASSWORD=' .env | head -1 | cut -d= -f2- | tr -d '"')
|
|
|
|
if [ -z "$prom_user" ] || [ -z "$prom_password" ]; then
|
|
log_warning "PROMETHEUS_USER or PROMETHEUS_PASSWORD not set in .env, skipping web.yml generation"
|
|
return 0
|
|
fi
|
|
|
|
local raw_hash hash
|
|
raw_hash=$(docker run --rm httpd:2-alpine htpasswd -nbBC 12 "" "$prom_password" 2>/dev/null)
|
|
|
|
if [ -z "$raw_hash" ]; then
|
|
log_warning "Failed to generate Prometheus password hash"
|
|
return 0
|
|
fi
|
|
|
|
# htpasswd outputs ":$2y$..." — strip leading colon and trailing whitespace
|
|
hash="${raw_hash#:}"
|
|
hash="${hash%%[[:space:]]*}"
|
|
|
|
cat > monitoring/web.yml <<EOF
|
|
basic_auth_users:
|
|
${prom_user}: ${hash}
|
|
EOF
|
|
|
|
log_success "Prometheus web config generated"
|
|
}
|
|
|
|
# Confirm action (returns 0 for yes, 1 for no)
|
|
confirm() {
|
|
local prompt="${1:-Are you sure?}"
|
|
local response
|
|
|
|
if ! is_interactive; then
|
|
# In non-interactive mode, assume yes
|
|
return 0
|
|
fi
|
|
|
|
read -r -p "$prompt [y/N]: " response
|
|
case "$response" in
|
|
[yY][eE][sS]|[yY])
|
|
return 0
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|