a1a17e81a1
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.
612 lines
17 KiB
Bash
612 lines
17 KiB
Bash
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
#############################################################
|
|
#### Prometheus Node Exporter Installer ####
|
|
#### For RHEL/Rocky/Alma, Oracle Linux, Debian & Ubuntu ####
|
|
#### ####
|
|
#### Author: Phil Connor ####
|
|
#### Contact: contact@mylinux.work ####
|
|
#### License: MIT ####
|
|
#### Version: 1.1 ####
|
|
#### ####
|
|
#### Usage: ./install-node-exporter.sh [OPTIONS] ####
|
|
#############################################################
|
|
|
|
# Script defaults
|
|
INSTALL_DIR="/usr/local/bin"
|
|
TEXTFILE_DIR="/var/lib/node_exporter/textfile_collector"
|
|
SERVICE_USER="node_exporter"
|
|
PORT=9100
|
|
COLLECTORS=""
|
|
NO_COLLECTORS=""
|
|
UPDATE_MODE=false
|
|
UNINSTALL_MODE=false
|
|
DRY_RUN=false
|
|
OPEN_FIREWALL=true
|
|
PROMETHEUS_IP=""
|
|
|
|
# System variables
|
|
logfile="/var/log/node-exporter-install.log"
|
|
TMPDIR=""
|
|
|
|
#########################
|
|
### Logging Functions ###
|
|
#########################
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$logfile"
|
|
}
|
|
|
|
log_error() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" | tee -a "$logfile" >&2
|
|
}
|
|
|
|
log_info() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1" | tee -a "$logfile"
|
|
}
|
|
|
|
#########################
|
|
### Cleanup Trap ###
|
|
#########################
|
|
cleanup() {
|
|
if [[ -n "$TMPDIR" && -d "$TMPDIR" ]]; then
|
|
rm -rf "$TMPDIR"
|
|
fi
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
|
|
#########################
|
|
### Utility Functions ###
|
|
#########################
|
|
show_help() {
|
|
cat << EOF
|
|
Prometheus Node Exporter Installer
|
|
|
|
USAGE:
|
|
$0 [OPTIONS]
|
|
|
|
OPTIONS:
|
|
--collectors LIST Additional collectors to enable (comma-separated)
|
|
e.g., "systemd,processes,tcpstat"
|
|
--no-collectors LIST Collectors to disable (comma-separated)
|
|
e.g., "wifi,infiniband"
|
|
--port PORT Listen port (default: 9100)
|
|
--textfile-dir DIR Textfile collector directory
|
|
(default: /var/lib/node_exporter/textfile_collector)
|
|
--prometheus-ip IP Restrict firewall rule to this source IP
|
|
--no-firewall Skip firewall configuration
|
|
--update Update existing installation
|
|
--uninstall Remove node_exporter completely
|
|
--dry-run Show what would be done without doing it
|
|
--help Show this help message
|
|
|
|
EXAMPLES:
|
|
$0
|
|
$0 --collectors "systemd,processes,tcpstat"
|
|
$0 --no-collectors "wifi,infiniband" --port 9200
|
|
$0 --prometheus-ip 10.0.0.5
|
|
$0 --update
|
|
$0 --uninstall
|
|
$0 --dry-run
|
|
|
|
EOF
|
|
}
|
|
|
|
#########################
|
|
### Permission Check ###
|
|
#########################
|
|
check_permissions() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
log_error "This script must be run as root! Login as root, or use sudo."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
#########################
|
|
### System Detection ###
|
|
#########################
|
|
detect_os() {
|
|
if [[ "$(command -v lsb_release)" ]]; then
|
|
OS=$(lsb_release -i | awk '{print $3}' | tr '[:upper:]' '[:lower:]')
|
|
OSVER=$(lsb_release -r | awk '{print $2}' | cut -d. -f1)
|
|
else
|
|
OS=$({ grep PRETTY_NAME /etc/os-release || true; } | sed 's/PRETTY_NAME=//g' | tr -d '="' | awk '{print $1}' | tr '[:upper:]' '[:lower:]')
|
|
OSVER=$({ grep VERSION_ID /etc/os-release || true; } | sed 's/VERSION_ID=//g' | tr -d '"' | cut -d. -f1)
|
|
fi
|
|
|
|
log_info "Detected OS: $OS version $OSVER"
|
|
}
|
|
|
|
detect_arch() {
|
|
local machine
|
|
machine=$(uname -m)
|
|
case "$machine" in
|
|
x86_64) ARCH="amd64" ;;
|
|
aarch64) ARCH="arm64" ;;
|
|
*)
|
|
log_error "Unsupported architecture: $machine"
|
|
exit 1
|
|
;;
|
|
esac
|
|
log_info "Detected architecture: $ARCH"
|
|
}
|
|
|
|
#########################
|
|
### Package Manager ###
|
|
#########################
|
|
setup_package_manager() {
|
|
case $OS in
|
|
"ubuntu"|"debian")
|
|
pkgmgr="apt -y"
|
|
;;
|
|
"red"|"centos"|"oracle"|"rocky"|"almalinux")
|
|
if command -v dnf >/dev/null 2>&1; then
|
|
pkgmgr="dnf -y"
|
|
else
|
|
pkgmgr="yum -y"
|
|
fi
|
|
;;
|
|
*)
|
|
log_error "Unsupported OS: $OS"
|
|
exit 1
|
|
;;
|
|
esac
|
|
log_info "Using package manager: $pkgmgr"
|
|
}
|
|
|
|
#########################
|
|
### Dependencies ###
|
|
#########################
|
|
install_dependencies() {
|
|
for cmd in curl tar; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
log_info "Installing $cmd"
|
|
$pkgmgr install "$cmd"
|
|
fi
|
|
done
|
|
}
|
|
|
|
#########################
|
|
### Version Helpers ###
|
|
#########################
|
|
get_latest_version() {
|
|
local version
|
|
version=$(curl -s https://api.github.com/repos/prometheus/node_exporter/releases/latest \
|
|
| grep '"tag_name"' | cut -d '"' -f 4 | sed 's/^v//')
|
|
if [[ -z "$version" ]]; then
|
|
log_error "Failed to fetch latest version from GitHub API"
|
|
exit 1
|
|
fi
|
|
echo "$version"
|
|
}
|
|
|
|
get_installed_version() {
|
|
if [[ -x "${INSTALL_DIR}/node_exporter" ]]; then
|
|
"${INSTALL_DIR}/node_exporter" --version 2>&1 | head -1 | awk '{print $3}'
|
|
else
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
#########################
|
|
### User Management ###
|
|
#########################
|
|
create_service_user() {
|
|
if ! id "$SERVICE_USER" &>/dev/null; then
|
|
log_info "Creating $SERVICE_USER user"
|
|
useradd --no-create-home --shell /usr/sbin/nologin --system "$SERVICE_USER"
|
|
else
|
|
log_info "User $SERVICE_USER already exists"
|
|
fi
|
|
}
|
|
|
|
#########################
|
|
### Download & Install ##
|
|
#########################
|
|
download_and_install() {
|
|
local version="$1"
|
|
|
|
TMPDIR=$(mktemp -d /tmp/node-exporter-install-XXXXXX)
|
|
local tarball="node_exporter-${version}.linux-${ARCH}.tar.gz"
|
|
local url="https://github.com/prometheus/node_exporter/releases/download/v${version}/${tarball}"
|
|
|
|
log_info "Downloading node_exporter v${version} for ${ARCH}"
|
|
curl -sL -o "${TMPDIR}/${tarball}" "$url" || {
|
|
log_error "Failed to download ${url}"
|
|
exit 1
|
|
}
|
|
|
|
log_info "Extracting archive"
|
|
tar -xzf "${TMPDIR}/${tarball}" -C "$TMPDIR"
|
|
|
|
log_info "Installing binary to ${INSTALL_DIR}/node_exporter"
|
|
cp "${TMPDIR}/node_exporter-${version}.linux-${ARCH}/node_exporter" "${INSTALL_DIR}/node_exporter"
|
|
chown root:root "${INSTALL_DIR}/node_exporter"
|
|
chmod 755 "${INSTALL_DIR}/node_exporter"
|
|
|
|
# SELinux context for RHEL 8+
|
|
if [[ "$OS" == "red" || "$OS" == "rocky" || "$OS" == "almalinux" || "$OS" == "oracle" ]] && [[ "$OSVER" -ge 8 ]]; then
|
|
restorecon -rv "${INSTALL_DIR}/node_exporter" || true
|
|
fi
|
|
}
|
|
|
|
#########################
|
|
### Textfile Directory ##
|
|
#########################
|
|
create_textfile_dir() {
|
|
log_info "Creating textfile collector directory: ${TEXTFILE_DIR}"
|
|
mkdir -p "$TEXTFILE_DIR"
|
|
chown "$SERVICE_USER":"$SERVICE_USER" "$TEXTFILE_DIR"
|
|
}
|
|
|
|
#########################
|
|
### Systemd Service ###
|
|
#########################
|
|
build_exec_start() {
|
|
local exec_start="${INSTALL_DIR}/node_exporter"
|
|
exec_start+=" --collector.textfile.directory=${TEXTFILE_DIR}"
|
|
|
|
# Custom listen port
|
|
if [[ "$PORT" -ne 9100 ]]; then
|
|
exec_start+=" --web.listen-address=:${PORT}"
|
|
fi
|
|
|
|
# Enable additional collectors
|
|
if [[ -n "$COLLECTORS" ]]; then
|
|
IFS=',' read -ra cols <<< "$COLLECTORS"
|
|
for col in "${cols[@]}"; do
|
|
exec_start+=" --collector.${col}"
|
|
done
|
|
fi
|
|
|
|
# Disable collectors
|
|
if [[ -n "$NO_COLLECTORS" ]]; then
|
|
IFS=',' read -ra nocols <<< "$NO_COLLECTORS"
|
|
for col in "${nocols[@]}"; do
|
|
exec_start+=" --no-collector.${col}"
|
|
done
|
|
fi
|
|
|
|
echo "$exec_start"
|
|
}
|
|
|
|
create_systemd_service() {
|
|
local exec_start
|
|
exec_start=$(build_exec_start)
|
|
|
|
log_info "Creating systemd service file"
|
|
cat > /etc/systemd/system/node_exporter.service << EOF
|
|
[Unit]
|
|
Description=Prometheus Node Exporter
|
|
Documentation=https://github.com/prometheus/node_exporter
|
|
Wants=network-online.target
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
User=${SERVICE_USER}
|
|
Group=${SERVICE_USER}
|
|
Type=simple
|
|
ExecStart=${exec_start}
|
|
Restart=always
|
|
RestartSec=5s
|
|
SyslogIdentifier=node_exporter
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable node_exporter
|
|
systemctl start node_exporter
|
|
log_info "node_exporter service started"
|
|
}
|
|
|
|
#########################
|
|
### Firewall Config ###
|
|
#########################
|
|
configure_firewall() {
|
|
if [[ "$OPEN_FIREWALL" == "false" ]]; then
|
|
log_info "Skipping firewall configuration (--no-firewall)"
|
|
return
|
|
fi
|
|
|
|
# UFW (Debian/Ubuntu)
|
|
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "active"; then
|
|
log_info "Configuring UFW firewall rule for port ${PORT}"
|
|
if [[ -n "$PROMETHEUS_IP" ]]; then
|
|
ufw allow from "$PROMETHEUS_IP" to any port "$PORT" proto tcp comment "node_exporter" >/dev/null
|
|
else
|
|
ufw allow "$PORT"/tcp comment "node_exporter" >/dev/null
|
|
fi
|
|
log_info "UFW rule added"
|
|
return
|
|
fi
|
|
|
|
# firewalld (RHEL/Rocky/Alma/Oracle)
|
|
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
|
|
log_info "Configuring firewalld rule for port ${PORT}"
|
|
if [[ -n "$PROMETHEUS_IP" ]]; then
|
|
firewall-cmd --permanent --new-zone=node_exporter 2>/dev/null || true
|
|
firewall-cmd --permanent --zone=node_exporter --add-source="$PROMETHEUS_IP" 2>/dev/null || true
|
|
firewall-cmd --permanent --zone=node_exporter --add-port="${PORT}/tcp" 2>/dev/null || true
|
|
else
|
|
firewall-cmd --permanent --add-port="${PORT}/tcp" >/dev/null
|
|
fi
|
|
firewall-cmd --reload >/dev/null
|
|
log_info "firewalld rule added"
|
|
return
|
|
fi
|
|
|
|
log_info "No active firewall detected, skipping firewall configuration"
|
|
}
|
|
|
|
#########################
|
|
### Verify Install ###
|
|
#########################
|
|
verify_installation() {
|
|
log_info "Verifying node_exporter service"
|
|
|
|
sleep 2
|
|
|
|
if ! systemctl is-active --quiet node_exporter; then
|
|
log_error "node_exporter service is not running"
|
|
systemctl status node_exporter --no-pager | tee -a "$logfile"
|
|
exit 1
|
|
fi
|
|
|
|
if curl -sf "http://localhost:${PORT}/metrics" >/dev/null 2>&1; then
|
|
log_info "Metrics endpoint responding at http://localhost:${PORT}/metrics"
|
|
else
|
|
log_error "Metrics endpoint not responding on port ${PORT}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
#########################
|
|
### Print Summary ###
|
|
#########################
|
|
print_summary() {
|
|
local version
|
|
version=$(get_installed_version)
|
|
|
|
echo
|
|
echo "=== Node Exporter Installation Summary ==="
|
|
echo " Version: ${version}"
|
|
echo " Binary: ${INSTALL_DIR}/node_exporter"
|
|
echo " Service user: ${SERVICE_USER}"
|
|
echo " Port: ${PORT}"
|
|
echo " Textfile dir: ${TEXTFILE_DIR}"
|
|
echo " Metrics URL: http://localhost:${PORT}/metrics"
|
|
[[ -n "$COLLECTORS" ]] && echo " Enabled: ${COLLECTORS}"
|
|
[[ -n "$NO_COLLECTORS" ]] && echo " Disabled: ${NO_COLLECTORS}"
|
|
echo
|
|
echo " Check logs at: ${logfile}"
|
|
echo
|
|
}
|
|
|
|
#########################
|
|
### Install Mode ###
|
|
#########################
|
|
do_install() {
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
log_info "[DRY RUN] Would install node_exporter"
|
|
log_info "[DRY RUN] User: ${SERVICE_USER}"
|
|
log_info "[DRY RUN] Port: ${PORT}"
|
|
log_info "[DRY RUN] Textfile dir: ${TEXTFILE_DIR}"
|
|
log_info "[DRY RUN] Firewall: ${OPEN_FIREWALL}"
|
|
[[ -n "$COLLECTORS" ]] && log_info "[DRY RUN] Enable collectors: ${COLLECTORS}"
|
|
[[ -n "$NO_COLLECTORS" ]] && log_info "[DRY RUN] Disable collectors: ${NO_COLLECTORS}"
|
|
return
|
|
fi
|
|
|
|
local version
|
|
version=$(get_latest_version)
|
|
log_info "Latest version: ${version}"
|
|
|
|
create_service_user
|
|
download_and_install "$version"
|
|
create_textfile_dir
|
|
create_systemd_service
|
|
configure_firewall
|
|
verify_installation
|
|
print_summary
|
|
}
|
|
|
|
#########################
|
|
### Update Mode ###
|
|
#########################
|
|
do_update() {
|
|
if [[ ! -x "${INSTALL_DIR}/node_exporter" ]]; then
|
|
log_error "node_exporter is not installed. Run without --update to install."
|
|
exit 1
|
|
fi
|
|
|
|
local current latest
|
|
current=$(get_installed_version)
|
|
latest=$(get_latest_version)
|
|
|
|
log_info "Installed version: ${current}"
|
|
log_info "Latest version: ${latest}"
|
|
|
|
if [[ "$current" == "$latest" ]]; then
|
|
log_info "Already up to date (v${current}), nothing to do"
|
|
return
|
|
fi
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
log_info "[DRY RUN] Would update node_exporter from v${current} to v${latest}"
|
|
return
|
|
fi
|
|
|
|
log_info "Updating node_exporter from v${current} to v${latest}"
|
|
|
|
systemctl stop node_exporter
|
|
download_and_install "$latest"
|
|
systemctl start node_exporter
|
|
|
|
verify_installation
|
|
|
|
echo
|
|
echo "=== Node Exporter Update Summary ==="
|
|
echo " Previous version: ${current}"
|
|
echo " New version: ${latest}"
|
|
echo " Metrics URL: http://localhost:${PORT}/metrics"
|
|
echo
|
|
}
|
|
|
|
#########################
|
|
### Uninstall Mode ###
|
|
#########################
|
|
do_uninstall() {
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
log_info "[DRY RUN] Would uninstall node_exporter"
|
|
log_info "[DRY RUN] Stop and disable service"
|
|
log_info "[DRY RUN] Remove ${INSTALL_DIR}/node_exporter"
|
|
log_info "[DRY RUN] Remove /etc/systemd/system/node_exporter.service"
|
|
log_info "[DRY RUN] Remove ${TEXTFILE_DIR}"
|
|
log_info "[DRY RUN] Remove user ${SERVICE_USER}"
|
|
log_info "[DRY RUN] Remove firewall rule for port ${PORT}"
|
|
return
|
|
fi
|
|
|
|
log_info "Uninstalling node_exporter"
|
|
|
|
# Stop and disable service
|
|
if systemctl is-active --quiet node_exporter 2>/dev/null; then
|
|
systemctl stop node_exporter
|
|
log_info "Stopped node_exporter service"
|
|
fi
|
|
if systemctl is-enabled --quiet node_exporter 2>/dev/null; then
|
|
systemctl disable node_exporter
|
|
log_info "Disabled node_exporter service"
|
|
fi
|
|
|
|
# Remove service file
|
|
if [[ -f /etc/systemd/system/node_exporter.service ]]; then
|
|
rm -f /etc/systemd/system/node_exporter.service
|
|
log_info "Removed systemd service file"
|
|
fi
|
|
|
|
systemctl daemon-reload
|
|
|
|
# Remove binary
|
|
if [[ -f "${INSTALL_DIR}/node_exporter" ]]; then
|
|
rm -f "${INSTALL_DIR}/node_exporter"
|
|
log_info "Removed binary"
|
|
fi
|
|
|
|
# Remove textfile directory
|
|
if [[ -d "$TEXTFILE_DIR" ]]; then
|
|
rm -rf "$TEXTFILE_DIR"
|
|
log_info "Removed textfile directory"
|
|
fi
|
|
|
|
# Remove user
|
|
if id "$SERVICE_USER" &>/dev/null; then
|
|
userdel "$SERVICE_USER" 2>/dev/null || true
|
|
log_info "Removed user ${SERVICE_USER}"
|
|
fi
|
|
|
|
# Remove firewall rules
|
|
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "active"; then
|
|
ufw delete allow "$PORT"/tcp 2>/dev/null || true
|
|
log_info "Removed UFW rule"
|
|
elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
|
|
firewall-cmd --permanent --remove-port="${PORT}/tcp" 2>/dev/null || true
|
|
firewall-cmd --permanent --delete-zone=node_exporter 2>/dev/null || true
|
|
firewall-cmd --reload >/dev/null 2>/dev/null || true
|
|
log_info "Removed firewalld rule"
|
|
fi
|
|
|
|
log_info "node_exporter has been completely removed"
|
|
}
|
|
|
|
#########################
|
|
### Parse Arguments ###
|
|
#########################
|
|
parse_arguments() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--collectors)
|
|
COLLECTORS="$2"
|
|
shift 2
|
|
;;
|
|
--no-collectors)
|
|
NO_COLLECTORS="$2"
|
|
shift 2
|
|
;;
|
|
--port)
|
|
PORT="$2"
|
|
shift 2
|
|
;;
|
|
--textfile-dir)
|
|
TEXTFILE_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--prometheus-ip)
|
|
PROMETHEUS_IP="$2"
|
|
shift 2
|
|
;;
|
|
--no-firewall)
|
|
OPEN_FIREWALL=false
|
|
shift
|
|
;;
|
|
--update)
|
|
UPDATE_MODE=true
|
|
shift
|
|
;;
|
|
--uninstall)
|
|
UNINSTALL_MODE=true
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
*)
|
|
log_error "Unknown option: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
#########################
|
|
### Main ###
|
|
#########################
|
|
main() {
|
|
mkdir -p "$(dirname "$logfile")"
|
|
touch "$logfile"
|
|
|
|
parse_arguments "$@"
|
|
|
|
log_info "Starting node_exporter installer"
|
|
log_info "Command line: $0 $*"
|
|
|
|
check_permissions
|
|
detect_os
|
|
detect_arch
|
|
setup_package_manager
|
|
install_dependencies
|
|
|
|
if [[ "$UNINSTALL_MODE" == "true" ]]; then
|
|
do_uninstall
|
|
elif [[ "$UPDATE_MODE" == "true" ]]; then
|
|
do_update
|
|
else
|
|
do_install
|
|
fi
|
|
|
|
log_info "Done"
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|