Комментарии 26
smartd не проще настроить, чем костыли выдумывать?
smartd шлёт на почту отчеты, хорошо бы научить его слать ещё в телеграм. Хотя тут можно на уровне почты передавать письма скрипту и делать дальше с ними что угодно.
На почту много кто умеет слать, например, виндовый CrystalDiskInfo. Кстати, он опенсорсный, так что технически можно и его научить отправлять в TG.
Тся.
"Reallocated > 0" и разве этого недостаточно? Надо поглумиться ради хелловина что-ли? Положите его в плов и выкиньте вместе с луком...
Смотря для чего, для помойки нормально. Для критических применений в утиль от греха подальше. По идее важна вообще динамика появился 1 пендинг>1 релокейт и 5 лет так висит - ну ладно. Ну и в статье мешанина из дисков и твердотельных, которые немножко по разному работают и оцениваются. И восстановить что то викторией итп. никогда ничего было нельзя - можно только до упора писать в не читаемый сектор с надежной что контроллер сам его переназначит.
"Reallocated > 0" и разве этого недостаточно?
А есть разница между собственно Reallocated и попыток Reallocated?
А негде посмотреть попытки переназначения, это нутрянка диска и доступа к ней у простых смертных нет. Есть только уже релокейты/переназначенные сектора и пендинги/кандидаты. Кандидаты - это не обязательно битые сектора, может кривая запись и не может прочитаться и контроллер пометил сектор, а если перезаписать сектор все будет нормально. Это собственно "ремонт" Викторией в режиме Эрейз, Ремап тоже самое только ПО делает очень много попыток записи в сектор.
Это собственно "ремонт" Викторией в режиме Эрейз, Ремап тоже самое
т.е. по факту это никакое не лечение? И получается что диск с одним таким сектором может как и долго-долго жить нормально с постоянными перезаписями , так и внезапно окончательно отказать?
Инфа из смарта не даёт никакой информации по одиночному дефекту в конкретный момент времени. Те дает, но только в 1 варианте: критичная инфа - списываем. Не критичный - одиночный дефект игнорируем и смотрим что будет дальше.
Более подробной инфы, не у производителя, уже не будет - некому собрать статистику - в бытовухе диски массово уже не используются, в датацентрах их(надеюсь) сразу списывают... Есть те, кто занимаются датарекавери, но к ним диск попадает уже на другом этапе...
Если вы за reallocated раз в неделю следите, то у меня для вас плохи новости. Ибо если диск сыпется всерьёз, то за неделю он рассыпется окончательно.
Так что следить за смартом надо в реальном времени. Ну и диски с reallocated переводить в разряд дискеток или мусорных помоек. А за такими можно и не следить.
А самое забавное, smart ничего не гарантирует. Попалась мне на одном из серверов парочка дисков с идеальным смартом, при этом на них живого места не было, это уже даже не зомби, а скелеты были (куча секторов со временем чтения 0.3-0.5 секунд, то есть попытки с сотой). Правда, они оба сидели в RAID1 и поэтому OS с них таки грузилась, да, за полчаса, но ведь грузилась :)
Поддерживаю. недавно было - диски в RAID1, внезапно в журнале системы пошли ошибки по записи на этот рейд. При этом контроллер говорит что с дисками все в порядке, смарт показывает что ошибок нет. А данные пришлось из ночного бэкапа вытаскивать, так как в базе сплошные ошибки.
Хороший смарт не гарантирует. Но вот плохой смарт обычно всё же гарантирует проблемы.
... столько воды ради неопределенных целей! ... толи хдд, толи ссд м.2 ... а как настраивал новый на первый запуск ни слова ... не туда ты копаешь, что очевидно не всем ... 🤦🏾♂️🥱
Для того чтобы что-то мониторить - неплохо понимать как все работает.
Если вы делали скан диска, после этого провели стирание и состояние ухудшилось, то диск ваш либо уроненый либо головке кирдык.
Мониторинг смарта в этом случае ничего не покажет, сектора читаются с задержкой, но читаются.
Вырастет raw read error rate, но там обычно и так все непросто.
Никто не писал бы mhdd и её наследников если бы достаточно было смарта для диагностики.
Первые 3 абзаца - просто "чаааавооооо"?
Кого изменилось? Когда изменилось? В рот мне ногу, руку и бэдсектора. Из какого криогенного сна автора достали? Времен перфокарт? Или анга-банга-телечанга в пещере?
Никогда, никогда, никогда в жизни нельзя было ЗАСТАВИТЬ сектор добавиться в G-лист. Только если прошивка диска сочла это нужным. Про P-лист в целом промолчу. Ни MHDD, ни Виктория никогда ничего не добавляла сама.
Максимум этого можно добиться с PC3000, WDmarvel и подобными тулзами. И то в основном лишь отчистить G-лист.
И эта логика уже на протяжении лет 20 еще со времен IDE дисков сколько я себя помню.
Размер дефект листа НИКОГДА не был особо публичным. И для каждого диска он всегда был разным.
Тот же P-лист можно было пересоздать только бурн комплектом, которых в паблике обычно днем с огнем не сыщешь.
И ни G, ни P лист не спасал никогда от ситуаций, когда головка размазывает мусор и царапины дальше по поляне. Максимум что можно было - отключить одну голову.
Заберите домохозяек с хабра. Пусть не изобретают велик, curl-ом вызовут GET запрос вебхука в телегу из любого уже существующего софта и будут довольны.
Как человек, у которого диски спокойно доживают до 80-100к часов аптайма и работают без каких либо проблем, если их не греть и не играть в футбол (статистический брак все еще 3-5%), отключить угребищную парковку принудительную (во всякой синей, зеленой серии есть. выставить на уровне софта неактивность 15-30 минут, если так хочется), могу сказать, что все выше действие ради действия.
Коллеги, а может кто подскажет, как можно мониторить под Windows smart ssd дискa или дисков на контроллере perc h710p отданных под cachecade?

