tg_monitor_bot/backup/bot.py.bak

149 lines
6.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import asyncio
import logging
from datetime import datetime
from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes
from config import BOT_TOKEN, ADMIN_ID, HOSTS_LIST
from monitor import collect_metrics
# Настройка логирования
logging.basicConfig(level=logging.INFO)
# Кеш для хранения последних собранных данных (чтобы не дергать SSH каждый раз при нажатии кнопки)
CACHE = {}
def format_metrics(data):
"""Формирует красивое сообщение из метрик"""
if "error" in data:
return f"❌ Ошибка подключения к {data['host']}:\n{data['error']}"
m = data['metrics']
host = data['host']
ip = data['ip']
# Блок CPU
cpu_bar = "" * int(m['cpu'] // 5) + "" * (20 - int(m['cpu'] // 5))
text = f"🖥️ *{host} ({ip})*\n"
text += f"🕒 *Uptime:* {m.get('uptime', 'N/A')}\n"
text += f"📊 *Load Avg:* {m.get('load_1', '0')}, {m.get('load_5', '0')}, {m.get('load_15', '0')}\n\n"
text += f"🔥 *CPU:* {m['cpu']:.1f}%\n`{cpu_bar}`\n"
mem_bar = "" * int(m['mem_percent'] // 5) + "" * (20 - int(m['mem_percent'] // 5))
text += f"🧠 *RAM:* {m['mem_used_mb']} MB ({m['mem_percent']}%)\n`{mem_bar}`\n"
# Сеть (за час)
text += f"🌐 *Network (per hour):* 📥 {m['net_rx_mb']} MB | 📤 {m['net_tx_mb']} MB\n"
# Диски
text += "\n💾 *Disks (top 3 by %util):*\n"
for disk in m.get('disks', []):
text += f" └─ {disk['name']}: util {disk['util']:.1f}% (r: {disk['rps']:.1f}/s, w: {disk['wps']:.1f}/s)\n"
# Температуры
if m.get('temps'):
text += "\n🌡️ *Temperatures:*\n"
for i, temp in enumerate(m['temps']):
text += f" └─ Sensor {i+1}: {temp:.1f}°C\n"
# Топ процессов
text += "\n🏆 *Top 5 CPU:*\n```\n"
text += m.get('top_cpu', 'N/A') + "\n```"
text += "🏆 *Top 5 RAM:*\n```\n"
text += m.get('top_mem', 'N/A') + "\n```"
# Логи и безопасность
text += "\n⚠️ *Recent Errors (journalctl -p 3):*\n```\n"
text += m.get('logs_errors', 'N/A')[:300] + "\n```"
text += "\n🛡️ *Fail2ban Status:*\n```\n"
text += m.get('fail2ban_status', 'N/A') + "\n```"
text += "\n🚫 *Fail2ban Logs (last bans):*\n```\n"
text += m.get('fail2ban_logs', 'N/A') + "\n```"
text += f"\n⏱️ *Обновлено:* {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
return text
# OOM проверка
text += "\n💀 *Out of Memory Events:*\n```\n"
text += m.get('oom', 'Нет данных') + "\n```"
async def status_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработчик команды /status"""
if update.effective_user.id != ADMIN_ID:
await update.message.reply_text("⛔ Доступ запрещен. Ты не мой хозяин.")
return
# Создаем клавиатуру с хостами
keyboard = []
for host in HOSTS_LIST:
keyboard.append([InlineKeyboardButton(host['name'], callback_data=f"host_{host['ip']}")])
keyboard.append([InlineKeyboardButton("🔄 Все хосты", callback_data="host_all")])
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
"🔍 Выбери хост для мониторинга или нажми 'Все хосты':",
reply_markup=reply_markup
)
async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработка нажатий на кнопки"""
query = update.callback_query
await query.answer()
if update.effective_user.id != ADMIN_ID:
await query.edit_message_text("⛔ Недостаточно прав.")
return
data = query.data
if data == "host_all":
await query.edit_message_text("⏳ Собираю данные со всех хостов...")
full_report = ""
for host in HOSTS_LIST:
result = collect_metrics(host)
report = format_metrics(result)
full_report += report + "\n\n" + "="*30 + "\n\n"
# Telegram имеет лимит 4096 символов, разобьем если что
await query.edit_message_text(full_report[:4000])
elif data.startswith("host_"):
ip = data.replace("host_", "")
host = next((h for h in HOSTS_LIST if h['ip'] == ip), None)
if not host:
await query.edit_message_text("Хост не найден")
return
await query.edit_message_text(f"⏳ Собираю данные с {host['name']}...")
result = collect_metrics(host)
report = format_metrics(result)
await query.edit_message_text(report, parse_mode="Markdown")
async def scheduled_job(context: ContextTypes.DEFAULT_TYPE):
"""Функция, вызываемая раз в час"""
bot: Bot = context.bot
for host in HOSTS_LIST:
result = collect_metrics(host)
report = format_metrics(result)
try:
await bot.send_message(chat_id=ADMIN_ID, text=report, parse_mode="Markdown")
except Exception as e:
await bot.send_message(chat_id=ADMIN_ID, text=f"Ошибка отправки для {host['name']}: {e}")
def main():
app = Application.builder().token(BOT_TOKEN).build()
# Регистрируем команды
app.add_handler(CommandHandler("status", status_command))
app.add_handler(CallbackQueryHandler(button_callback))
# Настройка шедулера (раз в час)
job_queue = app.job_queue
# Запускаем сразу при старте, потом каждый час
job_queue.run_repeating(scheduled_job, interval=3600, first=10) # first=10 (через 10 сек после запуска)
print("🤖 Бот запущен и готов к работе!")
app.run_polling()
if __name__ == "__main__":
main()