feat: add Pi monitoring stack with deployment scripts and architecture documentation
This commit is contained in:
135
setup/pi-monitoring/lib.sh
Executable file
135
setup/pi-monitoring/lib.sh
Executable file
@@ -0,0 +1,135 @@
|
||||
#!/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
|
||||
}
|
||||
Reference in New Issue
Block a user