情況基本介紹
原理:根據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 臺!