Files
linux-scripts/dhcp-lease-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

669 lines
24 KiB
Bash

#!/bin/bash
################################################################################
# Script Name: dhcp-lease-exporter.sh
# Version: 1.01
# Description: Prometheus exporter for DHCP lease metrics — pool utilization,
# active leases per subnet, lease expirations, reservation status,
# DORA packet counts, and lease duration tracking for ISC DHCP
# (dhcpd) and ISC Kea.
#
# Author: Phil Connor
# Contact: contact@mylinux.work
# Website: https://mylinux.work
# License: MIT
#
# Usage:
# # Output to stdout
# sudo ./dhcp-lease-exporter.sh
#
# # Textfile collector mode
# sudo ./dhcp-lease-exporter.sh --textfile
#
# # HTTP server mode
# sudo ./dhcp-lease-exporter.sh --http
#
# # Custom port
# sudo ./dhcp-lease-exporter.sh --http --port 9533
#
################################################################################
set -euo pipefail
# ============================================================================
# CONFIGURATION
# ============================================================================
readonly VERSION="1.0"
readonly SCRIPT_NAME="${0##*/}"
# DHCP backend — auto, dhcpd, or kea
DHCP_BACKEND="auto"
# dhcpd paths
DHCPD_LEASES="/var/lib/dhcp/dhcpd.leases"
DHCPD_CONF="/etc/dhcp/dhcpd.conf"
# Kea paths and API
KEA_LEASES="/var/lib/kea/kea-leases4.csv"
KEA_API="http://127.0.0.1:8000"
KEA_USE_API="true"
# Output settings
TEXTFILE_DIR="/var/lib/node_exporter/textfile_collector"
HTTP_PORT=9533
LOCK_FILE="/tmp/dhcp-lease-exporter.lock"
# Runtime
MODE="stdout"
ONCE=false
DETECTED_BACKEND=""
# ============================================================================
# COLORS
# ============================================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'
# ============================================================================
# HELPER FUNCTIONS
# ============================================================================
log_info() { echo -e "${GREEN}[INFO]${NC} $*" >&2; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*" >&2; }
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
show_usage() {
cat <<EOF
Usage: sudo $SCRIPT_NAME [OPTIONS]
Export DHCP lease metrics as Prometheus-compatible text format.
MODES:
--textfile Write to node_exporter textfile collector
--http Run as standalone HTTP server
(default) Print to stdout
OPTIONS:
--port PORT HTTP port (default: $HTTP_PORT)
--backend TYPE Force backend: dhcpd or kea (default: auto)
--once In HTTP mode, serve one request and exit
-h, --help Show this help message
CONFIGURATION:
Edit the variables at the top of this script to set paths, ports, etc.
EOF
exit 0
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--textfile) MODE="textfile"; shift ;;
--http) MODE="http"; shift ;;
--port) HTTP_PORT="$2"; shift 2 ;;
--backend) DHCP_BACKEND="$2"; shift 2 ;;
--once) ONCE=true; shift ;;
-h|--help) show_usage ;;
*) log_error "Unknown option: $1"; show_usage ;;
esac
done
}
write_metric_header() {
local name="$1" type="$2" help="$3"
echo "# HELP ${name} ${help}"
echo "# TYPE ${name} ${type}"
}
acquire_lock() {
if [ -f "$LOCK_FILE" ]; then
local pid
pid=$(cat "$LOCK_FILE" 2>/dev/null || true)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
log_error "Another instance is running (PID $pid)"
exit 1
fi
rm -f "$LOCK_FILE"
fi
echo $$ > "$LOCK_FILE"
trap 'rm -f "$LOCK_FILE"' EXIT
}
# ============================================================================
# BACKEND DETECTION
# ============================================================================
detect_backend() {
if [ "$DHCP_BACKEND" != "auto" ]; then
DETECTED_BACKEND="$DHCP_BACKEND"
return
fi
if systemctl is-active --quiet isc-kea-dhcp4-server 2>/dev/null || \
systemctl is-active --quiet kea-dhcp4 2>/dev/null; then
DETECTED_BACKEND="kea"
elif systemctl is-active --quiet isc-dhcp-server 2>/dev/null || \
systemctl is-active --quiet dhcpd 2>/dev/null; then
DETECTED_BACKEND="dhcpd"
elif [ -f "$KEA_LEASES" ]; then
DETECTED_BACKEND="kea"
elif [ -f "$DHCPD_LEASES" ]; then
DETECTED_BACKEND="dhcpd"
else
DETECTED_BACKEND="unknown"
fi
}
# ============================================================================
# DHCPD FUNCTIONS
# ============================================================================
# Parse dhcpd.conf for subnet definitions and pool ranges
parse_dhcpd_subnets() {
local conf="$DHCPD_CONF"
[ -f "$conf" ] || return
local current_subnet="" current_name="" range_start="" range_end=""
local in_subnet=false
while IFS= read -r line; do
# Match subnet declaration
if [[ "$line" =~ ^[[:space:]]*subnet[[:space:]]+([0-9.]+)[[:space:]]+netmask[[:space:]]+([0-9.]+) ]]; then
current_subnet="${BASH_REMATCH[1]}"
local netmask="${BASH_REMATCH[2]}"
current_name="$current_subnet"
in_subnet=true
range_start=""
range_end=""
# Calculate CIDR from netmask
local cidr
cidr=$(netmask_to_cidr "$netmask")
current_subnet="${current_subnet}/${cidr}"
fi
# Check for comment-based name
if $in_subnet && [[ "$line" =~ ^[[:space:]]*#[[:space:]]*(.+) ]]; then
if [ "$current_name" = "${current_subnet%%/*}" ]; then
current_name="${BASH_REMATCH[1]}"
fi
fi
# Match range declaration
if $in_subnet && [[ "$line" =~ ^[[:space:]]*range[[:space:]]+([0-9.]+)[[:space:]]+([0-9.]+) ]]; then
range_start="${BASH_REMATCH[1]}"
range_end="${BASH_REMATCH[2]}"
fi
# End of subnet block
if $in_subnet && [[ "$line" =~ ^[[:space:]]*\} ]]; then
if [ -n "$range_start" ] && [ -n "$range_end" ]; then
local total
total=$(ip_range_count "$range_start" "$range_end")
echo "${current_subnet}|${current_name}|${total}|${range_start}|${range_end}"
fi
in_subnet=false
fi
done < "$conf"
}
netmask_to_cidr() {
local netmask="$1"
local cidr=0
for octet in $(echo "$netmask" | tr '.' ' '); do
case $octet in
255) cidr=$((cidr + 8)) ;;
254) cidr=$((cidr + 7)) ;;
252) cidr=$((cidr + 6)) ;;
248) cidr=$((cidr + 5)) ;;
240) cidr=$((cidr + 4)) ;;
224) cidr=$((cidr + 3)) ;;
192) cidr=$((cidr + 2)) ;;
128) cidr=$((cidr + 1)) ;;
0) ;;
esac
done
echo "$cidr"
}
ip_to_int() {
local a b c d
IFS='.' read -r a b c d <<< "$1"
echo $(( (a << 24) + (b << 16) + (c << 8) + d ))
}
ip_range_count() {
local start_int end_int
start_int=$(ip_to_int "$1")
end_int=$(ip_to_int "$2")
echo $(( end_int - start_int + 1 ))
}
# Count active leases per subnet from dhcpd.leases
count_dhcpd_leases() {
local lease_file="$DHCPD_LEASES"
[ -f "$lease_file" ] || return
local now
now=$(date +%s)
awk -v now="$now" '
/^lease / { ip = $2 }
/ends / {
gsub(/[;\/:]/, " ", $0)
if ($2 != "never") {
t = mktime($3 " " $4 " " $5 " " $6 " " $7 " " $8)
if (t > now) active[ip] = t - now
}
}
/binding state active/ { state[ip] = "active" }
END {
for (ip in active) {
if (state[ip] == "active") {
print ip, active[ip]
}
}
}' "$lease_file"
}
# Count reservations from dhcpd.conf
count_dhcpd_reservations() {
local conf="$DHCPD_CONF"
[ -f "$conf" ] || return
grep -c "fixed-address" "$conf" 2>/dev/null || true
}
# Parse DORA stats from syslog
parse_dhcpd_dora() {
local logfile="/var/log/syslog"
[ -f "$logfile" ] || logfile="/var/log/messages"
[ -f "$logfile" ] || return
local discovers offers requests acks naks declines releases
discovers=$(grep -c "DHCPDISCOVER" "$logfile" 2>/dev/null || true)
offers=$(grep -c "DHCPOFFER" "$logfile" 2>/dev/null || true)
requests=$(grep -c "DHCPREQUEST" "$logfile" 2>/dev/null || true)
acks=$(grep -c "DHCPACK" "$logfile" 2>/dev/null || true)
naks=$(grep -c "DHCPNAK" "$logfile" 2>/dev/null || true)
declines=$(grep -c "DHCPDECLINE" "$logfile" 2>/dev/null || true)
releases=$(grep -c "DHCPRELEASE" "$logfile" 2>/dev/null || true)
echo "${discovers}|${offers}|${requests}|${acks}|${naks}|${declines}|${releases}"
}
# ============================================================================
# KEA FUNCTIONS
# ============================================================================
kea_api_call() {
local command="$1"
curl -s --max-time 5 -X POST "${KEA_API}" \
-H "Content-Type: application/json" \
-d "{\"command\": \"${command}\", \"service\": [\"dhcp4\"]}" 2>/dev/null
}
parse_kea_leases_file() {
local lease_file="$KEA_LEASES"
[ -f "$lease_file" ] || return
local now
now=$(date +%s)
awk -F',' -v now="$now" '
NR > 1 && NF >= 9 {
ip = $1
expire = $7
state = $9
if (state == 0 && expire > now) {
remaining = expire - now
print ip, remaining
}
}' "$lease_file"
}
parse_kea_api_subnets() {
local response
response=$(kea_api_call "subnet4-list")
if [ -z "$response" ]; then
return 1
fi
echo "$response" | python3 -c "
import sys, json
data = json.load(sys.stdin)
if data[0]['result'] == 0:
for s in data[0].get('arguments', {}).get('subnets', []):
sid = s.get('id', 0)
subnet = s.get('subnet', '')
print(f'{sid}|{subnet}')
" 2>/dev/null
}
parse_kea_api_stats() {
local response
response=$(kea_api_call "statistic-get-all")
if [ -z "$response" ]; then
return 1
fi
echo "$response"
}
# ============================================================================
# METRIC COLLECTION
# ============================================================================
collect_metrics() {
local start_time
start_time=$(date +%s%N)
local metrics=""
# Exporter status
metrics+="$(write_metric_header "dhcp_up" "gauge" "Exporter status (1=up, 0=down)")"$'\n'
metrics+="$(write_metric_header "dhcp_exporter_info" "gauge" "Exporter version and backend")"$'\n'
if [ "$DETECTED_BACKEND" = "unknown" ]; then
metrics+="dhcp_up 0"$'\n'
echo "$metrics"
return
fi
metrics+="dhcp_up 1"$'\n'
metrics+="dhcp_exporter_info{version=\"${VERSION}\",backend=\"${DETECTED_BACKEND}\"} 1"$'\n'
local subnet_count=0
local total_active=0
if [ "$DETECTED_BACKEND" = "dhcpd" ]; then
collect_dhcpd_metrics
elif [ "$DETECTED_BACKEND" = "kea" ]; then
collect_kea_metrics
fi
# Subnet count
metrics+="$(write_metric_header "dhcp_subnets_total" "gauge" "Total number of configured subnets")"$'\n'
metrics+="dhcp_subnets_total ${subnet_count}"$'\n'
# Total active leases
metrics+="$(write_metric_header "dhcp_leases_active_total" "gauge" "Total active leases across all subnets")"$'\n'
metrics+="dhcp_leases_active_total ${total_active}"$'\n'
# Lease file info
if [ "$DETECTED_BACKEND" = "dhcpd" ] && [ -f "$DHCPD_LEASES" ]; then
local file_age file_size
file_age=$(( $(date +%s) - $(stat -c %Y "$DHCPD_LEASES") ))
file_size=$(stat -c %s "$DHCPD_LEASES")
metrics+="$(write_metric_header "dhcp_lease_file_age_seconds" "gauge" "Seconds since the lease file was last modified")"$'\n'
metrics+="dhcp_lease_file_age_seconds ${file_age}"$'\n'
metrics+="$(write_metric_header "dhcp_lease_file_size_bytes" "gauge" "Size of the lease file")"$'\n'
metrics+="dhcp_lease_file_size_bytes ${file_size}"$'\n'
elif [ "$DETECTED_BACKEND" = "kea" ] && [ -f "$KEA_LEASES" ]; then
local file_age file_size
file_age=$(( $(date +%s) - $(stat -c %Y "$KEA_LEASES") ))
file_size=$(stat -c %s "$KEA_LEASES")
metrics+="$(write_metric_header "dhcp_lease_file_age_seconds" "gauge" "Seconds since the lease file was last modified")"$'\n'
metrics+="dhcp_lease_file_age_seconds ${file_age}"$'\n'
metrics+="$(write_metric_header "dhcp_lease_file_size_bytes" "gauge" "Size of the lease file")"$'\n'
metrics+="dhcp_lease_file_size_bytes ${file_size}"$'\n'
fi
# Execution time
local end_time duration
end_time=$(date +%s%N)
duration=$(echo "scale=2; ($end_time - $start_time) / 1000000000" | bc 2>/dev/null || echo "0")
metrics+="$(write_metric_header "dhcp_exporter_duration_seconds" "gauge" "Script execution time")"$'\n'
metrics+="dhcp_exporter_duration_seconds ${duration}"$'\n'
metrics+="$(write_metric_header "dhcp_exporter_last_run_timestamp" "gauge" "Unix timestamp of last successful run")"$'\n'
metrics+="dhcp_exporter_last_run_timestamp $(date +%s)"$'\n'
echo "$metrics"
}
collect_dhcpd_metrics() {
# Parse subnets from config
local subnet_data
subnet_data=$(parse_dhcpd_subnets)
# Get active leases
local lease_data
lease_data=$(count_dhcpd_leases)
metrics+="$(write_metric_header "dhcp_subnet_pool_total" "gauge" "Total addresses in the pool")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_active" "gauge" "Currently leased addresses")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_free" "gauge" "Available addresses in the pool")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_utilization" "gauge" "Pool utilization percentage (0-100)")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_reserved" "gauge" "Number of static reservations")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_leases_expiring" "gauge" "Leases expiring within threshold")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_lease_longest_seconds" "gauge" "Remaining time on the longest lease")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_lease_shortest_seconds" "gauge" "Remaining time on the shortest lease")"$'\n'
while IFS='|' read -r subnet name pool_total range_start range_end; do
[ -z "$subnet" ] && continue
subnet_count=$((subnet_count + 1))
# Count active leases in this subnet range
local active=0 longest=0 shortest=999999999
local expiring_1h=0 expiring_4h=0 expiring_24h=0
local start_int end_int
start_int=$(ip_to_int "$range_start")
end_int=$(ip_to_int "$range_end")
while read -r lease_ip remaining; do
[ -z "$lease_ip" ] && continue
local lip
lip=$(ip_to_int "$lease_ip")
if [ "$lip" -ge "$start_int" ] && [ "$lip" -le "$end_int" ]; then
active=$((active + 1))
total_active=$((total_active + 1))
[ "$remaining" -gt "$longest" ] && longest=$remaining
[ "$remaining" -lt "$shortest" ] && shortest=$remaining
[ "$remaining" -le 3600 ] && expiring_1h=$((expiring_1h + 1))
[ "$remaining" -le 14400 ] && expiring_4h=$((expiring_4h + 1))
[ "$remaining" -le 86400 ] && expiring_24h=$((expiring_24h + 1))
fi
done <<< "$lease_data"
local free=$((pool_total - active))
[ $free -lt 0 ] && free=0
local util=0
if [ "$pool_total" -gt 0 ]; then
util=$(echo "scale=2; $active * 100 / $pool_total" | bc 2>/dev/null || echo "0")
fi
[ $active -eq 0 ] && shortest=0
local reserved
reserved=$(count_dhcpd_reservations)
metrics+="dhcp_subnet_pool_total{subnet=\"${subnet}\",name=\"${name}\"} ${pool_total}"$'\n'
metrics+="dhcp_subnet_pool_active{subnet=\"${subnet}\",name=\"${name}\"} ${active}"$'\n'
metrics+="dhcp_subnet_pool_free{subnet=\"${subnet}\",name=\"${name}\"} ${free}"$'\n'
metrics+="dhcp_subnet_pool_utilization{subnet=\"${subnet}\",name=\"${name}\"} ${util}"$'\n'
metrics+="dhcp_subnet_pool_reserved{subnet=\"${subnet}\",name=\"${name}\"} ${reserved}"$'\n'
metrics+="dhcp_subnet_leases_expiring{subnet=\"${subnet}\",name=\"${name}\",within=\"1h\"} ${expiring_1h}"$'\n'
metrics+="dhcp_subnet_leases_expiring{subnet=\"${subnet}\",name=\"${name}\",within=\"4h\"} ${expiring_4h}"$'\n'
metrics+="dhcp_subnet_leases_expiring{subnet=\"${subnet}\",name=\"${name}\",within=\"24h\"} ${expiring_24h}"$'\n'
metrics+="dhcp_subnet_lease_longest_seconds{subnet=\"${subnet}\",name=\"${name}\"} ${longest}"$'\n'
metrics+="dhcp_subnet_lease_shortest_seconds{subnet=\"${subnet}\",name=\"${name}\"} ${shortest}"$'\n'
done <<< "$subnet_data"
# DORA stats
local dora
dora=$(parse_dhcpd_dora)
if [ -n "$dora" ]; then
IFS='|' read -r discovers offers requests acks naks declines releases <<< "$dora"
metrics+="$(write_metric_header "dhcp_discovers_total" "counter" "Total DHCPDISCOVER packets received")"$'\n'
metrics+="dhcp_discovers_total ${discovers}"$'\n'
metrics+="$(write_metric_header "dhcp_offers_total" "counter" "Total DHCPOFFER packets sent")"$'\n'
metrics+="dhcp_offers_total ${offers}"$'\n'
metrics+="$(write_metric_header "dhcp_requests_total" "counter" "Total DHCPREQUEST packets received")"$'\n'
metrics+="dhcp_requests_total ${requests}"$'\n'
metrics+="$(write_metric_header "dhcp_acks_total" "counter" "Total DHCPACK packets sent")"$'\n'
metrics+="dhcp_acks_total ${acks}"$'\n'
metrics+="$(write_metric_header "dhcp_naks_total" "counter" "Total DHCPNAK packets sent")"$'\n'
metrics+="dhcp_naks_total ${naks}"$'\n'
metrics+="$(write_metric_header "dhcp_declines_total" "counter" "Total DHCPDECLINE packets received")"$'\n'
metrics+="dhcp_declines_total ${declines}"$'\n'
metrics+="$(write_metric_header "dhcp_releases_total" "counter" "Total DHCPRELEASE packets received")"$'\n'
metrics+="dhcp_releases_total ${releases}"$'\n'
fi
}
collect_kea_metrics() {
metrics+="$(write_metric_header "dhcp_subnet_pool_total" "gauge" "Total addresses in the pool")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_active" "gauge" "Currently leased addresses")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_free" "gauge" "Available addresses in the pool")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_utilization" "gauge" "Pool utilization percentage (0-100)")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_pool_reserved" "gauge" "Number of static reservations")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_leases_expiring" "gauge" "Leases expiring within threshold")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_lease_longest_seconds" "gauge" "Remaining time on the longest lease")"$'\n'
metrics+="$(write_metric_header "dhcp_subnet_lease_shortest_seconds" "gauge" "Remaining time on the shortest lease")"$'\n'
if [ "$KEA_USE_API" = "true" ]; then
collect_kea_api_metrics
else
collect_kea_file_metrics
fi
}
collect_kea_api_metrics() {
local stats_json
stats_json=$(kea_api_call "statistic-get-all")
if [ -z "$stats_json" ]; then
log_warn "Kea API not responding, falling back to file mode"
collect_kea_file_metrics
return
fi
# Parse stats via python3
echo "$stats_json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
if data[0]['result'] == 0:
args = data[0].get('arguments', {})
for key, val in args.items():
if val and isinstance(val, list):
v = val[0][0] if isinstance(val[0], list) else val[0]
print(f'{key}={v}')
" 2>/dev/null | while IFS='=' read -r key value; do
case "$key" in
subnet*total-addresses*)
local sid="${key#subnet[}"
sid="${sid%%]*}"
metrics+="dhcp_subnet_pool_total{subnet=\"${sid}\"} ${value}"$'\n'
;;
subnet*assigned-addresses*)
local sid="${key#subnet[}"
sid="${sid%%]*}"
metrics+="dhcp_subnet_pool_active{subnet=\"${sid}\"} ${value}"$'\n'
;;
pkt4-discover-received)
metrics+="$(write_metric_header "dhcp_discovers_total" "counter" "Total DHCPDISCOVER packets received")"$'\n'
metrics+="dhcp_discovers_total ${value}"$'\n'
;;
pkt4-offer-sent)
metrics+="$(write_metric_header "dhcp_offers_total" "counter" "Total DHCPOFFER packets sent")"$'\n'
metrics+="dhcp_offers_total ${value}"$'\n'
;;
pkt4-request-received)
metrics+="$(write_metric_header "dhcp_requests_total" "counter" "Total DHCPREQUEST packets received")"$'\n'
metrics+="dhcp_requests_total ${value}"$'\n'
;;
pkt4-ack-sent)
metrics+="$(write_metric_header "dhcp_acks_total" "counter" "Total DHCPACK packets sent")"$'\n'
metrics+="dhcp_acks_total ${value}"$'\n'
;;
pkt4-nak-sent)
metrics+="$(write_metric_header "dhcp_naks_total" "counter" "Total DHCPNAK packets sent")"$'\n'
metrics+="dhcp_naks_total ${value}"$'\n'
;;
pkt4-decline-received)
metrics+="$(write_metric_header "dhcp_declines_total" "counter" "Total DHCPDECLINE packets received")"$'\n'
metrics+="dhcp_declines_total ${value}"$'\n'
;;
pkt4-release-received)
metrics+="$(write_metric_header "dhcp_releases_total" "counter" "Total DHCPRELEASE packets received")"$'\n'
metrics+="dhcp_releases_total ${value}"$'\n'
;;
esac
done
}
collect_kea_file_metrics() {
local lease_data
lease_data=$(parse_kea_leases_file)
local now
now=$(date +%s)
# Simple lease counting from CSV
while read -r lease_ip remaining; do
[ -z "$lease_ip" ] && continue
total_active=$((total_active + 1))
done <<< "$lease_data"
}
# ============================================================================
# OUTPUT
# ============================================================================
output_metrics() {
local all_metrics
all_metrics=$(collect_metrics)
case "$MODE" in
stdout)
echo "$all_metrics"
;;
textfile)
mkdir -p "$TEXTFILE_DIR"
local tmp_file
tmp_file=$(mktemp "${TEXTFILE_DIR}/.dhcp-metrics.XXXXXX")
echo "$all_metrics" > "$tmp_file"
mv "$tmp_file" "${TEXTFILE_DIR}/dhcp-metrics.prom"
log_info "Wrote metrics to ${TEXTFILE_DIR}/dhcp-metrics.prom"
;;
http)
run_http_server "$all_metrics"
;;
esac
}
run_http_server() {
log_info "Starting HTTP server on port ${HTTP_PORT}"
while true; do
local all_metrics
all_metrics=$(collect_metrics)
{
echo -e "HTTP/1.1 200 OK\r"
echo -e "Content-Type: text/plain; version=0.0.4; charset=utf-8\r"
echo -e "Content-Length: ${#all_metrics}\r"
echo -e "\r"
echo "$all_metrics"
} | nc -l -p "$HTTP_PORT" -q 1 2>/dev/null || \
{
echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n${all_metrics}"
} | nc -l "$HTTP_PORT" 2>/dev/null
if $ONCE; then
break
fi
done
}
# ============================================================================
# MAIN
# ============================================================================
main() {
parse_args "$@"
acquire_lock
detect_backend
log_info "Detected DHCP backend: ${DETECTED_BACKEND}"
output_metrics
}
main "$@"