#!/bin/sh
#############################################################################
# mount_monitor.sh
# Author : Abdul Muqeet
# Description : Monitors mounted filesystems on Solaris 11.4.
# Maintains a baseline of expected mount points and alerts
# via HTML email when any deviation is detected.
# Usage : mount_monitor.sh baseline -- record current mounts
# mount_monitor.sh monitor -- compare against baseline
# Compatibility: /bin/sh (POSIX), Solaris 11.4 SPARC/x86
#############################################################################
#----------------------------------------------------------------------------
# CONFIGURATION — adjust these before deployment
#----------------------------------------------------------------------------
BASE_DIR="/var/tmp/mount_monitor"
BASELINE_FILE="${BASE_DIR}/df_mounts_baseline.txt"
CURRENT_FILE="${BASE_DIR}/df_mounts_current.txt"
HTML_REPORT="${BASE_DIR}/mount_report.html"
MAIL_TO="dba-alerts@yourcompany.com"
MAIL_FROM="noreply-mountmonitor@yourcompany.com"
SENDMAIL="/usr/sbin/sendmail"
#----------------------------------------------------------------------------
HOSTNAME_VAL=$(hostname)
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
MODE="$1"
#----------------------------------------------------------------------------
# Helper: get sorted mount point list from df -h (column 6 = Mounted on)
#----------------------------------------------------------------------------
get_mounts() {
df -h | awk 'NR>1 {print $6}' | sort
}
#----------------------------------------------------------------------------
# Helper: ensure BASE_DIR exists
#----------------------------------------------------------------------------
ensure_basedir() {
if [ ! -d "${BASE_DIR}" ]; then
mkdir -p "${BASE_DIR}"
if [ $? -ne 0 ]; then
echo "ERROR: Cannot create BASE_DIR: ${BASE_DIR}" >&2
exit 1
fi
fi
}
#----------------------------------------------------------------------------
# BASELINE MODE
#----------------------------------------------------------------------------
run_baseline() {
ensure_basedir
get_mounts > "${BASELINE_FILE}"
if [ $? -ne 0 ]; then
echo "ERROR: Failed to write baseline file: ${BASELINE_FILE}" >&2
exit 1
fi
COUNT=$(wc -l < "${BASELINE_FILE}" | tr -d ' ')
echo "Baseline captured: ${COUNT} mount points stored in ${BASELINE_FILE}"
echo "Timestamp: ${TIMESTAMP}"
}
#----------------------------------------------------------------------------
# BUILD HTML REPORT
#----------------------------------------------------------------------------
build_html() {
MISSING_FILE="$1"
NEW_FILE="$2"
MISSING_COUNT=$(wc -l < "${MISSING_FILE}" | tr -d ' ')
NEW_COUNT=$(wc -l < "${NEW_FILE}" | tr -d ' ')
if [ "${MISSING_COUNT}" -gt 0 ]; then
MISSING_STATUS='<span style="color:red;font-weight:bold;">YES (ALERT)</span>'
else
MISSING_STATUS='<span style="color:green;font-weight:bold;">NO</span>'
fi
if [ "${NEW_COUNT}" -gt 0 ]; then
NEW_STATUS='<span style="color:orange;font-weight:bold;">YES</span>'
else
NEW_STATUS='<span style="color:green;font-weight:bold;">NO</span>'
fi
#--- Render missing mounts list ---
if [ "${MISSING_COUNT}" -gt 0 ]; then
MISSING_HTML=$(awk '{print "<li style=\"color:red\">" $0 "</li>"}' "${MISSING_FILE}")
else
MISSING_HTML='<li style="color:green">None</li>'
fi
#--- Render new mounts list ---
if [ "${NEW_COUNT}" -gt 0 ]; then
NEW_HTML=$(awk '{print "<li style=\"color:orange\">" $0 "</li>"}' "${NEW_FILE}")
else
NEW_HTML='<li style="color:green">None</li>'
fi
#--- Render baseline and current as <pre> blocks ---
BASELINE_PRE=$(cat "${BASELINE_FILE}")
CURRENT_PRE=$(cat "${CURRENT_FILE}")
cat > "${HTML_REPORT}" << HTMLEOF
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Mount Monitor Alert - ${HOSTNAME_VAL}</title>
</head>
<body style="font-family:monospace;font-size:13px;">
<h2 style="background:#333;color:#fff;padding:8px;">
Mount Point Monitor Report
</h2>
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse:collapse;">
<tr><td><b>Hostname</b></td><td>${HOSTNAME_VAL}</td></tr>
<tr><td><b>Check Time</b></td><td>${TIMESTAMP}</td></tr>
<tr><td><b>Missing Mounts Detected</b></td><td>${MISSING_STATUS}</td></tr>
<tr><td><b>New Mounts Detected</b></td><td>${NEW_STATUS}</td></tr>
</table>
<h3 style="color:red;">Missing Mount Points (in baseline but NOT currently mounted)</h3>
<ul>${MISSING_HTML}</ul>
<h3 style="color:orange;">New Mount Points (currently mounted but NOT in baseline)</h3>
<ul>${NEW_HTML}</ul>
<h3>Baseline Mount Points</h3>
<pre style="background:#f4f4f4;padding:8px;border:1px solid #ccc;">${BASELINE_PRE}</pre>
<h3>Current Mount Points</h3>
<pre style="background:#f4f4f4;padding:8px;border:1px solid #ccc;">${CURRENT_PRE}</pre>
<p style="color:#888;font-size:11px;">
Generated by mount_monitor.sh on ${HOSTNAME_VAL} at ${TIMESTAMP}
</p>
</body>
</html>
HTMLEOF
}
#----------------------------------------------------------------------------
# SEND HTML EMAIL via sendmail
#----------------------------------------------------------------------------
send_email() {
SUBJECT="$1"
if [ ! -x "${SENDMAIL}" ]; then
echo "WARNING: sendmail not found or not executable at ${SENDMAIL}. Skipping email." >&2
return 1
fi
(
echo "MIME-Version: 1.0"
echo "Content-Type: text/html; charset=UTF-8"
echo "From: ${MAIL_FROM}"
echo "To: ${MAIL_TO}"
echo "Subject: ${SUBJECT}"
echo ""
cat "${HTML_REPORT}"
) | "${SENDMAIL}" -f "${MAIL_FROM}" "${MAIL_TO}"
if [ $? -ne 0 ]; then
echo "WARNING: sendmail exited with an error. Check mail logs." >&2
else
echo "Alert email sent to ${MAIL_TO}"
fi
}
#----------------------------------------------------------------------------
# MONITOR MODE
#----------------------------------------------------------------------------
run_monitor() {
ensure_basedir
# Verify baseline exists
if [ ! -f "${BASELINE_FILE}" ]; then
echo "ERROR: Baseline file not found: ${BASELINE_FILE}" >&2
echo " Run '$0 baseline' on a healthy system first." >&2
exit 1
fi
# Capture current mount points
get_mounts > "${CURRENT_FILE}"
if [ $? -ne 0 ]; then
echo "ERROR: Failed to capture current mount points." >&2
exit 1
fi
# Compare: mounts in baseline but NOT current = missing
MISSING_FILE="${BASE_DIR}/mounts_missing.txt"
# Compare: mounts in current but NOT baseline = new
NEW_FILE="${BASE_DIR}/mounts_new.txt"
comm -23 "${BASELINE_FILE}" "${CURRENT_FILE}" > "${MISSING_FILE}"
comm -13 "${BASELINE_FILE}" "${CURRENT_FILE}" > "${NEW_FILE}"
MISSING_COUNT=$(wc -l < "${MISSING_FILE}" | tr -d ' ')
NEW_COUNT=$(wc -l < "${NEW_FILE}" | tr -d ' ')
if [ "${MISSING_COUNT}" -eq 0 ] && [ "${NEW_COUNT}" -eq 0 ]; then
echo "OK: No mount point changes detected at ${TIMESTAMP}"
exit 0
fi
# There are differences — build report and send alert
echo "ALERT: Mount point deviation detected at ${TIMESTAMP}"
echo " Missing : ${MISSING_COUNT}"
echo " New : ${NEW_COUNT}"
build_html "${MISSING_FILE}" "${NEW_FILE}"
SUBJECT="[MOUNT ALERT] ${HOSTNAME_VAL} - Missing:${MISSING_COUNT} New:${NEW_COUNT} - ${TIMESTAMP}"
send_email "${SUBJECT}"
exit 2 # non-zero so cron/SMF can flag this run as alerting
}
#----------------------------------------------------------------------------
# MAIN
#----------------------------------------------------------------------------
case "${MODE}" in
baseline)
run_baseline
;;
monitor)
run_monitor
;;
*)
echo "Usage: $0 { baseline | monitor }" >&2
echo ""
echo " baseline -- Capture current mounts as the reference baseline."
echo " Run once on a known-healthy system."
echo " monitor -- Compare current mounts against baseline."
echo " Schedule via cron or SMF for continuous monitoring."
exit 1
;;
esac
No comments:
Post a Comment