#!/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()