飞牛NAS Ping命令监控关机脚本部署指南
步骤1:创建脚本文件
-
登录飞牛NAS的SSH(确保已启用SSH访问)
-
飞牛的系统设置里,设置SSH开启。
在 Windows 上连接飞牛 NAS 的 SSH 详细指南
使用 Windows PowerShell(内置工具,无需安装)
打开 PowerShell(或者CMD):
按
Win + R
输入powershell(或者CMD)
回车或者在开始菜单搜索 "PowerShell" 并打开
连接 SSH:
powershell
ssh 用户名@NAS的IP地址例如:
powershell
ssh admin@192.168.1.100 (其中admin改成你自己的飞牛NAS账号)首次连接确认:
输入
yes
接受主机密钥输入密码:
输入您在飞牛NAS上设置的密码(输入时不会显示字符)
成功连接:
看到类似
admin@freenas:~ $
的提示符表示连接成功
接下来的命令都在powershell(或者CMD)中链接飞牛SSH后
输入:
1.创建脚本目录(默认创建在飞牛文件管理中的app文件夹里):
CMD:
sudo mkdir -p /vol1/1000/app/ping_monitor
sudo chown -R $(whoami) /vol1/1000/app/ping_monitor
2.创建脚本文件:
CMD:
nano /vol1/1000/app/ping_monitor/ping_monitor.sh
3.将脚本完整内容粘贴到文件中(或者可以直接在飞牛的文件里搜索ping_monitor.sh,找到它写入代码,代码在本文章最下面)
4.保存文件(Ctrl+O
,回车,Ctrl+X
)
步骤2:设置脚本权限
CMD:
chmod +x /vol1/1000/app/ping_monitor/ping_monitor.sh
步骤3:安装必要依赖(可以跳过不装)
CMD:
sudo apt update sudo apt install jq -y # 安装JSON处理工具
步骤4:配置脚本参数(可选)
编辑脚本文件修改以下参数:
CMD:
nano /vol1/1000/app/ping_monitor/ping_monitor.sh
需要关注的配置项(最下面代码的内容):
ping_monitor.sh:
TARGET_IP="192.168.0.1" # 修改为您的路由器IP MAX_FAILURES=10 # 连续失败次数阈值(默认10次) MIN_UPTIME=300 # 最小运行时间(默认300秒=5分钟) SHUTDOWN_DELAY=15 # 关机前等待时间(默认15秒)
步骤5:设置定时任务
-
编辑crontab:
CMD:
crontab -e
-
添加以下行(意思是每分钟运行一次ping_monitor.sh):
CMD:
* * * * * /vol1/1000/app/ping_monitor/ping_monitor.sh
-
保存退出(
Ctrl+O
,回车,Ctrl+X
)
步骤6:测试脚本
-
手动运行脚本:
CMD:
/vol1/1000/app/ping_monitor/ping_monitor.sh
-
检查日志:
CMD:
tail -f /vol1/1000/app/ping_monitor/logs/ping_monitor.log
正常输出应类似:
text
2025-07-02 10:30:45 - INFO - ===== Ping监控启动 ===== 2025-07-02 10:30:45 - INFO - 系统运行时间: 12345s 2025-07-02 10:30:45 - INFO - 目标IP: 192.168.0.1, 最大失败次数: 10 2025-07-02 10:30:45 - INFO - 当前失败计数: 0 2025-07-02 10:30:45 - INFO - 状态更新完成。下次检查在1分钟后。
这个代码里的通知功能没有用,无法通知,运行的具体的信息都能在LOG日志里面找到。
ping_monitor.sh:
# Ping监控关机脚本 for 飞牛NAS(防止开机死循环) - 优化版
# 配置参数
TARGET_IP="192.168.0.1" # 监控的目标IP(修改为您的路由器IP)
MAX_FAILURES=10 # 连续失败次数阈值
MIN_UPTIME=300 # 最小运行时间(秒)300秒=5分钟
SHUTDOWN_DELAY=15 # 关机前等待时间(秒)
LOG_DIR="/vol1/1000/app/ping_monitor/logs"
DATA_FILE="/vol1/1000/app/ping_monitor/ping_failure_count.json"
LOCK_FILE="/vol1/1000/app/ping_monitor/.shutdown_lock"
LOG_FILE="$LOG_DIR/ping_monitor.log"
MAX_LOG_SIZE=2048576 # 最大日志大小(1MB)
MAX_LOG_FILES=5 # 保留的历史日志文件数量
# 确保目录存在
mkdir -p "$LOG_DIR" || {
echo "无法创建日志目录: $LOG_DIR" >&2
exit 1
}
# 日志轮转函数
rotate_logs() {
[ -f "$LOG_FILE" ] || return 0
# 检查日志大小
local log_size=$(wc -c < "$LOG_FILE" 2>/dev/null)
[ -z "$log_size" ] && log_size=0
if [ "$log_size" -ge "$MAX_LOG_SIZE" ]; then
# 删除最旧的日志文件
local oldest_log="${LOG_FILE}.${MAX_LOG_FILES}"
[ -f "$oldest_log" ] && rm -f "$oldest_log"
# 轮转日志文件
for i in $(seq $((MAX_LOG_FILES-1)) -1 1); do
local src="${LOG_FILE}.${i}"
local dest="${LOG_FILE}.$((i+1))"
[ -f "$src" ] && mv -f "$src" "$dest"
done
# 移动当前日志
mv -f "$LOG_FILE" "${LOG_FILE}.1"
# 创建新日志文件
echo "日志轮转完成于 $(date)" > "$LOG_FILE"
fi
}
# 日志记录函数
log() {
local level=$1
local message=$2
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
# 安全地轮转日志
rotate_logs 2>/dev/null
# 写入日志
echo -e "${timestamp} - ${level} - ${message}" >> "$LOG_FILE" 2>/dev/null
}
# 发送通知函数
send_notification() {
local title=$1
local message=$2
# 方法1: 使用飞牛官方通知API
if command -v fn_notify &>/dev/null; then
fn_notify -t "$title" -m "$message" -p high >/dev/null 2>&1 && return 0
fi
# 方法2: 使用DBus发送通知
if command -v dbus-send &>/dev/null; then
dbus-send --session --dest=org.freedesktop.Notifications \
--type=method_call /org/freedesktop/Notifications \
org.freedesktop.Notifications.Notify \
string:"Ping Monitor" uint32:0 string:"" \
string:"$title" string:"$message" \
array:string:"" dict:string:string:"" int32:5000 >/dev/null 2>&1 && return 0
fi
# 方法3: 尝试使用curl发送通知(如果API可用)
if command -v curl &>/dev/null; then
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"title\":\"$title\", \"message\":\"$message\", \"priority\":\"high\"}" \
http://localhost:3040/api/notification >/dev/null 2>&1 && return 0
fi
log "WARNING" "无法发送通知: $title - $message"
return 1
}
# Ping检测函数
ping_ip() {
# 使用不同的ping工具以适应不同环境
if command -v ping &>/dev/null; then
ping -c 2 -W 5 "$TARGET_IP" > /dev/null 2>&1
elif command -v busybox &>/dev/null; then
busybox ping -c 2 -W 5 "$TARGET_IP" > /dev/null 2>&1
else
log "ERROR" "未找到ping命令!"
return 1
fi
return $?
}
# 获取系统运行时间(秒)
get_uptime() {
cut -d' ' -f1 /proc/uptime | cut -d. -f1
}
# 增强版加载失败次数
load_failure_count() {
[ -f "$DATA_FILE" ] || return 0
# 安全读取JSON文件
local json_data=$(<"$DATA_FILE")
[ -z "$json_data" ] && return 0
# 使用多种方法解析JSON
local count last_update last_ip
# 方法1: 使用jq
if command -v jq &>/dev/null; then
count=$(jq -r '.count' <<< "$json_data" 2>/dev/null)
last_update=$(jq -r '.last_update' <<< "$json_data" 2>/dev/null)
last_ip=$(jq -r '.last_ip' <<< "$json_data" 2>/dev/null)
fi
# 方法2: 使用grep/awk(备用方法)
if [ -z "$count" ] || [ -z "$last_update" ] || [ -z "$last_ip" ]; then
count=$(grep '"count"' "$DATA_FILE" | awk -F': ' '{print $2}' | tr -d ', ')
last_update=$(grep '"last_update"' "$DATA_FILE" | awk -F': ' '{print $2}' | tr -d ', ')
last_ip=$(grep '"last_ip"' "$DATA_FILE" | awk -F': ' '{print $2}' | tr -d '" ,')
fi
# 验证数据
[[ "$count" =~ ^[0-9]+$ ]] || count=0
[[ "$last_update" =~ ^[0-9]+$ ]] || last_update=0
[[ "$last_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || last_ip=""
local current_time=$(date +%s)
# 检查是否超过24小时或IP改变
if [ "$last_ip" != "$TARGET_IP" ] || \
[ $((current_time - last_update)) -gt 86400 ]; then
log "INFO" "重置计数器 (IP变更或超过24小时)"
echo 0
return
fi
echo "$count"
}
# 增强版保存失败次数
save_failure_count() {
local count=$1
local current_time=$(date +%s)
# 创建临时文件
local temp_file="${DATA_FILE}.tmp.$$"
# 构建JSON数据
cat > "$temp_file" <<EOF
{
"count": $count,
"last_update": $current_time,
"last_ip": "$TARGET_IP"
}
EOF
# 验证并移动文件
if [ -s "$temp_file" ]; then
mv -f "$temp_file" "$DATA_FILE"
chmod 644 "$DATA_FILE"
log "DEBUG" "保存失败计数: $count"
else
log "ERROR" "创建数据文件失败"
rm -f "$temp_file"
fi
}
# 关机提示函数
shutdown_warning() {
local remaining=$1
# 在控制台显示倒计时
if [ -t 1 ]; then
echo -ne "\r\033[K" # 清除当前行
echo -ne "NAS将在 ${remaining}秒 后关机! 按Ctrl+C取消"
fi
# 发送系统通知
if [ $((remaining % 10)) -eq 0 ] || [ $remaining -le 5 ]; then
send_notification "NAS关机警告" "检测到网络故障,NAS将在${remaining}秒后关机!"
fi
# 记录日志
log "WARNING" "关机倒计时: ${remaining}秒"
}
# 飞牛NAS专用关机函数
shutdown_nas() {
log "CRITICAL" "启动关机流程: 连续$MAX_FAILURES次ping失败 ($TARGET_IP)"
# 发送最终关机通知
send_notification "NAS正在关机" "检测到连续${MAX_FAILURES}次网络故障,NAS即将关机!"
# 方法1: 使用飞牛官方关机API
log "INFO" "尝试通过飞牛API关机"
if curl -s -X POST "http://localhost:3040/api/system/shutdown" >/dev/null 2>&1; then
log "INFO" "飞牛API关机命令已发送"
return
fi
# 方法2: 使用DBus关机(飞牛推荐)
log "INFO" "尝试通过DBus关机"
if command -v dbus-send >/dev/null 2>&1; then
if dbus-send --system --print-reply --dest=org.freenas.system \
/org/freenas/system org.freenas.system.Shutdown >/dev/null 2>&1; then
log "INFO" "DBus关机命令已发送"
return
fi
fi
# 方法3: 使用系统ctl关机
log "INFO" "尝试通过systemctl关机"
if command -v systemctl >/dev/null 2>&1; then
systemctl poweroff
if [ $? -eq 0 ]; then
log "INFO" "systemctl poweroff命令已发送"
return
fi
fi
# 方法4: 传统关机命令
log "INFO" "尝试传统shutdown命令"
if /sbin/shutdown -h now; then
log "INFO" "传统shutdown命令已发送"
return
fi
# 方法5: 紧急关机
log "CRITICAL" "所有关机方法均失败! 尝试紧急关机"
sync
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
}
# 清理函数
cleanup() {
rm -f "${DATA_FILE}.tmp.*"
exit 0
}
# 主程序
main() {
trap cleanup EXIT INT TERM
# 检查是否以root身份运行
if [ "$(id -u)" -ne 0 ]; then
echo -e "\n错误: 脚本必须以root权限运行\n" >&2
exit 1
fi
# 检查关机锁文件
if [ -f "$LOCK_FILE" ]; then
log "WARNING" "检测到关机锁文件 - 重置状态"
rm -f "$LOCK_FILE"
save_failure_count 0
fi
# 获取系统运行时间
local uptime=$(get_uptime)
# 检查是否达到最小运行时间
if [ "$uptime" -lt "$MIN_UPTIME" ]; then
log "INFO" "系统运行时间不足 (${uptime}s < ${MIN_UPTIME}s),跳过检查"
save_failure_count 0
send_notification "NAS已启动" "系统正在启动中,监控将在${MIN_UPTIME}秒后开始"
exit 0
fi
log "INFO" "===== Ping监控启动 ====="
log "INFO" "系统运行时间: ${uptime}s"
log "INFO" "目标IP: $TARGET_IP, 最大失败次数: $MAX_FAILURES"
# 加载失败次数
failure_count=$(load_failure_count)
log "INFO" "当前失败计数: $failure_count"
# 执行Ping测试
if ping_ip; then
# Ping成功时重置计数器
if [ "$failure_count" -gt 0 ]; then
log "INFO" "网络恢复! 重置计数器 (原计数: $failure_count)"
send_notification "网络恢复" "到 ${TARGET_IP} 的网络连接已恢复"
fi
save_failure_count 0
else
# Ping失败时增加计数器
failure_count=$((failure_count + 1))
log "WARNING" "Ping失败! 失败计数: $failure_count/$MAX_FAILURES"
save_failure_count "$failure_count"
# 当接近关机阈值时发送警告
if [ $failure_count -ge $((MAX_FAILURES - 1)) ]; then
send_notification "网络故障警告" "到 ${TARGET_IP} 的连接失败 (${failure_count}/${MAX_FAILURES}次)"
fi
# 检查是否达到关机阈值
if [ "$failure_count" -ge "$MAX_FAILURES" ]; then
log "CRITICAL" "达到最大失败次数! 准备关机..."
# 关机前强制重置计数器
save_failure_count 0
# 创建关机锁文件
touch "$LOCK_FILE"
# 关机倒计时
log "WARNING" "开始 ${SHUTDOWN_DELAY} 秒关机倒计时"
for ((i=SHUTDOWN_DELAY; i>0; i--)); do
shutdown_warning $i
sleep 1
done
# 添加空行清除倒计时显示
[ -t 1 ] && echo
# 执行关机
log "CRITICAL" "正在关闭NAS..."
shutdown_nas
exit 0
fi
fi
log "INFO" "状态更新完成。下次检查在1分钟后。"
}
# 执行主程序
main
评论 (0)