Переписан BGP сервер на FRR
This commit is contained in:
+177
-75
@@ -1,103 +1,205 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для перезагрузки префиксов без перезапуска BGP сервера
|
||||
Скрипт для перезагрузки префиксов в FRR
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import ipaddress
|
||||
from pathlib import Path
|
||||
from typing import Set
|
||||
|
||||
def run_command(cmd):
|
||||
"""Выполнение команды"""
|
||||
# Настройки
|
||||
DATA_DIR = "/app/data"
|
||||
LOG_FILE = "/app/logs/reload.log"
|
||||
PREFIX_FILES = ["prefixes.txt", "additional_prefixes.txt"]
|
||||
|
||||
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
|
||||
except Exception as e:
|
||||
return False, "", str(e)
|
||||
with open(LOG_FILE, "a") as f:
|
||||
f.write(log_entry + "\n")
|
||||
except (PermissionError, OSError):
|
||||
pass
|
||||
|
||||
def reload_prefixes():
|
||||
"""Перезагрузка префиксов"""
|
||||
print("Reloading prefixes...")
|
||||
|
||||
# Остановка процесса загрузки префиксов
|
||||
print("Stopping prefix loader process...")
|
||||
success, output, error = run_command("docker exec bgp-server pkill -f load_prefixes.py")
|
||||
|
||||
if not success:
|
||||
print("Warning: Could not stop prefix loader process")
|
||||
|
||||
# Ожидание завершения процесса
|
||||
time.sleep(2)
|
||||
|
||||
# Проверка что процесс остановлен
|
||||
success, output, error = run_command("docker exec bgp-server pgrep -f load_prefixes.py")
|
||||
if success:
|
||||
print("Error: Prefix loader process is still running")
|
||||
return False
|
||||
|
||||
print("Prefix loader process stopped successfully")
|
||||
|
||||
# Запуск нового процесса загрузки префиксов
|
||||
print("Starting new prefix loader process...")
|
||||
success, output, error = run_command("docker exec bgp-server /app/scripts/load_prefixes.py &")
|
||||
|
||||
if success:
|
||||
print("Prefix loader process started successfully")
|
||||
def validate_prefix(prefix: str) -> bool:
|
||||
"""Валидация IP префикса"""
|
||||
try:
|
||||
ipaddress.ip_network(prefix, strict=False)
|
||||
return True
|
||||
else:
|
||||
print(f"Error starting prefix loader: {error}")
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def check_status():
|
||||
"""Проверка статуса после перезагрузки"""
|
||||
print("Checking status...")
|
||||
time.sleep(5)
|
||||
def load_prefixes_from_file(file_path: Path) -> Set[str]:
|
||||
"""Загрузка префиксов из файла"""
|
||||
prefixes = set()
|
||||
|
||||
# Проверка процесса
|
||||
success, output, error = run_command("docker exec bgp-server pgrep -f load_prefixes.py")
|
||||
if success:
|
||||
print("✓ Prefix loader process is running")
|
||||
else:
|
||||
print("✗ Prefix loader process is not running")
|
||||
if not file_path.exists():
|
||||
log_message(f"File not found: {file_path}")
|
||||
return prefixes
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
for line_num, line in enumerate(f, 1):
|
||||
line = line.strip()
|
||||
|
||||
# Пропуск пустых строк и комментариев
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
# Валидация префикса
|
||||
if validate_prefix(line):
|
||||
prefixes.add(line)
|
||||
else:
|
||||
log_message(f"Invalid prefix in {file_path}:{line_num}: {line}")
|
||||
|
||||
except Exception as e:
|
||||
log_message(f"Error reading {file_path}: {e}")
|
||||
|
||||
return prefixes
|
||||
|
||||
def load_all_prefixes() -> Set[str]:
|
||||
"""Загрузка всех префиксов из всех файлов"""
|
||||
all_prefixes = set()
|
||||
|
||||
for filename in PREFIX_FILES:
|
||||
file_path = Path(DATA_DIR) / filename
|
||||
prefixes = load_prefixes_from_file(file_path)
|
||||
all_prefixes.update(prefixes)
|
||||
log_message(f"Loaded {len(prefixes)} prefixes from {filename}")
|
||||
|
||||
return all_prefixes
|
||||
|
||||
def get_current_routes() -> Set[str]:
|
||||
"""Получение текущих статических маршрутов из FRR"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['vtysh', '-c', 'show ip route static'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
log_message("Could not get current routes from FRR")
|
||||
return set()
|
||||
|
||||
routes = set()
|
||||
for line in result.stdout.split('\n'):
|
||||
line = line.strip()
|
||||
if line and 'via Null0' in line:
|
||||
# Парсинг строки маршрута
|
||||
parts = line.split()
|
||||
if len(parts) >= 2:
|
||||
route = parts[1]
|
||||
if validate_prefix(route):
|
||||
routes.add(route)
|
||||
|
||||
return routes
|
||||
except Exception as e:
|
||||
log_message(f"Error getting current routes: {e}")
|
||||
return set()
|
||||
|
||||
def run_vtysh_command(command: str) -> bool:
|
||||
"""Выполнение команды через vtysh"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['vtysh', '-c', command],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
log_message(f"vtysh command failed: {command}")
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
log_message(f"Error running vtysh command '{command}': {e}")
|
||||
return False
|
||||
|
||||
def announce_prefixes(prefixes: Set[str]):
|
||||
"""Анонсирование префиксов через FRR"""
|
||||
log_message(f"Announcing {len(prefixes)} prefixes...")
|
||||
|
||||
# Проверка логов
|
||||
success, output, error = run_command("docker exec bgp-server tail -n 5 /app/logs/prefixes.log")
|
||||
if success:
|
||||
print("Recent log entries:")
|
||||
print(output)
|
||||
else:
|
||||
print("No recent log entries found")
|
||||
for prefix in sorted(prefixes):
|
||||
command = f"ip route {prefix} Null0"
|
||||
if run_vtysh_command(command):
|
||||
log_message(f"Announced prefix: {prefix}")
|
||||
else:
|
||||
log_message(f"Failed to announce prefix: {prefix}")
|
||||
|
||||
def withdraw_prefixes(prefixes: Set[str]):
|
||||
"""Отзыв префиксов через FRR"""
|
||||
log_message(f"Withdrawing {len(prefixes)} prefixes...")
|
||||
|
||||
return True
|
||||
for prefix in sorted(prefixes):
|
||||
command = f"no ip route {prefix} Null0"
|
||||
if run_vtysh_command(command):
|
||||
log_message(f"Withdrew prefix: {prefix}")
|
||||
else:
|
||||
log_message(f"Failed to withdraw prefix: {prefix}")
|
||||
|
||||
def check_frr_status() -> bool:
|
||||
"""Проверка статуса FRR"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['vtysh', '-c', 'show version'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
return result.returncode == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Основная функция"""
|
||||
print("=== BGP Prefix Reloader ===")
|
||||
log_message("Starting prefix reload...")
|
||||
|
||||
# Проверка что контейнер запущен
|
||||
success, output, error = run_command("docker ps --filter name=bgp-server --format '{{.Status}}'")
|
||||
if not success or not output.strip():
|
||||
print("Error: BGP server container is not running")
|
||||
print("Please start the container first: docker-compose up -d")
|
||||
# Проверка статуса FRR
|
||||
if not check_frr_status():
|
||||
log_message("ERROR: FRR is not running")
|
||||
return 1
|
||||
|
||||
print("BGP server container is running")
|
||||
# Загрузка новых префиксов
|
||||
new_prefixes = load_all_prefixes()
|
||||
log_message(f"Loaded {len(new_prefixes)} prefixes from files")
|
||||
|
||||
# Перезагрузка префиксов
|
||||
if reload_prefixes():
|
||||
print("Prefix reload completed successfully")
|
||||
|
||||
# Проверка статуса
|
||||
if check_status():
|
||||
print("✓ All checks passed")
|
||||
return 0
|
||||
else:
|
||||
print("✗ Some checks failed")
|
||||
return 1
|
||||
# Получение текущих маршрутов
|
||||
current_routes = get_current_routes()
|
||||
log_message(f"Found {len(current_routes)} current routes in FRR")
|
||||
|
||||
# Определение изменений
|
||||
to_add = new_prefixes - current_routes
|
||||
to_remove = current_routes - new_prefixes
|
||||
|
||||
log_message(f"Changes: {len(to_add)} to add, {len(to_remove)} to remove")
|
||||
|
||||
# Применение изменений
|
||||
if to_remove:
|
||||
withdraw_prefixes(to_remove)
|
||||
|
||||
if to_add:
|
||||
announce_prefixes(to_add)
|
||||
|
||||
# Финальная проверка
|
||||
final_routes = get_current_routes()
|
||||
log_message(f"Final route count: {len(final_routes)}")
|
||||
|
||||
if len(final_routes) == len(new_prefixes):
|
||||
log_message("Reload completed successfully!")
|
||||
return 0
|
||||
else:
|
||||
print("✗ Prefix reload failed")
|
||||
log_message("WARNING: Route count mismatch after reload")
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user