feat(monitor): implement monitor role #29
2 changed files with 159 additions and 0 deletions
|
|
@ -1225,6 +1225,105 @@ uninstall_agent() {
|
|||
log "Agent removed${purge:+ ($purge)}."
|
||||
}
|
||||
|
||||
install_monitor() {
|
||||
local public_key="$1"
|
||||
require_root
|
||||
validate_platform
|
||||
|
||||
local metrics_script="/usr/local/libexec/ochenstarik-smm-metrics"
|
||||
local monitor_user="ochenstarik-monitor"
|
||||
local monitor_home="/var/lib/ochenstarik-monitor"
|
||||
|
||||
if ! id -u "$monitor_user" >/dev/null 2>&1; then
|
||||
useradd -r -s /usr/sbin/nologin -d "$monitor_home" -M "$monitor_user"
|
||||
fi
|
||||
install -d -m 0755 -o "$monitor_user" -g "$monitor_user" "$monitor_home"
|
||||
|
||||
install -d -m 0755 "/usr/local/libexec"
|
||||
cat >"$metrics_script" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
# ochenstarik-smm-metrics
|
||||
|
||||
MESH_STATUS=""
|
||||
if [[ -x /usr/bin/wg && -f /etc/wireguard/smm0.conf ]]; then
|
||||
MESH_STATUS=$(wg show smm0 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
echo "PROTOCOL=1"
|
||||
echo "HOSTNAME=$(hostname)"
|
||||
UPTIME=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||
echo "UPTIME_SECONDS=${UPTIME}"
|
||||
LOAD1=$(awk '{print $1}' /proc/loadavg 2>/dev/null || echo "0.00")
|
||||
echo "LOAD1=${LOAD1}"
|
||||
CPU_COUNT=$(nproc 2>/dev/null || echo "1")
|
||||
echo "CPU_COUNT=${CPU_COUNT}"
|
||||
MEM_TOTAL=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
||||
echo "MEM_TOTAL_KB=${MEM_TOTAL}"
|
||||
MEM_AVAIL=$(awk '/^MemAvailable:/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
||||
if [ "$MEM_AVAIL" = "0" ] || [ -z "$MEM_AVAIL" ]; then
|
||||
MEM_FREE=$(awk '/^MemFree:/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
||||
MEM_CACHED=$(awk '/^Cached:/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
||||
MEM_AVAIL=$((MEM_FREE + MEM_CACHED))
|
||||
fi
|
||||
echo "MEM_AVAILABLE_KB=${MEM_AVAIL}"
|
||||
SWAP_TOTAL=$(awk '/^SwapTotal:/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
||||
echo "SWAP_TOTAL_KB=${SWAP_TOTAL}"
|
||||
SWAP_FREE=$(awk '/^SwapFree:/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
||||
echo "SWAP_FREE_KB=${SWAP_FREE}"
|
||||
DF_OUT=$(df -k / 2>/dev/null | awk 'NR==2 {print $2, $4}' || echo "0 0")
|
||||
DISK_TOTAL=$(echo "$DF_OUT" | awk '{print $1}')
|
||||
DISK_AVAIL=$(echo "$DF_OUT" | awk '{print $2}')
|
||||
echo "DISK_TOTAL_KB=${DISK_TOTAL}"
|
||||
echo "DISK_AVAILABLE_KB=${DISK_AVAIL}"
|
||||
DF_INODES=$(df -i / 2>/dev/null | awk 'NR==2 {print $2, $4}' || echo "0 0")
|
||||
INODES_TOTAL=$(echo "$DF_INODES" | awk '{print $1}')
|
||||
INODES_FREE=$(echo "$DF_INODES" | awk '{print $2}')
|
||||
echo "DISK_INODES_TOTAL=${INODES_TOTAL}"
|
||||
echo "DISK_INODES_FREE=${INODES_FREE}"
|
||||
NET_RX=$(awk 'NR>2 {rx+=$1} END {print rx}' /proc/net/dev 2>/dev/null || echo "0")
|
||||
NET_TX=$(awk 'NR>2 {tx+=$9} END {print tx}' /proc/net/dev 2>/dev/null || echo "0")
|
||||
echo "NETWORK_RX_BYTES=${NET_RX}"
|
||||
echo "NETWORK_TX_BYTES=${NET_TX}"
|
||||
KERNEL=$(uname -r 2>/dev/null || echo "unknown")
|
||||
echo "KERNEL=${KERNEL}"
|
||||
if [ -n "$MESH_STATUS" ]; then
|
||||
echo "--- MESH STATUS ---"
|
||||
echo "$MESH_STATUS"
|
||||
fi
|
||||
EOF
|
||||
chown root:root "$metrics_script"
|
||||
chmod 0755 "$metrics_script"
|
||||
|
||||
install -d -m 0700 -o "$monitor_user" -g "$monitor_user" "$monitor_home/.ssh"
|
||||
local auth_keys="$monitor_home/.ssh/authorized_keys"
|
||||
|
||||
# We idempotently add the key
|
||||
local key_entry="command=\"$metrics_script\",restrict,no-pty,no-agent-forwarding,no-port-forwarding,no-X11-forwarding $public_key"
|
||||
if [[ -f "$auth_keys" ]] && grep -qF "$public_key" "$auth_keys"; then
|
||||
log "Monitor key already installed."
|
||||
else
|
||||
echo "$key_entry" >> "$auth_keys"
|
||||
chown "$monitor_user:$monitor_user" "$auth_keys"
|
||||
chmod 0600 "$auth_keys"
|
||||
log "Monitor key installed."
|
||||
fi
|
||||
}
|
||||
|
||||
uninstall_monitor() {
|
||||
require_root
|
||||
local monitor_user="ochenstarik-monitor"
|
||||
local monitor_home="/var/lib/ochenstarik-monitor"
|
||||
local metrics_script="/usr/local/libexec/ochenstarik-smm-metrics"
|
||||
|
||||
if id -u "$monitor_user" >/dev/null 2>&1; then
|
||||
userdel -f "$monitor_user" || true
|
||||
fi
|
||||
rm -rf -- "$monitor_home"
|
||||
rm -f -- "$metrics_script"
|
||||
log "Monitor removed."
|
||||
}
|
||||
|
||||
uninstall_control() {
|
||||
[[ "${1:-}" == "--confirm-destroy-control" ]] || fail "Control removal requires --confirm-destroy-control"
|
||||
require_root
|
||||
|
|
@ -1260,6 +1359,8 @@ main() {
|
|||
install-control) [[ $# -ge 2 && $# -le 3 ]] || fail "install-control requires ARCHIVE PUBLIC_HOST [HTTPS_PORT]"; install_control "$@" ;;
|
||||
install-agent) [[ $# -eq 4 ]] || fail "install-agent requires ARCHIVE NODE_ID CONTROL_URL CA_CERT"; install_agent "$@" ;;
|
||||
install-node) [[ $# -eq 1 ]] || fail "install-node requires ARCHIVE"; install_node_from_code "$1" ;;
|
||||
install-monitor) [[ $# -eq 1 ]] || fail "install-monitor requires PUBLIC_KEY"; install_monitor "$1" ;;
|
||||
uninstall-monitor) [[ $# -eq 0 ]] || fail "uninstall-monitor takes no arguments"; uninstall_monitor ;;
|
||||
mesh-init) [[ $# -ge 1 && $# -le 2 ]] || fail "mesh-init requires PUBLIC_ENDPOINT [WG_PORT]"; mesh_init "$@" ;;
|
||||
peer-add) [[ $# -eq 1 ]] || fail "peer-add requires SMMPEER1_CODE"; add_mesh_peer "$1" ;;
|
||||
mesh-status) [[ $# -eq 0 ]] || fail "mesh-status takes no arguments"; show_mesh_status ;;
|
||||
|
|
|
|||
58
tests/acceptance/test_monitor_snapshot.sh
Normal file
58
tests/acceptance/test_monitor_snapshot.sh
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# test_monitor_snapshot.sh
|
||||
# Acceptance test for Monitor role installation and metrics format
|
||||
|
||||
cd "$(dirname "$0")/../.."
|
||||
BOOTSTRAP="./deploy/ochenstarik-server-monitor-manager.sh"
|
||||
DUMMY_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDummyTestKeyForAcceptanceTest dummy@test"
|
||||
|
||||
echo "=== Testing install-monitor ==="
|
||||
sudo "$BOOTSTRAP" install-monitor "$DUMMY_KEY"
|
||||
|
||||
# 1. Verify user exists and has nologin
|
||||
getent passwd ochenstarik-monitor | grep -q "/usr/sbin/nologin" || {
|
||||
echo "ERROR: User ochenstarik-monitor does not exist or does not have nologin"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 2. Verify authorized_keys
|
||||
AUTH_KEYS="/var/lib/ochenstarik-monitor/.ssh/authorized_keys"
|
||||
if ! sudo test -f "$AUTH_KEYS"; then
|
||||
echo "ERROR: authorized_keys not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo grep -q "command=\"/usr/local/libexec/ochenstarik-smm-metrics\",restrict" "$AUTH_KEYS" || {
|
||||
echo "ERROR: Forced command not found in authorized_keys"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 3. Verify metrics script output format
|
||||
echo "=== Testing metrics output ==="
|
||||
METRICS_OUT=$(sudo /usr/local/libexec/ochenstarik-smm-metrics)
|
||||
echo "$METRICS_OUT"
|
||||
|
||||
for FIELD in PROTOCOL HOSTNAME UPTIME_SECONDS LOAD1 CPU_COUNT MEM_TOTAL_KB MEM_AVAILABLE_KB SWAP_TOTAL_KB SWAP_FREE_KB DISK_TOTAL_KB DISK_AVAILABLE_KB DISK_INODES_TOTAL DISK_INODES_FREE NETWORK_RX_BYTES NETWORK_TX_BYTES KERNEL; do
|
||||
if ! echo "$METRICS_OUT" | grep -q "^${FIELD}="; then
|
||||
echo "ERROR: Missing field ${FIELD} in metrics output"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 4. Verify uninstall
|
||||
echo "=== Testing uninstall-monitor ==="
|
||||
sudo "$BOOTSTRAP" uninstall-monitor
|
||||
|
||||
if getent passwd ochenstarik-monitor >/dev/null 2>&1; then
|
||||
echo "ERROR: User ochenstarik-monitor was not removed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if sudo test -f "$AUTH_KEYS" || sudo test -f "/usr/local/libexec/ochenstarik-smm-metrics"; then
|
||||
echo "ERROR: Leftover files found after uninstall"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== PASS: Monitor role acceptance test ==="
|
||||
Loading…
Reference in a new issue