В продолжении статьи: https://habr.com/ru/articles/962290
Пришла мне мысль что для такой задачи должны быть готовые зрелые решения. В частности в smartmontools и оказалось что всё уже давно придумано. Но не до конца …
Решил поделится опытом. Причесал моё словоблудие нейронкой.
📋 Оглавление
⚙️ Основная конфигурация smartd
Файл: /etc/smartmontools/smartd.conf
DEVICESCAN -a -o on -S on \ -s (S/../../7/10|L/../../01/12) \ -m root \ -M exec /path/to/script/smartd-tg-alert.sh \ -n standby,10,q
🔍 Параметры DEVICESCAN
|
Параметр |
Описание |
|---|---|
|
|
Автоматическое обнаружение всех дисков: SATA, NVMe, USB (с поддержкой SMART) |
|
|
Мониторить все SMART-атрибуты, ошибки, health-статус |
|
|
Включить автоматический offline-сбор данных (если поддерживается) |
|
|
Включить автосохранение атрибутов |
|
|
Расписание тестов (см. ниже) |
|
|
Получатель email-уведомлений (резервный канал) |
|
|
Скрипт для кастомных уведомлений |
|
|
Не будить диск в спящем режиме (до 10 пропусков, |
📅 Формат расписания -s
Синтаксис: T/MM/DD/d/HH
|
Поле |
Значение |
Пример |
|---|---|---|
|
|
Тип теста: |
|
|
|
Месяц (01–12 или |
|
|
|
День месяца (01–31 или |
|
|
|
День недели (1–7, где 7 = воскресенье) |
|
|
|
Час запуска (00–23) |
|
Моя конфигурация:
(S/../../7/10|L/../../01/12)
|
Тест |
Расписание |
|---|---|
|
🔹 Короткий |
Каждое воскресенье в 10:00 |
|
🔹 Длинный |
1-го числа каждого месяца в 12:00 |
💡 Важно: Если в момент запуска диск в режиме
standbyи активна опция-n, тест будет пропущен. Для критичных систем можно убрать эту опцию или использовать-n standby,10,m(отправить письмо при пропуске).
🔔 Скрипт уведомлений в Telegram
Файл: /path/to/script/smartd-tg-alert.sh
#!/bin/bashBOT_TOKEN="bot-token"CHAT_ID="chat-id"HOST=$(hostname)MESSAGE="$SMARTD_MESSAGE"curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \ -d "chat_id=$CHAT_ID" \ -d "text=🖥 *$HOST*\n\n$MESSAGE" \ -d "parse_mode=Markdown" >/dev/null 2>&1# Всегда возвращаем 0, чтобы smartd не считал ошибкуexit 0
🔧 Настройка прав:
sudo chmod +x /path/to/script/smartd-tg-alert.shsudo chown root:root /path/to/script/smartd-tg-alert.sh
⚠️ Важно: Бот должен быть запущен, а чат с ним — начат пользователем. Бот не может писать первым.
🔄 Fallback-скрипт: проверка пропущенных тестов
Зачем: Если ПК был выключен в момент планового теста — этот скрипт запустит его при первой возможности.
Файл: /path/to/script/smart-fallback.sh
#!/bin/bash# === CONFIG ===SHORT_MAX_DAYS=8 # если short тест старше 8 дней → запускаемLONG_MAX_DAYS=35 # если long тест старше 35 дней → запускаемLOG_TAG="smart-fallback"log() { logger -t "$LOG_TAG" "$1"}get_power_on_hours() { # Возвращает Power-On Hours (целое) или пусто. # Поддержка ATA и NVMe. local disk="$1" local a out out=$(smartctl -a "$disk" 2>/dev/null) || return 0 # NVMe: "Power On Hours: 1234" a=$(echo "$out" | awk -F: '/^[[:space:]]*Power On Hours[[:space:]]*:/ {gsub(/[^0-9]/,"",$2); print $2; exit}') if [[ -n "$a" ]]; then printf '%s' "$a" return 0 fi # ATA: таблица атрибутов, строка "Power_On_Hours" a=$(echo "$out" | awk '$2=="Power_On_Hours" {print $10; exit}') if [[ "$a" =~ ^[0-9]+$ ]]; then printf '%s' "$a" return 0 fi}get_last_selftest_poh() { # Возвращает Lifetime (hours) из самого свежего self-test указанного типа. # type: "Short" или "Extended" local output="$1" local type="$2" # В selftest-логе smartctl колонка обычно называется "LifeTime(hours)". # Для строк вида: # "# 1 Short offline Completed ... 00% 12345 -" # или: # "# 1 Extended offline Completed ... 00% 12345 -" # NVMe формат другой, например: # "0 Short Completed ... 1353 -" # # Берем первое (самое свежее) совпадение и вынимаем число из колонки lifetime. echo "$output" | awk -v t="$type" ' $0 ~ t && $0 !~ /^[[:space:]]*Num[[:space:]]/ { for (i=1; i<=NF; i++) { if ($i ~ /^[0-9]+$/) n = $i } if (n ~ /^[0-9]+$/) { print n; exit } } '}check_and_run_test() { local disk="$1" # получаем лог тестов local output output=$(smartctl -l selftest "$disk" 2>/dev/null) local poh poh=$(get_power_on_hours "$disk") # --- SHORT TEST --- local last_short_poh short_age_days last_short_poh=$(get_last_selftest_poh "$output" "Short") short_age_days="" if [[ -n "$poh" && -n "$last_short_poh" && "$poh" =~ ^[0-9]+$ && "$last_short_poh" =~ ^[0-9]+$ && "$poh" -ge "$last_short_poh" ]]; then short_age_days=$(( (poh - last_short_poh) / 24 )) fi if [[ -z "$last_short_poh" || -z "$poh" || -z "$short_age_days" || "$short_age_days" -gt "$SHORT_MAX_DAYS" ]]; then log "Running SHORT test on $disk (age_days: ${short_age_days:-unknown})" smartctl -t short "$disk" >/dev/null 2>&1 fi # --- LONG TEST --- local last_long_poh long_age_days last_long_poh=$(get_last_selftest_poh "$output" "Extended") long_age_days="" if [[ -n "$poh" && -n "$last_long_poh" && "$poh" =~ ^[0-9]+$ && "$last_long_poh" =~ ^[0-9]+$ && "$poh" -ge "$last_long_poh" ]]; then long_age_days=$(( (poh - last_long_poh) / 24 )) fi if [[ -z "$last_long_poh" || -z "$poh" || -z "$long_age_days" || "$long_age_days" -gt "$LONG_MAX_DAYS" ]]; then log "Running LONG test on $disk (age_days: ${long_age_days:-unknown})" smartctl -t long "$disk" >/dev/null 2>&1 fi}# === MAIN ===smartctl --scan-open 2>/dev/null | awk '{print $1}' | while IFS= read -r disk; do [[ -z "$disk" ]] && continue if smartctl -c "$disk" &>/dev/null; then check_and_run_test "$disk" fidone
🔧 systemd: сервис + таймер
/etc/systemd/system/smart-fallback.service
[Unit]Description=SMART fallback test runner[Service]Type=oneshotExecStart=/path/to/script/smart-fallback.sh
/etc/systemd/system/smart-fallback.timer
[Unit]Description=Run SMART fallback daily[Timer]OnCalendar=dailyPersistent=true[Install]WantedBy=timers.target
▶️ Активация:
sudo chmod +x /path/to/script/smart-fallback.shsudo systemctl daemon-reloadsudo systemctl enable --now smart-fallback.timer
📊 Weekly Summary: еженедельная сводка
Зачем: Не просто алерты «что-то сломалось», а регулярный обзор состояния всех дисков.
Файл: /path/to/script/smart-summary.sh
#!/bin/bashBOT_TOKEN="bot-token"CHAT_ID="chat-id"HOST=$(hostname)DATE=$(date '+%Y-%m-%d')LOG_TAG="smart-summary"log() { logger -t "$LOG_TAG" -p user.info "$1"}# Используем <b>...</b> вместо *...* для жирногоMESSAGE=$(printf '📊 <b>SMART Summary (%s)</b>\nДата: %s' "$HOST" "$DATE")$'\n\n'for disk in $(smartctl --scan-open | awk '{print $1}'); do if smartctl -c "$disk" &>/dev/null; then # Получаем health (работает и для ATA, и для NVMe) health=$(smartctl -H "$disk" 2>/dev/null | grep -E "SMART overall-health|SMART Health Status" | sed 's/.*: //') # Температура temp=$(smartctl -A "$disk" 2>/dev/null | grep -i temperature | head -n1 | awk -F': ' '{print $2}' | awk '{print $1, $2}') MESSAGE+=$(printf '💽 <b>%s</b> - %s' "$disk" "$health")$'\n\n' if [[ -n "$temp" && "$temp" != *" "* ]]; then # Важно: $(...) срезает завершающие переводы строк, поэтому добавляем их снаружи. MESSAGE+=$(printf '%s' "$temp")$'\n' fi # Ошибки: Reallocated, Pending, Uncorrectable errors=$(smartctl -A "$disk" 2>/dev/null | grep -E "(Reallocated_Sector|Current_Pending|Offline_Uncorrectable|Media_Error)" | awk '$10 > 0 {print " • " $2 ": " $10}') if [[ -n "$errors" ]]; then MESSAGE+=$(printf '❗ Ошибки:\n%s' "$errors")$'\n' fi # Износ SSD wear=$(smartctl -A "$disk" 2>/dev/null | grep -E "(Wear_Leveling|Percent_Lifetime|Media_Wearout)" | head -n1 | awk -F': ' '{print $2}' | awk '{print $1}') if [[ -n "$wear" ]]; then MESSAGE+=$(printf '🧠 Износ: %s' "$wear")$'\n' fi MESSAGE+=$'\n' fidone# Отправляем с parse_mode=HTML и получаем код ответаHTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \ --data-urlencode "chat_id=$CHAT_ID" \ --data-urlencode "text=$MESSAGE" \ --data-urlencode "parse_mode=HTML")# Опционально: логирование ошибокif [[ "$HTTP_CODE" != "200" ]]; then log "[$(date)] SMART summary failed: HTTP $HTTP_CODE"fiexit 0
🔧 systemd: сервис + таймер
/etc/systemd/system/smart-summary.service
[Unit]Description=SMART weekly summary[Service]Type=oneshotExecStart=/path/to/script/smart-summary.sh
/etc/systemd/system/smart-summary.timer
[Unit]Description=Run SMART summary weekly[Timer]OnCalendar=Mon 12:00Persistent=true[Install]WantedBy=timers.target
▶️ Активация:
sudo chmod +x /path/to/script/smart-summary.shsudo systemctl daemon-reloadsudo systemctl enable --now smart-summary.timer
🧩 Архитектура системы
┌─────────────────────────────────────┐│ smartd (демон) ││ • Мониторит диски в реальном времени││ • Запускает тесты по расписанию ││ • Вызывает скрипт при событиях │└────────────┬────────────────────────┘ │ событие (алерт) ▼┌─────────────────────────────────────┐│ 📢 smartd-tg-alert.sh ││ • Мгновенное уведомление в Telegram│└─────────────────────────────────────┘┌─────────────────────────────────────┐│ 🔄 smart-fallback.timer (daily) ││ • Проверяет, не пропущены ли тесты││ • Запускает их при необходимости │└─────────────────────────────────────┘┌─────────────────────────────────────┐│ 📊 smart-summary.timer (weekly) ││ • Формирует сводку по всем дискам ││ • Отправляет отчёт в Telegram │└─────────────────────────────────────┘
🎯 Принципы работы:
|
Компонент |
Тип |
Частота |
Цель |
|---|---|---|---|
|
|
Демон |
Постоянно |
Реактивный мониторинг |
|
Скрипт-хук |
По событию |
Мгновенные алерты |
|
|
Скрипт + timer |
Ежедневно |
Надёжность (пропущенные тесты) |
|
|
Скрипт + timer |
Еженедельно |
Проактивный обзор |
✅ Чеклист проверки
🔧 Конфигурация
-
sudo smartd -d -c /etc/smartmontools/smartd.conf— нет ошибок парсинга -
sudo smartctl --scan— все ожидаемые диски отображаются -
sudo systemctl enable --now smartd— служба активна
🔔 Уведомления
-
Скрипт
smartd-tg-alert.shимеет права+xи владельцаroot -
Бот активен, чат начат, токен верный
-
Проверка отправки в телеграм напрямую:
SMARTD_MESSAGE=$'TEST from smartd\nsecond line' /path/to/script/smartd-tg-alert.sh -
Проверка отправки через
smartd: добавить в/etc/smartmontools/smartd.confвременно строку-M test \И запуститьsudo smartd -c /etc/smartmontools/smartd.conf -q onecheck
🔄 Fallback
-
systemctl list-timers | grep smart-fallback— таймер активен, следующее срабатывание указано -
sudo systemctl start smart-fallback.service— выполняется без ошибок -
В
journalctl -t smart-fallbackпоявляются записи при запуске
📊 Summary
-
systemctl list-timers | grep smart-summary— таймер настроен на воскресенье 12:00 -
sudo systemctl start smart-summary.service— сводка приходит в Telegram -
В сообщении отображаются: здоровье, температура, ошибки, износ (для SSD)
📋 Полезные команды
# Статус службы smartdsudo systemctl status smartd# Логи в реальном времениjournalctl -u smartd -f# Проверка расписания тестов для дискаsudo smartctl -l selftest /dev/sdb# Ручной запуск тестаsudo smartctl -t short /dev/sdbsudo smartctl -t long /dev/sdb# Просмотр результатов тестовsudo smartctl -l selftest /dev/sdb# Проверка таймеровsystemctl list-timers --all | grep smart
ссылка на оригинал статьи https://habr.com/ru/articles/1028462/