Для домашнего сервера небольшой самописный скрипт раз в сутки отправляет в тг информацию по всем основным параметрам, включая smart дисков и состояние raid. Если что не так - светит красным.
Можно скриптик в студию, пожалуйста
import os
import subprocess
import datetime
import psutil
import requests
import shutil
from reportlab.pdfgen import canvas
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter # будем задавать ширину вручную
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# Регистрируем шрифты (убедись, что файлы шрифтов существуют!)
pdfmetrics.registerFont(TTFont('DejaVuSans', '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'))
pdfmetrics.registerFont(TTFont('DejaVuSans-Bold', '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf'))
pdfmetrics.registerFont(TTFont('DejaVuSansMono', '/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf'))
# Параметры для Telegram
BOT_TOKEN = 'token'
CHAT_ID = 'ID_chat'
# Пути для хранения отчётов
SCRIPT_DIR = '/home/user/script/report'
PDF_DIR = os.path.join(SCRIPT_DIR, 'pdf')
os.makedirs(PDF_DIR, exist_ok=True)
# Параметры отрисовки
LINE_HEIGHT = 14
TOP_MARGIN = 50
BOTTOM_MARGIN = 50
PAGE_WIDTH = 595 # фиксированная ширина (A4)
def get_uptime():
try:
return subprocess.check_output(['uptime', '-p'], universal_newlines=True).strip()
except Exception as e:
return f"Ошибка получения аптайма: {e}"
def get_temperatures():
try:
out = subprocess.check_output(['sensors'], universal_newlines=True)
temps = [line.strip() for line in out.splitlines() if '°C' in line]
return "\n".join(temps) if temps else "Нет данных о температуре"
except Exception as e:
return f"Ошибка: {e}"
def get_critical_errors():
try:
cmd = ['journalctl', '-p', 'crit', '--since', '24 hours ago', '--no-pager']
return subprocess.check_output(cmd, universal_newlines=True)
except Exception as e:
return f"Ошибка получения критических ошибок: {e}"
def get_services_status(services):
statuses = {}
for svc in services:
try:
stat = subprocess.check_output(['systemctl', 'is-active', svc], universal_newlines=True).strip()
except subprocess.CalledProcessError:
stat = "inactive"
statuses[svc] = stat
return statuses
def get_disk_usage():
return psutil.disk_usage('/')
def get_smart_status(disk):
if not shutil.which("smartctl"):
return "smartctl не установлен"
try:
return subprocess.check_output(['smartctl', '-a', disk], universal_newlines=True)
except Exception as e:
return f"Ошибка: {e}"
def get_smart_overall(disk):
"""Возвращаем общий статус SMART (например, PASSED) для диска."""
if not shutil.which("smartctl"):
return "smartctl не установлен"
try:
overall_output = subprocess.check_output(['smartctl', '-H', disk], universal_newlines=True)
for line in overall_output.splitlines():
if "SMART overall-health self-assessment test result:" in line:
return line.split(":", 1)[1].strip()
return overall_output.strip()
except Exception as e:
return f"Ошибка: {e}"
def parse_smart_full(disk):
full_output = get_smart_status(disk)
lines = full_output.splitlines()
start_idx = None
end_idx = None
for i, line in enumerate(lines):
if "SMART Attributes Data Structure" in line:
start_idx = i
break
if start_idx is None:
return full_output
for j in range(start_idx, len(lines)):
if lines[j].startswith("SMART Error Log"):
end_idx = j
break
block = lines[start_idx:end_idx] if end_idx else lines[start_idx:]
return "\n".join(block)
def get_raid_status():
try:
with open('/proc/mdstat', 'r') as f:
return f.read()
except Exception as e:
return f"Ошибка получения RAID статуса: {e}"
def get_fail2ban_stats():
jails = ['sshd', 'postgresql', 'vsftpd']
stats = {}
for jail in jails:
try:
out = subprocess.check_output(['fail2ban-client', 'status', jail], universal_newlines=True)
banned = "0"
for line in out.splitlines():
if "Currently banned" in line:
banned = line.split(":")[1].strip()
break
stats[jail] = banned
except Exception as e:
stats[jail] = f"Ошибка: {e}"
return stats
def build_report_lines(report_data):
lines = []
def add_line(text, font="DejaVuSans", size=10, color=colors.black):
lines.append((text, font, size, color))
def add_separator():
add_line("____________________", font="DejaVuSans", size=10, color=colors.black)
# Заголовок
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
add_line(f"Ежедневный отчёт о состоянии системы - {timestamp}", font="DejaVuSans-Bold", size=14)
add_separator()
# 1. Аптайм
add_line("Аптайм системы:", font="DejaVuSans-Bold", size=12)
for line in report_data['uptime'].splitlines():
add_line(line)
add_separator()
# 2. Температуры
add_line("Температуры (по всем датчикам):", font="DejaVuSans-Bold", size=12)
for line in report_data['temperatures'].splitlines():
add_line(line)
add_separator()
# 3. Критические ошибки
add_line("Критические ошибки за последние 24 часа:", font="DejaVuSans-Bold", size=12, color=colors.red)
crit = report_data['critical_errors'].strip()
if crit:
for line in crit.splitlines():
add_line(line, color=colors.red)
else:
add_line("Нет критических ошибок", color=colors.green)
add_separator()
# 4. Состояние критических служб
add_line("Состояние критических служб:", font="DejaVuSans-Bold", size=12)
for svc, stat in report_data['services_status'].items():
col = colors.green if stat == "active" else colors.red
add_line(f"{svc}: {stat}", color=col)
add_separator()
# 5. SMART статус дисков
add_line("SMART статус дисков:", font="DejaVuSans-Bold", size=12)
for disk in report_data['smart']:
overall = get_smart_overall(disk)
header_color = colors.green if "PASSED" in overall.upper() else colors.red
add_line(f"{disk} - {overall}", font="DejaVuSans-Bold", size=10, color=header_color)
smart_text = parse_smart_full(disk)
for line in smart_text.splitlines():
# Выводим SMART-атрибуты обычным (чёрным) шрифтом
add_line(line, font="DejaVuSansMono", size=7, color=colors.black)
add_separator()
# 6. RAID статус
add_line("RAID статус:", font="DejaVuSans-Bold", size=12)
raid_lines = report_data['raid_status'].splitlines()
raid_color = colors.green if ("degraded" not in report_data['raid_status'].lower() and "inactive" not in report_data['raid_status'].lower()) else colors.red
for line in raid_lines:
add_line(line, color=raid_color)
add_separator()
# 7. Использование дискового пространства
add_line("Использование дискового пространства:", font="DejaVuSans-Bold", size=12)
du = report_data['disk_usage']
add_line(f"Общий объём: {du.total / (1024**3):.2f} GB")
add_line(f"Использовано: {du.used / (1024**3):.2f} GB")
add_line(f"Свободно: {du.free / (1024**3):.2f} GB")
add_separator()
# 8. Статистика fail2ban
add_line("Статистика fail2ban (количество забаненных адресов):", font="DejaVuSans-Bold", size=12)
for jail, banned in report_data['fail2ban'].items():
col = colors.green if banned == "0" else colors.red
add_line(f"{jail}: {banned}", color=col)
add_separator()
# 9. Дополнительная информация
add_line("Дополнительная информация:", font="DejaVuSans-Bold", size=12)
load = os.getloadavg()
add_line(f"Load average (1, 5, 15 мин): {load}")
mem = psutil.virtual_memory()
add_line(f"Использование памяти: {mem.percent}%")
add_separator()
return lines
def draw_report(lines, pdf_file_path, page_width, page_height):
c = canvas.Canvas(pdf_file_path, pagesize=(page_width, page_height))
y = page_height - TOP_MARGIN
for text, font, size, color in lines:
c.setFont(font, size)
c.setFillColor(color)
c.drawString(50, y, text)
y -= LINE_HEIGHT
c.save()
def main():
# Собираем данные отчёта
report_data = {}
report_data['uptime'] = get_uptime()
report_data['temperatures'] = get_temperatures()
report_data['critical_errors'] = get_critical_errors()
report_data['services_status'] = get_services_status(['fail2ban', 'ssh', 'postgresql'])
report_data['disk_usage'] = get_disk_usage()
# Задаём список дисков для SMART
report_data['smart'] = ['/dev/sda', '/dev/sdb']
report_data['raid_status'] = get_raid_status()
report_data['fail2ban'] = get_fail2ban_stats()
# Собираем список строк отчёта
lines = build_report_lines(report_data)
total_lines = len(lines)
required_height = TOP_MARGIN + (total_lines * LINE_HEIGHT) + BOTTOM_MARGIN
print(f"Всего строк: {total_lines}, требуемая высота: {required_height}")
now = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
pdf_file = os.path.join(PDF_DIR, f'report_{now}.pdf')
draw_report(lines, pdf_file, PAGE_WIDTH, required_height)
print(f"PDF отчёт сохранён: {pdf_file}")
# Отправляем PDF через Telegram
url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendDocument"
with open(pdf_file, 'rb') as f:
files = {'document': f}
data = {'chat_id': CHAT_ID, 'caption': 'Ежедневный отчёт сервера'}
response = requests.post(url, files=files, data=data)
print("Ответ Telegram:", response.text)
if __name__ == '__main__':
main()Пожалуйста. Бот собирает и отправляет в чат один раз в сутки (через crontab) pdf с параметрами. Здесь у меня из параметров:
- аптайм
- температура
- критические ошибки
- состояние критических служб
- smart дисков
- статус RAID
- использование дискового пространства
- статистика fail2ban
- средняя нагрузка
- использование памяти
Если в виктории пошли красные сектора, ты уже насилуешь труп.
У этого диска явно кончилась область с резервными секторами и это никак не связано умный он или нет, а кончилась она потому что в диск попала пыль, мусор, который в процессе работы задирает поверхность, вот тебе и красные сектора, ты борешься со следствием, а не причиной.

Мониторинг жёстких дисков