KarelWintersky revised this gist . Go to revision
No changes
KarelWintersky revised this gist . Go to revision
1 file changed, 4 insertions, 6 deletions
howto.md
@@ -2,11 +2,9 @@ | |||
2 | 2 | ||
3 | 3 | Узнаем chat_id: | |
4 | 4 | ||
5 | - | Пишем боту любое сообщение. | |
5 | + | Пишем боту любое сообщение. | |
6 | 6 | ||
7 | - | Выполняем запрос (подставив свой токен): | |
8 | - | `curl -s "https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates" | jq '.result[0].message.chat.id'` | |
7 | + | Выполняем запрос (подставив свой токен): | |
8 | + | `curl -s "https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates" | jq '.result[0].message.chat.id'` | |
9 | 9 | ||
10 | - | (Если нет jq, установите: sudo apt install jq) | |
11 | - | ||
12 | - | Получаем chat_id (например: `123456789`). | |
10 | + | Получаем chat_id (например: `123456789`). |
KarelWintersky revised this gist . Go to revision
1 file changed, 12 insertions
howto.md(file created)
@@ -0,0 +1,12 @@ | |||
1 | + | Создаем бота через @BotFather, получаем API-токен (например: `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). | |
2 | + | ||
3 | + | Узнаем chat_id: | |
4 | + | ||
5 | + | Пишем боту любое сообщение. | |
6 | + | ||
7 | + | Выполняем запрос (подставив свой токен): | |
8 | + | `curl -s "https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates" | jq '.result[0].message.chat.id'` | |
9 | + | ||
10 | + | (Если нет jq, установите: sudo apt install jq) | |
11 | + | ||
12 | + | Получаем chat_id (например: `123456789`). |
KarelWintersky revised this gist . Go to revision
1 file changed, 14 deletions
gistfile1.txt (file deleted)
@@ -1,14 +0,0 @@ | |||
1 | - | Создаем Telegram-бота и получаем chat_id | |
2 | - | ||
3 | - | Создаем бота через @BotFather, получаем API-токен (например: `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). | |
4 | - | ||
5 | - | Узнаем chat_id: | |
6 | - | ||
7 | - | Пишем боту любое сообщение. | |
8 | - | ||
9 | - | Выполняем запрос (подставив свой токен): | |
10 | - | `curl -s "https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates" | jq '.result[0].message.chat.id'` | |
11 | - | ||
12 | - | (Если нет jq, установите: sudo apt install jq) | |
13 | - | ||
14 | - | Получаем chat_id (например: `123456789`). |
KarelWintersky revised this gist . Go to revision
1 file changed, 14 insertions
gistfile1.txt(file created)
@@ -0,0 +1,14 @@ | |||
1 | + | Создаем Telegram-бота и получаем chat_id | |
2 | + | ||
3 | + | Создаем бота через @BotFather, получаем API-токен (например: `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). | |
4 | + | ||
5 | + | Узнаем chat_id: | |
6 | + | ||
7 | + | Пишем боту любое сообщение. | |
8 | + | ||
9 | + | Выполняем запрос (подставив свой токен): | |
10 | + | `curl -s "https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates" | jq '.result[0].message.chat.id'` | |
11 | + | ||
12 | + | (Если нет jq, установите: sudo apt install jq) | |
13 | + | ||
14 | + | Получаем chat_id (например: `123456789`). |
KarelWintersky revised this gist . Go to revision
3 files changed, 189 insertions
lib_common.sh(file created)
@@ -0,0 +1,28 @@ | |||
1 | + | #!/bin/bash | |
2 | + | ||
3 | + | # --- Telegram sender function --- | |
4 | + | send_to_telegram() { | |
5 | + | local bot_token="$1" | |
6 | + | local chat_id="$2" | |
7 | + | local message="$3" | |
8 | + | local attempt=0 | |
9 | + | local max_attempts=3 | |
10 | + | local timeout=2 | |
11 | + | local result="Failed" | |
12 | + | ||
13 | + | while [ $attempt -lt $max_attempts ]; do | |
14 | + | if curl -s --max-time $timeout -X POST \ | |
15 | + | "https://api.telegram.org/bot${bot_token}/sendMessage" \ | |
16 | + | -d "chat_id=${chat_id}" \ | |
17 | + | -d "text=${message}" \ | |
18 | + | -d "parse_mode=HTML" >/dev/null 2>&1; then | |
19 | + | result="Success" | |
20 | + | break | |
21 | + | fi | |
22 | + | attempt=$((attempt + 1)) | |
23 | + | sleep $timeout | |
24 | + | done | |
25 | + | ||
26 | + | echo "$result" | |
27 | + | } | |
28 | + |
smart_monitor.conf(file created)
@@ -0,0 +1,6 @@ | |||
1 | + | # Конфиг для BlackTower скриптов | |
2 | + | ||
3 | + | TELEGRAM_BOT_TOKEN="..." | |
4 | + | TELEGRAM_CHAT_ID="..." | |
5 | + | TELEGRAM_POST_MESSAGE_ALWAYS=1 # Set to 0 to send only on errors | |
6 | + | LOG_SMART_CHECK="/var/log/smart_check.log" |
smart_monitor.sh(file created)
@@ -0,0 +1,155 @@ | |||
1 | + | #!/bin/bash | |
2 | + | ||
3 | + | # --- Загрузка конфига --- | |
4 | + | CONFIG_FILE="/srv/smart_monitor.conf" | |
5 | + | if [ -f "$CONFIG_FILE" ]; then | |
6 | + | . "$CONFIG_FILE" | |
7 | + | else | |
8 | + | echo "Config file $CONFIG_FILE not found!" >&2 | |
9 | + | exit 1 | |
10 | + | fi | |
11 | + | ||
12 | + | # --- Load library --- | |
13 | + | LIBRARY_FILE="/srv/lib_common.sh" | |
14 | + | if [ -f "$LIBRARY_FILE" ]; then | |
15 | + | . "$LIBRARY_FILE" | |
16 | + | else | |
17 | + | echo "Library file $LIBRARY_FILE not found!" >&2 | |
18 | + | exit 1 | |
19 | + | fi | |
20 | + | ||
21 | + | ||
22 | + | # --- Настройки --- | |
23 | + | LOG="${LOG_FILE:-/var/log/smart_check.log}" | |
24 | + | START_TIME=$(date "+%Y-%m-%d %H:%M:%S") | |
25 | + | ||
26 | + | { | |
27 | + | echo "==========================================" | |
28 | + | echo "Smart check started at $START_TIME" | |
29 | + | echo "" | |
30 | + | echo "Config loaded from: $CONFIG_FILE" | |
31 | + | echo "" | |
32 | + | echo "--- Disk Check Results ---" | |
33 | + | } >> "$LOG" | |
34 | + | ||
35 | + | # --- Поиск дисков (исключаем виртуальные устройства) --- | |
36 | + | DISKS_HDD=$(lsblk -d -o NAME,ROTA,TYPE | awk '$2 == "1" && $3 == "disk" && $1 !~ /^loop|^sr/ {print "/dev/"$1}') | |
37 | + | DISKS_NVME=$(lsblk -d -o NAME,TYPE | awk '$1 ~ /^nvme/ && $2 == "disk" {print "/dev/"$1}') | |
38 | + | DISKS_SSD=$(comm -23 \ | |
39 | + | <(lsblk -d -o NAME,ROTA,TYPE | awk '$2 == "0" && $3 == "disk" && $1 !~ /^loop|^nvme|^sr/ {print "/dev/"$1}' | sort) \ | |
40 | + | <(echo "$DISKS_NVME" | sort)) | |
41 | + | ||
42 | + | # --- Проверка диска --- | |
43 | + | check_disk() { | |
44 | + | local disk=$1 | |
45 | + | local disk_type=$2 | |
46 | + | local -A result=( | |
47 | + | ["disk"]="$disk" | |
48 | + | ["type"]="$disk_type" | |
49 | + | ["status"]="UNKNOWN" | |
50 | + | ["errors"]="" | |
51 | + | ) | |
52 | + | ||
53 | + | local smart_data=$(sudo smartctl -H -A "$disk" 2>/dev/null) | |
54 | + | ||
55 | + | if [[ "$disk_type" == "NVMe" ]]; then | |
56 | + | result["status"]=$(echo "$smart_data" | grep -i "SMART overall-health" | awk '{print $NF}') | |
57 | + | ||
58 | + | # NVMe-специфичные атрибуты | |
59 | + | result["media_errors"]=$(echo "$smart_data" | grep -i "Media and Data Integrity Errors" | awk '{print $NF}') | |
60 | + | result["log_errors"]=$(echo "$smart_data" | grep -i "Error Information Log Entries" | awk '{print $NF}') | |
61 | + | ||
62 | + | [[ "${result["media_errors"]}" =~ ^[0-9]+$ ]] || result["media_errors"]=0 | |
63 | + | [[ "${result["log_errors"]}" =~ ^[0-9]+$ ]] || result["log_errors"]=0 | |
64 | + | ||
65 | + | [ "${result["media_errors"]}" -ne 0 ] && result["errors"]+="Media Errors: ${result["media_errors"]} " | |
66 | + | [ "${result["log_errors"]}" -ne 0 ] && result["errors"]+="Log Errors: ${result["log_errors"]} " | |
67 | + | else | |
68 | + | result["status"]=$(echo "$smart_data" | grep -i "test result" | awk '{print $NF}') | |
69 | + | ||
70 | + | # Атрибуты для HDD/SATA SSD | |
71 | + | while read -r line; do | |
72 | + | key=$(echo "$line" | awk '{print $1}') | |
73 | + | value=$(echo "$line" | awk '{print $10}') | |
74 | + | [ "$value" != "0" ] && result["errors"]+="$key=$value " | |
75 | + | done <<< "$(echo "$smart_data" | grep -E "Reallocated_Sector_Ct|Current_Pending_Sector|Uncorrectable_Error_Ct")" | |
76 | + | fi | |
77 | + | ||
78 | + | result["errors"]="${result["errors"]% }" | |
79 | + | echo "$(declare -p result)" | |
80 | + | } | |
81 | + | ||
82 | + | # --- Основная проверка --- | |
83 | + | declare -a ALL_RESULTS | |
84 | + | ERRORS_FOUND=0 | |
85 | + | ||
86 | + | #{ | |
87 | + | # echo "--- Проверка дисков ---" | |
88 | + | # echo "Типы дисков:" | |
89 | + | # echo "HDD: $DISKS_HDD" | |
90 | + | # echo "SATA SSD: $DISKS_SSD" | |
91 | + | # echo "NVMe: $DISKS_NVME" | |
92 | + | # echo "" | |
93 | + | #} >> "$LOG" | |
94 | + | ||
95 | + | for disk in $DISKS_HDD $DISKS_SSD $DISKS_NVME; do | |
96 | + | if [[ "$DISKS_HDD" == *"$disk"* ]]; then | |
97 | + | disk_type="HDD" | |
98 | + | elif [[ "$DISKS_SSD" == *"$disk"* ]]; then | |
99 | + | disk_type="SATA SSD" | |
100 | + | else | |
101 | + | disk_type="NVMe" | |
102 | + | fi | |
103 | + | ||
104 | + | eval "$(check_disk "$disk" "$disk_type")" | |
105 | + | ||
106 | + | # Человеко-читаемый лог | |
107 | + | { | |
108 | + | printf "Диск: %-16s | Тип: %-8s | Статус: %-6s" "${result[disk]}" "${result[type]}" "${result[status]}" | |
109 | + | [ -n "${result[errors]}" ] && printf " | Ошибки: %s" "${result[errors]}" | |
110 | + | printf "\n" | |
111 | + | } >> "$LOG" | |
112 | + | ||
113 | + | ALL_RESULTS+=("$(declare -p result)") | |
114 | + | [[ "${result[status]}" != "PASSED" ]] && ERRORS_FOUND=1 | |
115 | + | done | |
116 | + | ||
117 | + | # --- Уведомление в Telegram --- | |
118 | + | TELEGRAM_STATUS="Not sent" | |
119 | + | if [[ "$TELEGRAM_POST_MESSAGE_ALWAYS" == "1" || "$ERRORS_FOUND" == "1" ]]; then | |
120 | + | # Формируем сообщение с HTML-разметкой | |
121 | + | MESSAGE="<b>🛡️ SMART Report</b> | $(date '+%Y-%m-%d %H:%M:%S')%0A%0A" | |
122 | + | MESSAGE+="<b>Host</b>: $(hostname)%0A%0A" | |
123 | + | ||
124 | + | for result_str in "${ALL_RESULTS[@]}"; do | |
125 | + | eval "$result_str" | |
126 | + | ||
127 | + | if [[ "${result[status]}" == "PASSED" ]]; then | |
128 | + | MESSAGE+="✅ <b>${result[type]}</b>: <code>${result[disk]}</code> (PASSED)%0A" | |
129 | + | else | |
130 | + | MESSAGE+="🔴 <b>${result[type]}</b>: <code>${result[disk]}</code> (${result[status]})%0A" | |
131 | + | ||
132 | + | if [[ -n "${result[errors]}" ]]; then | |
133 | + | MESSAGE+="<b>Errors</b>: <code>${result[errors]// /</code> <code>}</code>%0A" | |
134 | + | fi | |
135 | + | MESSAGE+="%0A" | |
136 | + | fi | |
137 | + | done | |
138 | + | ||
139 | + | # Отправляем в Telegram | |
140 | + | TELEGRAM_STATUS=$(send_to_telegram "$TELEGRAM_BOT_TOKEN" "$TELEGRAM_CHAT_ID" "$MESSAGE") | |
141 | + | fi | |
142 | + | ||
143 | + | ||
144 | + | ||
145 | + | # --- Финальный лог --- | |
146 | + | { | |
147 | + | echo "" | |
148 | + | echo "--- Notification Status ---" | |
149 | + | echo "Telegram: $TELEGRAM_STATUS" | |
150 | + | echo "" | |
151 | + | echo "Finished at: $(date '+%Y-%m-%d %H:%M:%S')" | |
152 | + | echo "==========================================" | |
153 | + | echo "" | |
154 | + | } >> "$LOG" | |
155 | + |