194 lines
6.2 KiB
Python
194 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Скрипт мониторинга FRR BGP сервера
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import time
|
|
import subprocess
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Dict, Any
|
|
|
|
# Настройки
|
|
LOG_FILE = "/app/logs/monitor.log"
|
|
STATUS_FILE = "/app/logs/status.json"
|
|
|
|
def log_message(message: str):
|
|
"""Запись сообщения в лог"""
|
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
|
log_entry = f"[{timestamp}] {message}"
|
|
|
|
print(log_entry, flush=True)
|
|
|
|
try:
|
|
with open(LOG_FILE, "a") as f:
|
|
f.write(log_entry + "\n")
|
|
except (PermissionError, OSError):
|
|
pass
|
|
|
|
def run_vtysh_command(command: str) -> str:
|
|
"""Выполнение команды через vtysh"""
|
|
try:
|
|
result = subprocess.run(
|
|
['vtysh', '-c', command],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
return result.stdout.strip()
|
|
else:
|
|
log_message(f"vtysh command failed: {command}")
|
|
return ""
|
|
except Exception as e:
|
|
log_message(f"Error running vtysh command '{command}': {e}")
|
|
return ""
|
|
|
|
def get_bgp_summary() -> Dict[str, Any]:
|
|
"""Получение сводки BGP"""
|
|
summary = run_vtysh_command("show ip bgp summary")
|
|
|
|
if not summary:
|
|
return {"error": "Could not get BGP summary"}
|
|
|
|
# Парсинг вывода BGP summary
|
|
lines = summary.split('\n')
|
|
neighbors = []
|
|
|
|
for line in lines:
|
|
if 'BGP neighbor' in line and 'remote AS' in line:
|
|
parts = line.split()
|
|
if len(parts) >= 8:
|
|
neighbor = {
|
|
"ip": parts[2].rstrip(','),
|
|
"remote_as": parts[7],
|
|
"state": parts[-1] if len(parts) > 7 else "Unknown"
|
|
}
|
|
neighbors.append(neighbor)
|
|
|
|
return {
|
|
"neighbors": neighbors,
|
|
"raw_output": summary
|
|
}
|
|
|
|
def get_bgp_routes() -> Dict[str, Any]:
|
|
"""Получение BGP маршрутов"""
|
|
routes = run_vtysh_command("show ip bgp")
|
|
|
|
if not routes:
|
|
return {"error": "Could not get BGP routes"}
|
|
|
|
# Подсчет маршрутов
|
|
route_count = 0
|
|
for line in routes.split('\n'):
|
|
if line.strip() and not line.startswith('BGP table') and not line.startswith('*>'):
|
|
if any(char.isdigit() for char in line):
|
|
route_count += 1
|
|
|
|
return {
|
|
"route_count": route_count,
|
|
"raw_output": routes
|
|
}
|
|
|
|
def get_frr_status() -> Dict[str, Any]:
|
|
"""Получение статуса FRR"""
|
|
version = run_vtysh_command("show version")
|
|
|
|
if not version:
|
|
return {"error": "Could not get FRR version"}
|
|
|
|
return {
|
|
"version": version.split('\n')[0] if version else "Unknown",
|
|
"raw_output": version
|
|
}
|
|
|
|
def get_system_status() -> Dict[str, Any]:
|
|
"""Получение системного статуса"""
|
|
try:
|
|
# Проверка процессов FRR
|
|
zebra_running = subprocess.run(['pgrep', 'zebra'], capture_output=True).returncode == 0
|
|
bgpd_running = subprocess.run(['pgrep', 'bgpd'], capture_output=True).returncode == 0
|
|
|
|
# Проверка использования памяти
|
|
memory_info = {}
|
|
try:
|
|
with open('/proc/meminfo', 'r') as f:
|
|
for line in f:
|
|
if 'MemTotal:' in line:
|
|
memory_info['total'] = line.split()[1]
|
|
elif 'MemAvailable:' in line:
|
|
memory_info['available'] = line.split()[1]
|
|
except:
|
|
pass
|
|
|
|
return {
|
|
"zebra_running": zebra_running,
|
|
"bgpd_running": bgpd_running,
|
|
"memory": memory_info
|
|
}
|
|
except Exception as e:
|
|
return {"error": f"Could not get system status: {e}"}
|
|
|
|
def save_status(status: Dict[str, Any]):
|
|
"""Сохранение статуса в файл"""
|
|
try:
|
|
with open(STATUS_FILE, 'w') as f:
|
|
json.dump(status, f, indent=2)
|
|
except Exception as e:
|
|
log_message(f"Error saving status: {e}")
|
|
|
|
def main():
|
|
"""Основная функция"""
|
|
log_message("Starting FRR monitor...")
|
|
|
|
# Создание директории для логов
|
|
try:
|
|
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
|
|
os.makedirs(os.path.dirname(STATUS_FILE), exist_ok=True)
|
|
except (PermissionError, OSError):
|
|
pass
|
|
|
|
while True:
|
|
try:
|
|
# Сбор статуса
|
|
status = {
|
|
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
|
|
"frr": get_frr_status(),
|
|
"bgp_summary": get_bgp_summary(),
|
|
"bgp_routes": get_bgp_routes(),
|
|
"system": get_system_status()
|
|
}
|
|
|
|
# Сохранение статуса
|
|
save_status(status)
|
|
|
|
# Логирование важной информации
|
|
bgp_summary = status["bgp_summary"]
|
|
if "neighbors" in bgp_summary:
|
|
for neighbor in bgp_summary["neighbors"]:
|
|
log_message(f"BGP neighbor {neighbor['ip']} (AS {neighbor['remote_as']}): {neighbor['state']}")
|
|
|
|
bgp_routes = status["bgp_routes"]
|
|
if "route_count" in bgp_routes:
|
|
log_message(f"BGP routes: {bgp_routes['route_count']}")
|
|
|
|
system = status["system"]
|
|
if "zebra_running" in system and "bgpd_running" in system:
|
|
if not system["zebra_running"] or not system["bgpd_running"]:
|
|
log_message("WARNING: FRR daemons not running properly")
|
|
|
|
# Ожидание перед следующей проверкой
|
|
time.sleep(60) # Проверка каждую минуту
|
|
|
|
except KeyboardInterrupt:
|
|
log_message("Monitor stopped by user")
|
|
break
|
|
except Exception as e:
|
|
log_message(f"Error in monitor loop: {e}")
|
|
time.sleep(30) # Короткая пауза при ошибке
|
|
|
|
if __name__ == "__main__":
|
|
main() |