Files

136 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
if [[ -t 2 ]]; then
_C_RESET='\033[0m'
_C_RED='\033[0;31m'
_C_GREEN='\033[0;32m'
_C_YELLOW='\033[0;33m'
_C_BLUE='\033[0;34m'
else
_C_RESET='' _C_RED='' _C_GREEN='' _C_YELLOW='' _C_BLUE=''
fi
log_info() {
printf '%b[INFO]%b %s\n' "$_C_BLUE" "$_C_RESET" "$*" >&2
}
log_warn() {
printf '%b[WARN]%b %s\n' "$_C_YELLOW" "$_C_RESET" "$*" >&2
}
log_error() {
printf '%b[ERROR]%b %s\n' "$_C_RED" "$_C_RESET" "$*" >&2
}
log_success() {
printf '%b[OK]%b %s\n' "$_C_GREEN" "$_C_RESET" "$*" >&2
}
require_cmd() {
local cmd
for cmd in "$@"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log_error "Required command not found: $cmd"
return 1
fi
done
}
confirm_action() {
local prompt="${1:-Continue?}"
local auto_yes="${2:-false}"
if [[ "$auto_yes" == "true" ]]; then
return 0
fi
printf '%s [y/N] ' "$prompt"
read -r reply
[[ "$reply" =~ ^[Yy]$ ]]
}
stack_script_dir() {
cd "$(dirname "${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}")" && pwd
}
load_stack_env() {
local env_file="$1"
if [[ ! -f "$env_file" ]]; then
log_error "Missing env file: $env_file"
log_info "Copy stack.env.example to stack.env and update secrets first."
return 1
fi
local line key value
while IFS= read -r line || [[ -n "$line" ]]; do
[[ -z "$line" || "$line" == \#* ]] && continue
[[ "$line" == *=* ]] || continue
key="${line%%=*}"
value="${line#*=}"
value="${value%%# *}"
if [[ "$value" =~ ^\"(.*)\"$ ]] || [[ "$value" =~ ^\'(.*)\'$ ]]; then
value="${BASH_REMATCH[1]}"
fi
value="${value%"${value##*[![:space:]]}"}"
export "$key=$value"
done < "$env_file"
: "${OPS_ROOT:=/srv/ops}"
: "${COMPOSE_PROJECT_NAME:=pi-monitoring}"
}
compose_file() {
local dir
dir="$(stack_script_dir)"
printf '%s/docker-compose.yml' "$dir"
}
ensure_ops_dirs() {
local root="$1"
sudo mkdir -p \
"$root/portainer/data" \
"$root/grafana/data" \
"$root/prometheus/data" \
"$root/prometheus/targets" \
"$root/uptime-kuma/data" \
"$root/backups"
}
prepare_permissions() {
local root="$1"
# Keep operational directories writable by the current admin user.
sudo chown -R "$USER:$USER" \
"$root/portainer/data" \
"$root/uptime-kuma/data" \
"$root/prometheus/targets" \
"$root/backups"
# Grafana UID/GID in official image is usually 472
sudo chown -R 472:472 "$root/grafana/data"
# Prometheus runs as nobody (65534) in official image
sudo chown -R 65534:65534 "$root/prometheus/data"
}
wait_for_container_running() {
local container_id="$1"
local timeout_sec="$2"
local elapsed=0
while (( elapsed < timeout_sec )); do
local state
state="$(docker inspect -f '{{.State.Status}}' "$container_id" 2>/dev/null || true)"
if [[ "$state" == "running" ]]; then
return 0
fi
sleep 2
elapsed=$((elapsed + 2))
done
return 1
}