#!/usr/bin/env bash # BugWatch Server Monitoring Agent — Installer # Usage: curl -sSL https://install.bugwatch.dev | bash -s -- --api-key # Version: 1.0 set -euo pipefail # ============================================================================ # Defaults # ============================================================================ BUGWATCH_API_KEY="" BUGWATCH_ENDPOINT="https://api.bugwatch.dev" BUGWATCH_INTERVAL=60 INSTALL_DIR="/opt/bugwatch" CONFIG_DIR="/etc/bugwatch" CONFIG_FILE="${CONFIG_DIR}/agent.conf" AGENT_SCRIPT="${INSTALL_DIR}/agent.sh" # ============================================================================ # Parse arguments # ============================================================================ while [[ $# -gt 0 ]]; do case $1 in --api-key) BUGWATCH_API_KEY="$2" shift 2 ;; --endpoint) BUGWATCH_ENDPOINT="$2" shift 2 ;; --interval) BUGWATCH_INTERVAL="$2" shift 2 ;; --help|-h) echo "BugWatch Server Agent Installer" echo "" echo "Usage:" echo " curl -sSL https://install.bugwatch.dev | bash -s -- --api-key " echo "" echo "Options:" echo " --api-key (required) Your BugWatch project API key" echo " --endpoint API endpoint (default: https://api.bugwatch.dev)" echo " --interval Collection interval in seconds (default: 60)" echo "" exit 0 ;; *) echo "Unknown option: $1" exit 1 ;; esac done # ============================================================================ # Validate # ============================================================================ if [[ -z "$BUGWATCH_API_KEY" ]]; then echo "Error: --api-key is required" echo "Usage: curl -sSL https://install.bugwatch.dev | bash -s -- --api-key " exit 1 fi if ! command -v curl &>/dev/null; then echo "Error: curl is required but not installed" exit 1 fi echo "================================================" echo " BugWatch Server Monitoring Agent Installer" echo "================================================" echo "" # ============================================================================ # Create directories # ============================================================================ echo "[1/5] Creating directories..." mkdir -p "$INSTALL_DIR" mkdir -p "$CONFIG_DIR" # ============================================================================ # Write config # ============================================================================ echo "[2/5] Writing configuration..." cat > "$CONFIG_FILE" </dev/null; then echo " Downloaded agent from $AGENT_URL" else # Embedded fallback — write the agent inline cat > "$AGENT_SCRIPT" << 'AGENT_EOF' #!/usr/bin/env bash # BugWatch Server Monitoring Agent (embedded) set -euo pipefail CONFIG_FILE="/etc/bugwatch/agent.conf" NET_PREV_FILE="/tmp/bugwatch_net_prev" [[ -f "$CONFIG_FILE" ]] && source "$CONFIG_FILE" BUGWATCH_API_KEY="${BUGWATCH_API_KEY:-}" BUGWATCH_ENDPOINT="${BUGWATCH_ENDPOINT:-https://api.bugwatch.dev}" BUGWATCH_COLLECT_DOCKER="${BUGWATCH_COLLECT_DOCKER:-auto}" BUGWATCH_DISK_PATHS="${BUGWATCH_DISK_PATHS:-/}" [[ -z "$BUGWATCH_API_KEY" ]] && { echo "Error: BUGWATCH_API_KEY not set" >&2; exit 1; } json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g; s/\n/\\n/g'; } HOSTNAME_VAL=$(hostname 2>/dev/null || echo "unknown") MACHINE_ID=$(head -c 8 /etc/machine-id 2>/dev/null || head -c 8 /var/lib/dbus/machine-id 2>/dev/null || echo "00000000") SERVER_ID="${HOSTNAME_VAL}-${MACHINE_ID}" OS_INFO=$(grep -oP '(?<=^PRETTY_NAME=").*(?="$)' /etc/os-release 2>/dev/null || echo "Linux") KERNEL_VER=$(uname -r 2>/dev/null || echo "unknown") read_cpu() { awk '/^cpu / {print $2+$3+$4, $5}' /proc/stat; } CPU_B=$(read_cpu); sleep 1; CPU_A=$(read_cpu) ACT_D=$(( $(echo "$CPU_A" | awk '{print $1}') - $(echo "$CPU_B" | awk '{print $1}') )) IDL_D=$(( $(echo "$CPU_A" | awk '{print $2}') - $(echo "$CPU_B" | awk '{print $2}') )) TOT_D=$((ACT_D + IDL_D)) [[ $TOT_D -gt 0 ]] && CPU_PCT=$(awk "BEGIN {printf \"%.1f\", ($ACT_D/$TOT_D)*100}") || CPU_PCT="0.0" MEM_TOT=$(awk '/^MemTotal:/{print $2*1024}' /proc/meminfo) MEM_AVL=$(awk '/^MemAvailable:/{print $2*1024}' /proc/meminfo) MEM_USD=$((MEM_TOT - MEM_AVL)) [[ $MEM_TOT -gt 0 ]] && MEM_PCT=$(awk "BEGIN {printf \"%.1f\", ($MEM_USD/$MEM_TOT)*100}") || MEM_PCT="0.0" SWP_TOT=$(awk '/^SwapTotal:/{print $2*1024}' /proc/meminfo) SWP_FRE=$(awk '/^SwapFree:/{print $2*1024}' /proc/meminfo) SWP_USD=$((SWP_TOT - SWP_FRE)) read -r L1 L5 L15 _ < /proc/loadavg NET=$(awk 'NR>2 && $1!~/lo:/{rx+=$2;tx+=$10}END{print rx,tx}' /proc/net/dev) NRX=$(echo "$NET"|awk '{print $1}'); NTX=$(echo "$NET"|awk '{print $2}') NRXS=0; NTXS=0 if [[ -f "$NET_PREV_FILE" ]]; then read -r PRX PTX PTS < "$NET_PREV_FILE" EL=$(($(date +%s) - PTS)) [[ $EL -gt 0 ]] && { NRXS=$(((NRX-PRX)/EL)); NTXS=$(((NTX-PTX)/EL)); } [[ $NRXS -lt 0 ]] && NRXS=0; [[ $NTXS -lt 0 ]] && NTXS=0 fi echo "$NRX $NTX $(date +%s)" > "$NET_PREV_FILE" UPT=$(awk '{printf "%d",$1}' /proc/uptime) DISKS="[" FD=true IFS=',' read -ra DPS <<< "$BUGWATCH_DISK_PATHS" for DP in "${DPS[@]}"; do DP=$(echo "$DP"|xargs) if df -B1 "$DP" >/dev/null 2>&1; then DL=$(df -B1 "$DP"|tail -1) FS=$(echo "$DL"|awk '{print $1}') DT=$(echo "$DL"|awk '{print $2}') DU=$(echo "$DL"|awk '{print $3}') DA=$(echo "$DL"|awk '{print $4}') [[ $DT -gt 0 ]] && DP_PCT=$(awk "BEGIN {printf \"%.1f\",($DU/$DT)*100}") || DP_PCT="0.0" [[ "$FD" != "true" ]] && DISKS+="," DISKS+="{\"mount\":\"$(json_escape "$DP")\",\"filesystem\":\"$(json_escape "$FS")\",\"total_bytes\":$DT,\"used_bytes\":$DU,\"available_bytes\":$DA,\"usage_percent\":$DP_PCT}" FD=false fi done DISKS+="]" PROCS="[" FP=true while IFS= read -r line; do PU=$(echo "$line"|awk '{print $1}'); PP=$(echo "$line"|awk '{print $2}') PC=$(echo "$line"|awk '{print $3}'); PM=$(echo "$line"|awk '{print $4}') PN=$(echo "$line"|awk '{print $11}'|sed 's/.*\///') [[ "$FP" != "true" ]] && PROCS+="," PROCS+="{\"pid\":$PP,\"name\":\"$(json_escape "$PN")\",\"cpu_percent\":$PC,\"mem_percent\":$PM,\"user\":\"$(json_escape "$PU")\"}" FP=false done < <(ps aux --sort=-%cpu 2>/dev/null|head -6|tail -5) PROCS+="]" DOCKER="null" if [[ "$BUGWATCH_COLLECT_DOCKER" == "auto" || "$BUGWATCH_COLLECT_DOCKER" == "true" ]]; then if command -v docker &>/dev/null && docker info &>/dev/null 2>&1; then DOCKER="[]" fi fi PAYLOAD="{\"server_id\":\"$(json_escape "$SERVER_ID")\",\"hostname\":\"$(json_escape "$HOSTNAME_VAL")\",\"os\":\"$(json_escape "$OS_INFO")\",\"kernel\":\"$(json_escape "$KERNEL_VER")\",\"cpu\":{\"usage_percent\":$CPU_PCT},\"memory\":{\"total_bytes\":$MEM_TOT,\"used_bytes\":$MEM_USD,\"available_bytes\":$MEM_AVL,\"usage_percent\":$MEM_PCT},\"swap\":{\"total_bytes\":$SWP_TOT,\"used_bytes\":$SWP_USD},\"network\":{\"rx_bytes_per_sec\":$NRXS,\"tx_bytes_per_sec\":$NTXS},\"load\":{\"avg_1\":$L1,\"avg_5\":$L5,\"avg_15\":$L15},\"uptime_seconds\":$UPT,\"disks\":$DISKS,\"processes\":$PROCS,\"docker\":$DOCKER}" curl -sS -o /dev/null -w "" -X POST \ -H "Authorization: Bearer ${BUGWATCH_API_KEY}" \ -H "Content-Type: application/json" \ -H "X-Bugwatch-Agent: server-monitor/1.0" \ -d "$PAYLOAD" \ "${BUGWATCH_ENDPOINT}/api/v1/metrics" \ --max-time 10 2>/dev/null || true AGENT_EOF echo " Used embedded agent script" fi chmod +x "$AGENT_SCRIPT" echo " Agent: $AGENT_SCRIPT" # ============================================================================ # Setup systemd timer (or cron fallback) # ============================================================================ echo "[4/5] Setting up scheduled execution..." if command -v systemctl &>/dev/null && systemctl --version &>/dev/null 2>&1; then # systemd service cat > /etc/systemd/system/bugwatch-agent.service < /etc/systemd/system/bugwatch-agent.timer </dev/null || true) | grep -v "bugwatch" || true; echo "$CRON_ENTRY") | crontab - echo " Cron job installed (every minute)" fi # ============================================================================ # Verify connectivity # ============================================================================ echo "[5/5] Verifying connectivity..." if "$AGENT_SCRIPT" 2>/dev/null; then echo "" echo "================================================" echo " BugWatch Agent installed successfully!" echo "================================================" echo "" echo " Server ID: $(hostname)-$(head -c 8 /etc/machine-id 2>/dev/null || echo '????????')" echo " Config: $CONFIG_FILE" echo " Agent: $AGENT_SCRIPT" echo " Interval: ${BUGWATCH_INTERVAL}s" echo "" echo " Metrics should appear in your BugWatch dashboard" echo " within a few minutes." echo "" else echo "" echo "================================================" echo " Agent installed but connectivity check failed" echo "================================================" echo "" echo " The agent was installed but could not reach the" echo " BugWatch API. Check your API key and endpoint." echo "" echo " Config: $CONFIG_FILE" echo "" fi