Files
linux-scripts/deploy-exporter.sh
T
chiefgeek a1a17e81a1 Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist,
same-site referer bypass, Blackbox-Exporter allowed bot, and all
new exporters, cheat sheets, and automation scripts.
2026-05-25 03:31:08 +02:00

589 lines
21 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# Script Name: deploy-exporter.sh
# Version: 1.0
# Description: Deployment tool for Prometheus exporters from mylinux.work.
# Downloads, installs, configures cron jobs, validates output,
# and manages lifecycle (install, update, remove, status) for
# any exporter script hosted at mylinux.work/downloads/.
#
# Author: Phil Connor
# Contact: contact@mylinux.work
# Website: https://mylinux.work
# License: MIT
#
# Prerequisites:
# - wget or curl
# - root access (for /usr/local/bin/ and /etc/cron.d/)
#
# Usage:
# deploy-exporter.sh list # list available
# deploy-exporter.sh install process-metrics-exporter # install one
# deploy-exporter.sh install process-metrics-exporter --cron "*/3 * * * *"
# deploy-exporter.sh install process-metrics-exporter journal-error-exporter
# deploy-exporter.sh status # check installed
# deploy-exporter.sh remove process-metrics-exporter # remove one
# deploy-exporter.sh update # update all
#
################################################################################
set -uo pipefail
# ============================================================================
# CONFIGURATION
# ============================================================================
BASE_URL="https://mylinux.work/downloads"
INSTALL_DIR="/usr/local/bin"
CRON_DIR="/etc/cron.d"
TEXTFILE_DIR="/var/lib/node_exporter"
# ============================================================================
# AVAILABLE EXPORTERS
# ============================================================================
declare -A EXPORTER_DESC=(
[alertmanager-exporter]="Alertmanager notification and silence metrics"
[apache-metrics-exporter]="Apache HTTP server performance metrics"
[apt-updates-exporter]="Pending apt package updates"
[artifactory-exporter]="JFrog Artifactory repository metrics"
[backup-status-exporter]="Backup job status and age metrics"
[borg-backup-exporter]="Borg backup repository and archive metrics"
[caprover-exporter]="CapRover app deployment metrics"
[clickhouse-exporter]="ClickHouse query, memory, merge, and replication metrics"
[consul-exporter]="HashiCorp Consul service health metrics"
[container-health-exporter]="Docker container health and resource metrics"
[coolify-exporter]="Coolify deployment platform metrics"
[dokku-exporter]="Dokku deployment platform metrics"
[dokploy-exporter]="Dokploy deployment platform metrics"
[cron-job-exporter]="Cron job execution status and timing"
[crowdsec-decisions-exporter]="CrowdSec active decisions and ban metrics"
[crowdsec-exporter]="CrowdSec intrusion detection metrics"
[database-backup-exporter]="Database backup status and size metrics"
[dhcp-lease-exporter]="DHCP lease allocation metrics"
[directory-size-exporter]="Directory size and file count metrics"
[disk-io-exporter]="Disk I/O throughput and latency metrics"
[docker-swarm-exporter]="Docker Swarm node and service metrics"
[dovecot-metrics-exporter]="Dovecot mail server metrics"
[duplicati-exporter]="Duplicati backup job metrics"
[elasticsearch-exporter]="Elasticsearch cluster health and index metrics"
[fail2ban-exporter]="Fail2ban jail and ban metrics"
[freeradius-exporter]="FreeRADIUS authentication metrics"
[game-server-exporter]="Game server player count and status metrics"
[gitea-exporter]="Gitea repository and user metrics"
[glpi-exporter]="GLPI ITSM ticket and asset metrics"
[gitlab-metrics-exporter]="GitLab instance performance metrics"
[gitlab-migration-exporter]="GitLab migration progress metrics"
[gpu-exporter]="GPU utilization and temperature metrics"
[graylog-exporter]="Graylog log management metrics"
[headscale-metrics-exporter]="Headscale coordination server metrics"
[ip-intel-exporter]="IP intelligence from nginx access logs"
[jenkins-exporter]="Jenkins build and queue metrics"
[incus-metrics-exporter]="Incus storage pool, snapshot, and instance inventory metrics"
[journal-error-exporter]="Journalctl error and warning metrics"
[keepalived-exporter]="Keepalived VRRP failover metrics"
[login-attempt-exporter]="SSH and system login attempt metrics"
[ufw-blocklist-metrics]="UFW blocklist feed, ipset, and block count metrics"
[users-logged-in]="User login sessions, terminals, sudo, and failed login metrics"
[logrotate-check-exporter]="Logrotate configuration health metrics"
[lynis-metrics-exporter]="Lynis security audit score metrics"
[mailcow-exporter]="Mailcow mail server metrics"
[memory-pressure-exporter]="Memory pressure and swap usage metrics"
[mysql-exporter]="MySQL/MariaDB performance metrics"
[n8n-exporter]="n8n workflow automation metrics"
[network-info-exporter]="Network interface and routing metrics"
[nexus-exporter]="Sonatype Nexus Repository metrics"
[nextcloud-exporter]="Nextcloud instance health metrics"
[nfs-exporter]="NFS client mount and performance metrics"
[nfs-server-exporter]="NFS server export and connection metrics"
[nginx-metrics-exporter]="Nginx connection and request metrics"
[ntp-drift-exporter]="NTP clock drift and sync metrics"
[ollama-exporter]="Ollama LLM model and inference metrics"
[openvpn-exporter]="OpenVPN tunnel and client metrics"
[password-expiry-exporter]="System user password expiry metrics"
[pihole-exporter]="Pi-hole DNS filtering metrics"
[plex-exporter]="Plex media server activity metrics"
[podman-container-exporter]="Podman container health and resource metrics"
[postgresql-exporter]="PostgreSQL database performance metrics"
[postgresql-ha-exporter]="PostgreSQL HA replication metrics"
[process-metrics-exporter]="Process CPU/memory/state metrics"
[textfile-health-exporter]="Textfile collector health monitoring"
[rabbitmq-exporter]="RabbitMQ queue and connection metrics"
[redis-metrics-exporter]="Redis server performance metrics"
[redis-sentinel-exporter]="Redis Sentinel failover metrics"
[restic-backup-exporter]="Restic backup snapshot and size metrics"
[rsyslog-metrics-exporter]="Rsyslog message processing metrics"
[samba-exporter]="Samba file share and session metrics"
[seo-exporter]="SEO health and crawl metrics"
[smart-drive-exporter]="SMART disk health and temperature metrics"
[snipeit-exporter]="Snipe-IT asset management metrics"
[sonarqube-exporter]="SonarQube code quality metrics"
[squid-exporter]="Squid proxy cache and request metrics"
[storage-health-exporter]="Storage pool and volume health metrics"
[suricata-exporter]="Suricata IDS/IPS alert metrics"
[syncthing-exporter]="Syncthing folder sync and device metrics"
[systemd-boot-time-exporter]="Systemd boot and service startup timing"
[systemd-service-exporter]="Systemd service state and restart metrics"
[systemd-timer-exporter]="Systemd timer schedule and execution metrics"
[tailscale-exporter]="Tailscale node and network metrics"
[trivy-cve-auditor]="Trivy container image vulnerability metrics"
[vault-exporter]="HashiCorp Vault seal and token metrics"
[vaultwarden-exporter]="Vaultwarden password manager metrics"
[wazuh-exporter]="Wazuh SIEM alert and agent metrics"
[web-traffic-exporter]="Web traffic request and response metrics"
[webtop-selkies-exporter]="Webtop and Selkies container desktop metrics"
[wickr-io-exporter]="Wickr.io bot and message metrics"
[wickr-metrics-exporter]="Wickr messaging platform metrics"
[wireguard-exporter]="WireGuard tunnel and peer metrics"
[yum-updates-exporter]="Pending yum/dnf package updates"
)
declare -A EXPORTER_CRON=(
[alertmanager-exporter]="*/5 * * * *"
[apache-metrics-exporter]="*/3 * * * *"
[apt-updates-exporter]="0 0 * * *"
[artifactory-exporter]="*/5 * * * *"
[backup-status-exporter]="*/15 * * * *"
[borg-backup-exporter]="*/15 * * * *"
[caprover-exporter]="*/5 * * * *"
[clickhouse-exporter]="*/3 * * * *"
[consul-exporter]="*/3 * * * *"
[container-health-exporter]="*/3 * * * *"
[coolify-exporter]="*/5 * * * *"
[dokku-exporter]="*/5 * * * *"
[dokploy-exporter]="*/5 * * * *"
[cron-job-exporter]="*/5 * * * *"
[crowdsec-decisions-exporter]="*/5 * * * *"
[crowdsec-exporter]="*/5 * * * *"
[database-backup-exporter]="*/15 * * * *"
[dhcp-lease-exporter]="*/5 * * * *"
[directory-size-exporter]="*/15 * * * *"
[disk-io-exporter]="*/3 * * * *"
[docker-swarm-exporter]="*/3 * * * *"
[dovecot-metrics-exporter]="*/5 * * * *"
[duplicati-exporter]="*/15 * * * *"
[elasticsearch-exporter]="*/3 * * * *"
[fail2ban-exporter]="*/5 * * * *"
[freeradius-exporter]="*/5 * * * *"
[game-server-exporter]="*/3 * * * *"
[gitea-exporter]="*/5 * * * *"
[glpi-exporter]="*/5 * * * *"
[gitlab-metrics-exporter]="*/5 * * * *"
[gitlab-migration-exporter]="*/5 * * * *"
[gpu-exporter]="*/3 * * * *"
[graylog-exporter]="*/5 * * * *"
[headscale-metrics-exporter]="*/5 * * * *"
[ip-intel-exporter]="*/5 * * * *"
[jenkins-exporter]="*/5 * * * *"
[incus-metrics-exporter]="*/5 * * * *"
[journal-error-exporter]="*/5 * * * *"
[keepalived-exporter]="*/5 * * * *"
[login-attempt-exporter]="*/5 * * * *"
[ufw-blocklist-metrics]="*/5 * * * *"
[users-logged-in]="*/3 * * * *"
[logrotate-check-exporter]="0 */6 * * *"
[lynis-metrics-exporter]="0 0 * * *"
[mailcow-exporter]="*/5 * * * *"
[memory-pressure-exporter]="*/3 * * * *"
[mysql-exporter]="*/3 * * * *"
[n8n-exporter]="*/5 * * * *"
[network-info-exporter]="*/5 * * * *"
[nexus-exporter]="*/5 * * * *"
[nextcloud-exporter]="*/5 * * * *"
[nfs-exporter]="*/5 * * * *"
[nfs-server-exporter]="*/5 * * * *"
[nginx-metrics-exporter]="*/3 * * * *"
[ntp-drift-exporter]="*/5 * * * *"
[ollama-exporter]="*/5 * * * *"
[openvpn-exporter]="*/5 * * * *"
[password-expiry-exporter]="0 0 * * *"
[pihole-exporter]="*/5 * * * *"
[plex-exporter]="*/5 * * * *"
[podman-container-exporter]="*/3 * * * *"
[postgresql-exporter]="*/3 * * * *"
[postgresql-ha-exporter]="*/3 * * * *"
[process-metrics-exporter]="*/3 * * * *"
[textfile-health-exporter]="*/5 * * * *"
[rabbitmq-exporter]="*/5 * * * *"
[redis-metrics-exporter]="*/3 * * * *"
[redis-sentinel-exporter]="*/5 * * * *"
[restic-backup-exporter]="*/15 * * * *"
[rsyslog-metrics-exporter]="*/5 * * * *"
[samba-exporter]="*/5 * * * *"
[seo-exporter]="0 */6 * * *"
[smart-drive-exporter]="*/15 * * * *"
[snipeit-exporter]="*/5 * * * *"
[sonarqube-exporter]="*/5 * * * *"
[squid-exporter]="*/5 * * * *"
[storage-health-exporter]="*/15 * * * *"
[suricata-exporter]="*/5 * * * *"
[syncthing-exporter]="*/5 * * * *"
[systemd-boot-time-exporter]="*/15 * * * *"
[systemd-service-exporter]="*/5 * * * *"
[systemd-timer-exporter]="*/5 * * * *"
[tailscale-exporter]="*/5 * * * *"
[trivy-cve-auditor]="*/30 * * * *"
[vault-exporter]="*/5 * * * *"
[vaultwarden-exporter]="*/5 * * * *"
[wazuh-exporter]="*/5 * * * *"
[web-traffic-exporter]="*/5 * * * *"
[webtop-selkies-exporter]="*/3 * * * *"
[wickr-io-exporter]="*/5 * * * *"
[wickr-metrics-exporter]="*/5 * * * *"
[wireguard-exporter]="*/5 * * * *"
[yum-updates-exporter]="0 0 * * *"
)
# ============================================================================
# HELPERS
# ============================================================================
log() { echo "# $*"; }
warn() { echo "# WARN: $*" >&2; }
err() { echo "# ERROR: $*" >&2; }
die() { err "$@"; exit 1; }
check_root() {
[[ $EUID -eq 0 ]] || die "Must run as root (need write access to ${INSTALL_DIR}/ and ${CRON_DIR}/)"
}
download() {
local url="$1" dest="$2"
if command -v wget &>/dev/null; then
wget -q -O "$dest" "$url"
elif command -v curl &>/dev/null; then
curl -fsSL -o "$dest" "$url"
else
die "Neither wget nor curl found"
fi
}
get_script_version() {
local file="$1"
grep -m1 '^# Version:' "$file" 2>/dev/null | awk '{print $3}' || echo "unknown"
}
# ============================================================================
# LIST
# ============================================================================
cmd_list() {
log "Available exporters from mylinux.work (${#EXPORTER_DESC[@]} total)"
log ""
printf "# %-40s %-15s %s\n" "EXPORTER" "DEFAULT CRON" "DESCRIPTION"
printf "# %-40s %-15s %s\n" "--------" "------------" "-----------"
for name in $(echo "${!EXPORTER_DESC[@]}" | tr ' ' '\n' | sort); do
local cron="${EXPORTER_CRON[$name]:-*/5 * * * *}"
local desc="${EXPORTER_DESC[$name]}"
local installed=""
[[ -f "${INSTALL_DIR}/${name}.sh" ]] && installed=" [installed]"
printf "# %-40s %-15s %s%s\n" "$name" "$cron" "$desc" "$installed"
done
}
# ============================================================================
# INSTALL
# ============================================================================
cmd_install() {
check_root
local names=()
local cron_schedule=""
while [[ $# -gt 0 ]]; do
case "$1" in
--cron)
cron_schedule="$2"
shift 2
;;
-*)
die "Unknown option: $1"
;;
*)
names+=("$1")
shift
;;
esac
done
[[ ${#names[@]} -gt 0 ]] || die "No exporter name(s) specified"
for name in "${names[@]}"; do
install_one "$name" "$cron_schedule"
done
}
install_one() {
local name="$1"
local cron_schedule="$2"
local url="${BASE_URL}/${name}.sh"
local dest="${INSTALL_DIR}/${name}.sh"
local temp_file
if [[ -z "${EXPORTER_DESC[$name]+x}" ]]; then
warn "Unknown exporter '${name}' — not in the built-in list, attempting download anyway"
fi
log "Installing ${name}..."
temp_file=$(mktemp "/tmp/${name}.XXXXXX")
if ! download "$url" "$temp_file"; then
rm -f "$temp_file"
err "Failed to download ${url}"
return 1
fi
if [[ ! -s "$temp_file" ]]; then
rm -f "$temp_file"
err "Downloaded file is empty: ${url}"
return 1
fi
chmod +x "$temp_file"
log "Validating ${name}..."
local test_output
test_output=$("$temp_file" 2>/dev/null || true)
local line_count
line_count=$(echo "$test_output" | wc -l)
if [[ "$line_count" -lt 3 ]]; then
rm -f "$temp_file"
err "Validation failed — ${name} produced only ${line_count} lines of output"
return 1
fi
mv -f "$temp_file" "$dest"
chmod +x "$dest"
log "Installed ${dest}"
if [[ -n "$cron_schedule" ]]; then
local default_cron="$cron_schedule"
elif [[ -n "${EXPORTER_CRON[$name]+x}" ]]; then
local default_cron="${EXPORTER_CRON[$name]}"
log "No --cron specified, using default: ${default_cron}"
else
local default_cron=""
fi
if [[ -n "$default_cron" ]]; then
mkdir -p "$TEXTFILE_DIR"
local cron_file="${CRON_DIR}/${name}"
cat > "$cron_file" <<EOF
# Managed by deploy-exporter.sh — do not edit manually
${default_cron} root ${INSTALL_DIR}/${name}.sh --textfile 2>&1
EOF
log "Created cron job: ${cron_file}"
log " Schedule: ${default_cron}"
log " Command: ${INSTALL_DIR}/${name}.sh --textfile"
fi
log "${name} installed successfully"
log ""
}
# ============================================================================
# STATUS
# ============================================================================
cmd_status() {
local found=0
log "Installed exporters in ${INSTALL_DIR}/:"
log ""
printf "# %-40s %-12s %-10s %s\n" "EXPORTER" "VERSION" "CRON" "LAST .prom UPDATE"
printf "# %-40s %-12s %-10s %s\n" "--------" "-------" "----" "-----------------"
for script in "${INSTALL_DIR}"/*-exporter.sh; do
[[ -f "$script" ]] || continue
found=1
local name
name=$(basename "$script" .sh)
local version
version=$(get_script_version "$script")
local cron_status="none"
[[ -f "${CRON_DIR}/${name}" ]] && cron_status="active"
local prom_name
prom_name=$(echo "$name" | tr '-' '_')
local prom_file="${TEXTFILE_DIR}/${prom_name}.prom"
local prom_age="no .prom file"
if [[ -f "$prom_file" ]]; then
local mod_time now age_sec
mod_time=$(stat -c %Y "$prom_file" 2>/dev/null || echo 0)
now=$(date +%s)
age_sec=$(( now - mod_time ))
if [[ $age_sec -lt 60 ]]; then
prom_age="${age_sec}s ago"
elif [[ $age_sec -lt 3600 ]]; then
prom_age="$(( age_sec / 60 ))m ago"
elif [[ $age_sec -lt 86400 ]]; then
prom_age="$(( age_sec / 3600 ))h ago"
else
prom_age="$(( age_sec / 86400 ))d ago (STALE)"
fi
fi
printf "# %-40s %-12s %-10s %s\n" "$name" "$version" "$cron_status" "$prom_age"
done
if [[ $found -eq 0 ]]; then
log "No exporters installed in ${INSTALL_DIR}/"
fi
}
# ============================================================================
# REMOVE
# ============================================================================
cmd_remove() {
check_root
[[ $# -gt 0 ]] || die "No exporter name specified"
for name in "$@"; do
remove_one "$name"
done
}
remove_one() {
local name="$1"
local script="${INSTALL_DIR}/${name}.sh"
local cron_file="${CRON_DIR}/${name}"
local prom_name
prom_name=$(echo "$name" | tr '-' '_')
local prom_file="${TEXTFILE_DIR}/${prom_name}.prom"
if [[ ! -f "$script" ]]; then
warn "${name} is not installed in ${INSTALL_DIR}/"
return 1
fi
rm -f "$script"
log "Removed ${script}"
if [[ -f "$cron_file" ]]; then
rm -f "$cron_file"
log "Removed cron job: ${cron_file}"
fi
if [[ -f "$prom_file" ]]; then
rm -f "$prom_file"
log "Removed .prom file: ${prom_file}"
fi
log "${name} removed"
log ""
}
# ============================================================================
# UPDATE
# ============================================================================
cmd_update() {
check_root
local found=0
for script in "${INSTALL_DIR}"/*-exporter.sh; do
[[ -f "$script" ]] || continue
found=1
local name
name=$(basename "$script" .sh)
local old_version
old_version=$(get_script_version "$script")
log "Updating ${name} (current: v${old_version})..."
local url="${BASE_URL}/${name}.sh"
local temp_file
temp_file=$(mktemp "/tmp/${name}.XXXXXX")
if ! download "$url" "$temp_file"; then
rm -f "$temp_file"
err "Failed to download ${name}, skipping"
continue
fi
if [[ ! -s "$temp_file" ]]; then
rm -f "$temp_file"
err "Downloaded file is empty for ${name}, skipping"
continue
fi
local new_version
new_version=$(get_script_version "$temp_file")
chmod +x "$temp_file"
mv -f "$temp_file" "$script"
chmod +x "$script"
if [[ "$old_version" == "$new_version" ]]; then
log "${name}: v${new_version} (unchanged)"
else
log "${name}: v${old_version} → v${new_version}"
fi
done
if [[ $found -eq 0 ]]; then
log "No exporters installed in ${INSTALL_DIR}/"
fi
}
# ============================================================================
# USAGE
# ============================================================================
show_usage() {
cat <<EOF
Usage: $(basename "$0") COMMAND [OPTIONS]
Deploy, manage, and update Prometheus exporters from mylinux.work.
COMMANDS:
list List available exporters
install NAME [NAME...] [OPTS] Install one or more exporters
status Show installed exporters and their state
remove NAME [NAME...] Remove one or more exporters
update Update all installed exporters
INSTALL OPTIONS:
--cron "SCHEDULE" Set cron schedule (default: per-exporter)
EXAMPLES:
$(basename "$0") list
$(basename "$0") install process-metrics-exporter
$(basename "$0") install process-metrics-exporter --cron "*/3 * * * *"
$(basename "$0") install process-metrics-exporter journal-error-exporter
$(basename "$0") status
$(basename "$0") remove process-metrics-exporter
$(basename "$0") update
EOF
exit 0
}
# ============================================================================
# MAIN
# ============================================================================
[[ $# -gt 0 ]] || show_usage
COMMAND="$1"
shift
case "$COMMAND" in
list) cmd_list ;;
install) cmd_install "$@" ;;
status) cmd_status ;;
remove) cmd_remove "$@" ;;
update) cmd_update ;;
-h|--help) show_usage ;;
*) die "Unknown command: ${COMMAND} — run with --help for usage" ;;
esac