Переписан BGP сервер на FRR

This commit is contained in:
2025-07-11 18:06:07 +07:00
parent 3c5740784b
commit e197dae9f7
14 changed files with 1222 additions and 812 deletions
+174 -73
View File
@@ -1,93 +1,194 @@
#!/usr/bin/env python3
"""
Скрипт мониторинга BGP сервера
Скрипт мониторинга FRR BGP сервера
"""
import sys
import os
import time
import subprocess
import json
import time
import sys
from datetime import datetime
from pathlib import Path
from typing import Dict, Any
def run_command(cmd):
"""Выполнение команды и возврат результата"""
# Настройки
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:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.returncode == 0, result.stdout, result.stderr
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:
return False, "", str(e)
log_message(f"Error running vtysh command '{command}': {e}")
return ""
def check_container_status():
"""Проверка статуса Docker контейнера"""
success, output, error = run_command("docker ps --filter name=bgp-server --format '{{.Status}}'")
if success and output.strip():
return True, output.strip()
return False, "Container not running"
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 check_bgp_session():
"""Проверка BGP сессии"""
success, output, error = run_command("docker exec bgp-server exabgpcli show neighbor")
if success:
return True, output
return False, "Cannot check BGP session"
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 check_prefixes():
"""Проверка загруженных префиксов"""
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:
with open("/app/logs/prefixes.log", "r") as f:
lines = f.readlines()
return True, f"Found {len(lines)} log entries"
except FileNotFoundError:
return False, "Prefix log not found"
# Проверка процессов 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 check_network_connectivity():
"""Проверка сетевого подключения"""
success, output, error = run_command("docker exec bgp-server ping -c 1 192.168.1.1")
return success, "Network connectivity OK" if success else "Network connectivity failed"
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():
"""Основная функция мониторинга"""
print("=== BGP Server Monitoring ===")
print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
"""Основная функция"""
log_message("Starting FRR monitor...")
# Проверка контейнера
print("1. Container Status:")
status, details = check_container_status()
print(f" Status: {'✓ Running' if status else '✗ Stopped'}")
print(f" Details: {details}")
print()
# Создание директории для логов
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
# Проверка сети
print("2. Network Connectivity:")
net_ok, net_details = check_network_connectivity()
print(f" Status: {'✓ OK' if net_ok else '✗ Failed'}")
print(f" Details: {net_details}")
print()
# Проверка BGP сессии
print("3. BGP Session:")
bgp_ok, bgp_details = check_bgp_session()
print(f" Status: {'✓ Active' if bgp_ok else '✗ Inactive'}")
if bgp_ok:
print(f" Details: {bgp_details[:200]}...")
else:
print(f" Details: {bgp_details}")
print()
# Проверка префиксов
print("4. Prefixes:")
prefix_ok, prefix_details = check_prefixes()
print(f" Status: {'✓ Loaded' if prefix_ok else '✗ Not loaded'}")
print(f" Details: {prefix_details}")
print()
# Общий статус
overall_status = status and net_ok and bgp_ok and prefix_ok
print("=== Overall Status ===")
print(f"Status: {'✓ HEALTHY' if overall_status else '✗ UNHEALTHY'}")
return 0 if overall_status else 1
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__":
sys.exit(main())
main()