Trunk Monitor with State-Change Alerts
Trunk Monitor with State-Change Alerts
Unlike simple "check and alert every time" monitors, this script tracks trunk state in a file and only sends a notification when the state changes. You get one "trunk is DOWN" alert and one "trunk has RECOVERED" alert, not 288 identical alerts per day from a 5-minute cron job.
The Script
#!/bin/bash
# trunk-monitor.sh - SIP trunk registration monitor with state tracking
# Install: /opt/pbx-scripts/trunk-monitor.sh
# Cron: */5 * * * * root /opt/pbx-scripts/trunk-monitor.sh
STATE_FILE="/var/run/asterisk/trunk-monitor.state"
SLACK_WEBHOOK="$(asterisk -rx 'dialplan show globals' 2>/dev/null | grep SLACK_WEBHOOK | cut -d'=' -f2-)"
TRUNK_NAME="my-trunk-reg"
HOSTNAME=$(hostname -f)
mkdir -p "$(dirname "$STATE_FILE")"
# Send Slack notification with color-coded attachment
send_slack() {
local message="$1"
local color="$2" # "danger" for down, "good" for up
if [ -z "$SLACK_WEBHOOK" ] || [ "$SLACK_WEBHOOK" = " " ]; then
logger -t trunk-monitor "Slack webhook not configured"
return
fi
local payload
payload=$(jq -n \
--arg color "$color" \
--arg title "PBX Trunk Alert - $HOSTNAME" \
--arg text "$message" \
--argjson ts "$(date +%s)" \
'{attachments: [{color: $color, title: $title, text: $text, ts: $ts}]}')
curl -s -X POST -H 'Content-type: application/json' \
--data "$payload" "$SLACK_WEBHOOK" > /dev/null 2>&1
}
# Check trunk registration status
check_trunk() {
local output
output=$(asterisk -rx 'pjsip show registrations' 2>/dev/null)
if echo "$output" | grep -q "$TRUNK_NAME.*Registered"; then
echo "UP"
elif echo "$output" | grep -q "$TRUNK_NAME"; then
echo "DOWN"
else
echo "MISSING"
fi
}
# State management
get_previous_state() {
[ -f "$STATE_FILE" ] && cat "$STATE_FILE" || echo "UNKNOWN"
}
CURRENT_STATE=$(check_trunk)
PREVIOUS_STATE=$(get_previous_state)
logger -t trunk-monitor "Check: ${TRUNK_NAME} is ${CURRENT_STATE} (was ${PREVIOUS_STATE})"
# Only alert on state change
if [ "$CURRENT_STATE" != "$PREVIOUS_STATE" ]; then
case "$CURRENT_STATE" in
UP)
if [ "$PREVIOUS_STATE" = "DOWN" ] || [ "$PREVIOUS_STATE" = "MISSING" ]; then
send_slack "Trunk *${TRUNK_NAME}* has RECOVERED." "good"
logger -t trunk-monitor "RECOVERED: ${TRUNK_NAME}"
fi
;;
DOWN)
send_slack "Trunk *${TRUNK_NAME}* is DOWN - registration failed." "danger"
logger -t trunk-monitor "DOWN: ${TRUNK_NAME}"
;;
MISSING)
send_slack "Trunk *${TRUNK_NAME}* is MISSING from config." "danger"
logger -t trunk-monitor "MISSING: ${TRUNK_NAME}"
;;
esac
echo "$CURRENT_STATE" > "$STATE_FILE"
fi
case "$CURRENT_STATE" in
UP) exit 0 ;;
*) exit 1 ;;
esac
How It Works
State tracking: The script writes the current state (UP, DOWN, or MISSING) to a file in /var/run/asterisk/. On each run, it compares current state to the saved state. Only if they differ does it fire a notification.
State transitions that trigger alerts:
- UP -> DOWN or UP -> MISSING: sends a red "danger" alert
- DOWN -> UP or MISSING -> UP: sends a green "good" recovery alert
- UP -> UP, DOWN -> DOWN: no notification (no change)
Webhook sourcing: The script reads the Slack webhook URL from Asterisk's global variables (dialplan show globals). This keeps the webhook in one place (your extensions.conf) rather than duplicating it in scripts.
Installation
sudo cp trunk-monitor.sh /opt/pbx-scripts/
sudo chmod +x /opt/pbx-scripts/trunk-monitor.sh
# Add cron job
echo '*/5 * * * * root /opt/pbx-scripts/trunk-monitor.sh >/dev/null 2>&1' | \
sudo tee /etc/cron.d/trunk-monitor
Checking State Manually
# See current tracked state
cat /var/run/asterisk/trunk-monitor.state
# See recent checks in syslog
journalctl -t trunk-monitor --since "1 hour ago"
Extending for Multiple Trunks
To monitor multiple trunks, loop over an array:
TRUNKS=("primary-trunk" "backup-trunk")
for TRUNK_NAME in "${TRUNKS[@]}"; do
STATE_FILE="/var/run/asterisk/trunk-${TRUNK_NAME}.state"
CURRENT_STATE=$(check_trunk)
PREVIOUS_STATE=$(get_previous_state)
# ... same alert logic ...
done
User Notes
No notes yet. Be the first to contribute a tip or example.
Contribute a note
Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.