tools: add shared library ppf-common.sh
Host topology, ansible/podman/compose wrappers, color helpers, syntax validation, and target resolution for the PPF ops toolkit.
This commit is contained in:
158
tools/lib/ppf-common.sh
Normal file
158
tools/lib/ppf-common.sh
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/bin/bash
|
||||
# ppf-common.sh -- shared library for PPF operations toolkit
|
||||
# Source this file; do not execute directly.
|
||||
|
||||
set -eu
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paths
|
||||
# ---------------------------------------------------------------------------
|
||||
PPF_DIR="${PPF_DIR:-$HOME/git/ppf}"
|
||||
ANSIBLE_DIR="/opt/ansible"
|
||||
ANSIBLE_VENV="${ANSIBLE_DIR}/venv/bin/activate"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Host topology
|
||||
# ---------------------------------------------------------------------------
|
||||
MASTER="odin"
|
||||
WORKERS="cassius edge sentinel"
|
||||
ALL_HOSTS="odin cassius edge sentinel"
|
||||
|
||||
# Container names per role
|
||||
MASTER_CONTAINER="ppf"
|
||||
WORKER_CONTAINER="ppf-worker"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Colors (respects NO_COLOR -- https://no-color.org)
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ -z "${NO_COLOR:-}" ] && [ -t 1 ]; then
|
||||
C_RST='\033[0m'
|
||||
C_DIM='\033[2m'
|
||||
C_BOLD='\033[1m'
|
||||
C_RED='\033[38;5;167m'
|
||||
C_GREEN='\033[38;5;114m'
|
||||
C_YELLOW='\033[38;5;180m'
|
||||
C_BLUE='\033[38;5;110m'
|
||||
C_CYAN='\033[38;5;116m'
|
||||
else
|
||||
C_RST='' C_DIM='' C_BOLD='' C_RED='' C_GREEN=''
|
||||
C_YELLOW='' C_BLUE='' C_CYAN=''
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Output helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
log_ok() { printf "${C_GREEN} ✓${C_RST} %s\n" "$*"; }
|
||||
log_err() { printf "${C_RED} ✗${C_RST} %s\n" "$*" >&2; }
|
||||
log_warn() { printf "${C_YELLOW} ⚠${C_RST} %s\n" "$*"; }
|
||||
log_info() { printf "${C_BLUE} ●${C_RST} %s\n" "$*"; }
|
||||
log_dim() { printf "${C_DIM} %s${C_RST}\n" "$*"; }
|
||||
|
||||
die() { log_err "$@"; exit 1; }
|
||||
|
||||
# Section header
|
||||
section() {
|
||||
printf "\n${C_BOLD}${C_CYAN} %s${C_RST}\n" "$*"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Host resolution helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
is_master() { [ "$1" = "$MASTER" ]; }
|
||||
is_worker() {
|
||||
local h
|
||||
for h in $WORKERS; do [ "$h" = "$1" ] && return 0; done
|
||||
return 1
|
||||
}
|
||||
|
||||
container_name() {
|
||||
if is_master "$1"; then echo "$MASTER_CONTAINER"; else echo "$WORKER_CONTAINER"; fi
|
||||
}
|
||||
|
||||
# Expand target aliases into host list
|
||||
# "all" -> all hosts
|
||||
# "workers" -> worker hosts
|
||||
# "odin" -> just odin
|
||||
# Multiple args are concatenated with comma
|
||||
resolve_targets() {
|
||||
local targets=""
|
||||
local arg
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
all) targets="${targets:+$targets }$ALL_HOSTS" ;;
|
||||
workers) targets="${targets:+$targets }$WORKERS" ;;
|
||||
master) targets="${targets:+$targets }$MASTER" ;;
|
||||
*) targets="${targets:+$targets }$arg" ;;
|
||||
esac
|
||||
done
|
||||
# Deduplicate while preserving order
|
||||
echo "$targets" | tr ' ' '\n' | awk '!seen[$0]++' | tr '\n' ' ' | sed 's/ $//'
|
||||
}
|
||||
|
||||
# Convert space-separated host list to comma-separated for ansible
|
||||
hosts_csv() {
|
||||
echo "$*" | tr ' ' ','
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ansible wrapper
|
||||
# ---------------------------------------------------------------------------
|
||||
# Runs ansible with venv activated and ANSIBLE_REMOTE_TMP set.
|
||||
# Usage: ansible_cmd <ansible args...>
|
||||
ansible_cmd() {
|
||||
(
|
||||
# shellcheck disable=SC1090
|
||||
. "$ANSIBLE_VENV"
|
||||
cd "$ANSIBLE_DIR"
|
||||
ANSIBLE_REMOTE_TMP=/tmp/.ansible ansible "$@"
|
||||
)
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Remote podman/compose wrappers
|
||||
# ---------------------------------------------------------------------------
|
||||
# Run a podman command on a remote host as the podman user.
|
||||
# Uses dynamic UID discovery.
|
||||
# Usage: podman_cmd HOST "podman subcommand..."
|
||||
podman_cmd() {
|
||||
local host="$1"; shift
|
||||
local cmd="$*"
|
||||
ansible_cmd "$host" -m raw -a \
|
||||
"uid=\$(id -u podman) && sudo -u podman XDG_RUNTIME_DIR=/run/user/\$uid $cmd"
|
||||
}
|
||||
|
||||
# Run a podman-compose subcommand on a remote host.
|
||||
# Usage: compose_cmd HOST "subcommand [args]"
|
||||
compose_cmd() {
|
||||
local host="$1"; shift
|
||||
local cmd="$*"
|
||||
ansible_cmd "$host" -m raw -a \
|
||||
"uid=\$(id -u podman) && cd /home/podman/ppf && sudo -u podman XDG_RUNTIME_DIR=/run/user/\$uid podman-compose $cmd"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Validation
|
||||
# ---------------------------------------------------------------------------
|
||||
validate_syntax() {
|
||||
local errors=0
|
||||
local f
|
||||
section "Validating Python syntax"
|
||||
for f in "$PPF_DIR"/*.py; do
|
||||
[ -f "$f" ] || continue
|
||||
if python3 -m py_compile "$f" 2>/dev/null; then
|
||||
log_dim "$(basename "$f")"
|
||||
else
|
||||
log_err "$(basename "$f")"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
done
|
||||
if [ "$errors" -gt 0 ]; then
|
||||
die "$errors file(s) failed syntax check"
|
||||
fi
|
||||
log_ok "All files valid"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Version
|
||||
# ---------------------------------------------------------------------------
|
||||
PPF_TOOLS_VERSION="1.0.0"
|
||||
Reference in New Issue
Block a user