Megacli 批量磁盘巡检
情况基本介绍
原理:根据megacli -ldpdinfo -aALL -Nolog命令输出的Count错误计数来判断磁盘预错误信息,以实现故障提前处置,避免磁盘连续非预期离线,导致存储集群服务故障。
背景:
现网生产环境,不允许安装额外的软件。
smartctl版本较老且不允许升级,部分smart参数不能识别。
python版本2.7和熟悉的python3差别也挺大,所以选择用shell编写脚本。
步骤:
定义输出目标文件,和结果计数对象。
从host文件里读取server列表,并遍历执行megacli命令。
对megacli的输出进行格式化和计数,并在屏幕中反馈故障信息。
环境要求:
脚本执行主机需要有免密登录目标主机的权限。
目标主机需要有megacli工具,如果有storcli,可以对脚本的计数、匹配语句稍作修改,且storcli功能更强。
目前脚本的不足,和下一步的改进方向:
目前未统计故障硬盘数量,后续可根据磁盘ID等信息统计故障数量并输出。
未对故障信息进行转存记录。
未联动告警功能。
megacli命令过滤后的原始输出:
Virtual Drive: 0 (Target Id: 0)
RAID Level : Primary-1, Secondary-0, RAID Level Qualifier-0
Size : 446.625 GB
State : Optimal
Enclosure Device ID: 8
Slot Number: 38
Device Id: 24
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Firmware state: Online, Spun Up
Drive Temperature :31C (87.80 F)
Enclosure Device ID: 8
Slot Number: 39
Device Id: 34
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Firmware state: Online, Spun Up
Drive Temperature :33C (91.40 F)
shell脚本内容:
#!/bin/bash
# 定义一个空数组failHost,用于存储执行失败的主机
failHost=()
# 判断当前目录下是否有名为“年月日-时分秒-OsdDiskCheck.csv”的文件,如果没有,就新建一个:
ResultFile="$(date +%Y%m%d-%H%M%S)-OsdDiskCheck.csv"
if [ ! -f "$ResultFile" ]; then
touch "$ResultFile"
else
echo "$ResultFile 巡检结果文件已存在,请检查是否需要删除!"
fi
# 读取主机列表文件内容到数组
mapfile -t hosts < "osdServerList.txt"
hostsLen="${#hosts[@]}"
hostsSuc=0
# 遍历数组中的每一行主机名
for line in "${hosts[@]}"; do
echo "----------ssh $line----------"
# 尝试在远端主机$line 上执行命令:
if ! diskOutPut=`ssh $line 'megacli -ldpdinfo -aALL -Nolog | egrep -i "Virtual Drive|RAID Level|^Size|^State|Enclosure Device|Slot Number|Device Id|media error|other error|^Predictive|Firmware stat|Temperature"' && sleep 5`
then
echo "$line 巡检失败,请检查"
failHost+=(" $line")
else
hostsSuc=$((hostsSuc+1))
# 1. 分割outPut对象,:做为分隔符,之前的字符定义为key,之后的字符为value
while IFS=: read -r key value; do
key=`echo $key | awk -F' ' '{print $1}'`
value="${value#"${value%%[![:space:]]*}"}"
# 对命令输出里的Count(错误计数)进行信息组合,加上raid ID和eid、sid
if [[ $key =~ "Virtual Drive" ]]; then
keyVirt="RaidID_`echo $value|awk '{print $1}'`"
elif [[ $key =~ "Enclosure Device ID" ]]; then
keyEID="E_$value"
elif [[ $key =~ "Slot Number" ]]; then
keySID="S_$value"
elif [[ $key =~ "Count" ]]; then
key="Host: $line, $keyVirt, $keyEID~$keySID, $key"
# 如果value不为0,就输出:“发现错误:$key---$value”
if [[ $value != 0 ]]; then
echo "发现磁盘错误:$key---$value"
if [[ $key =~ "Firmware state" ]] && [[ $value =~ "Online" ]]; then
echo "该告警磁盘仍然在线,请密切关注,确认是否手动踢盘!"
else
echo "该告警磁盘已处于故障状态!"
fi
fi
else
key="$key"
fi
echo "$key---$value" >> "$ResultFile"
done <<<"$diskOutPut"
fi
done
# 判断failHost数组是否为空,如果为空,就打印“所有主机巡检执行成功”,否则打印出“执行失败的主机:${failHost[@]}”:
echo "主机列表共 $hostsLen 台主机,巡检执行成功 $hostsSuc 台!"
if [ ${#failHost[@]} -ne 0 ]; then
echo "执行失败的主机有:${failHost[@]}。"
fi
执行输出:
……
----------ssh z***3----------
Warning: Permanently added 'z***3' (ECDSA) to the list of known hosts.
发现磁盘错误:Host: z***3, RaidID_1, E_8~S_0, Other Error Count---6
该告警磁盘已处于故障状态!
发现磁盘错误:Host: z***3, RaidID_6, E_8~S_5, Other Error Count---3
该告警磁盘已处于故障状态!
发现磁盘错误:Host: z***3, RaidID_9, E_8~S_8, Other Error Count---7
该告警磁盘已处于故障状态!
----------ssh z***4----------
Warning: Permanently added 'z***4' (ECDSA) to the list of known hosts.
----------ssh z***7----------
Warning: Permanently added 'z***7' (ECDSA) to the list of known hosts.
发现磁盘错误:Host: z***7, RaidID_2, E_8~S_2, Media Error Count---20
该告警磁盘已处于故障状态!
主机列表共 15 台主机,巡检执行成功 15 台!
bug修复--无法准确识别在线的Error磁盘
修改:
- 增加一个Error输出文件,记录所有的告警和磁盘状态;
- 使用awk对Error输出文件进行处理,并进行排序和故障统计;
#!/bin/bash
# 输出文件定义函数
function checkTouchFile() {
ResultFile="$(date +%Y%m%d-%H%M%S)-OsdDiskCheck.csv"
ResultError="$(date +%Y%m%d-%H%M%S)-OsdDiskError.csv"
if [ ! -f "$ResultFile" ] && [ ! -f "$ResultError" ]; then
touch "$ResultFile"
touch "$ResultError"
else
echo "$ResultFile 或 $ResultError 巡检结果文件已存在,请检查是否需要删除!"
break
fi
}
function readHosts() {
mapfile -t hosts < $1
}
# 磁盘巡检函数:
function diskScan() {
failHost=()
hostsLen="${#hosts[@]}"
hostsSuc=0
for line in "${hosts[@]}"; do
echo "----------ssh $line----------"
if ! diskOutPut=`ssh $line 'megacli -ldpdinfo -aALL -Nolog | egrep -i "Virtual Drive|RAID Level|^Size|^State|Enclosure Device|Slot Number|Device Id|media error|other error|^Predictive|Firmware stat|Temperature"' && sleep 3`
then
echo "$line 巡检失败,请检查"
failHost+=(" $line")
else
hostsSuc=$((hostsSuc+1))
while IFS=: read -r key value; do
key=`echo $key | awk -F' ' '{print $1}'`
value="${value#"${value%%[![:space:]]*}"}"
if [[ $key =~ "Virtual Drive" ]]; then
keyVirt="RaidID_`echo $value|awk '{print $1}'`"
elif [[ $key =~ "Size" ]]; then
keyVol="$value"
elif [[ $key =~ "Enclosure Device ID" ]]; then
keyEID="E_$value"
elif [[ $key =~ "Slot Number" ]]; then
keySID="S_$value"
elif [[ $key =~ "Count" ]]; then
key="Host--$line, $keyVirt $keyVol, $keyEID~$keySID---$key"
if [[ $value != 0 ]]; then
echo "$key:$value---DiskFault" >> "$ResultError"
fi
elif [[ $key =~ "Firmware state" ]]; then
key="Host--$line, $keyVirt $keyVol, $keyEID~$keySID---$key"
if [[ $value =~ "Online" ]]; then
echo "$key---DiskOnline" >> "$ResultError"
else
echo "$key---DiskOffline" >> "$ResultError"
fi
else
key="$key"
fi
echo "$key---$value" >> "$ResultFile"
done <<<"$diskOutPut"
fi
done
echo "主机列表共 $hostsLen 台主机,巡检执行成功 $hostsSuc 台!"
if [ ${#failHost[@]} -ne 0 ]; then
echo "执行失败的主机有:${failHost[@]}。"
fi
}
# awk分析函数:
function analysis() {
has_alert=0
online_count=0
awk -F '---' '
{
lines[$1] = $0;
if ($NF == "DiskFault") {
fault_lines[$1] = 1;
}
}
END {
for (line in fault_lines) {
line_content = lines[line];
split(line_content, fields, "---");
last_field = fields[length(fields)];
for (other_line in lines) {
if (other_line == line) {
split(lines[other_line], other_fields, "---");
other_last_field = other_fields[length(other_fields)];
if (other_last_field == "DiskOnline") {
online_count++;
print "" line_content " 磁盘告警且仍然在线,请密切关注,确认是否手动踢盘!";
has_alert=1;
}
}
}
}
if (!has_alert) {
print "当前没有在线的告警磁盘";
}
print "在线预故障磁盘数量统计: " online_count;
}
' "$ResultError" | sort -k1,1
}
# 调用函数,完成脚本功能:
checkTouchFile
readHosts "osdServerList.txt"
diskScan
analysis
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)