Files
iix/sync_routing.py

156 lines
6.2 KiB
Python

import os
import requests
import json
import ipaddress
from dotenv import load_dotenv
# Load configuration dari file .env
load_dotenv()
BGP_ROUTER_IP = os.getenv("BGP_ROUTER_IP")
BGP_ROUTER_USER = os.getenv("BGP_ROUTER_USER")
BGP_ROUTER_PASSWORD = os.getenv("BGP_ROUTER_PASSWORD")
# URL API RouterOS v7 untuk membaca tabel routing
API_URL = f"http://{BGP_ROUTER_IP}/rest/routing/route"
# Kredensial basic auth
auth = (BGP_ROUTER_USER, BGP_ROUTER_PASSWORD)
def get_local_bgp_routes():
"""Mengambil daftar IP lokal dari address-list 'bgp-export' di router BGP.
Prosedurnya:
1. Triggers script 'bgp_lokal_export' via SSH background command.
2. API polling ke /log MikroTik mencari string 'BGP Export: selesai'.
3. Setelah tercapai secara proporsional (~15K IPs), list diekstrak.
"""
import urllib3
import time
import subprocess
from datetime import datetime
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
print(f"Menghubungi router {BGP_ROUTER_IP} via SSH untuk trigger script...")
# 1. Jalankan script di Mikrotik via SSH background command
try:
ssh_cmd = [
"sshpass", "-p", BGP_ROUTER_PASSWORD,
"ssh", "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=10",
f"{BGP_ROUTER_USER}@{BGP_ROUTER_IP}",
"/system/script run bgp_lokal_export"
]
# Run process asynchronous di background (-n/& setara dengan Popen)
# Jangan terminate proses Python sebelum SSH selesai, agar RouterOS tidak kill script-nya!
subprocess.Popen(ssh_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print(" -> Script 'bgp_lokal_export' berhasil di-trigger via SSH.")
except Exception as e:
print(f" -> Gagal trigger script via SSH: {e}")
print(" -> Melanjutkan dengan data bgp-export yang ada (jika ada).")
session = requests.Session()
session.auth = auth
session.verify = False
api_url = f"http://{BGP_ROUTER_IP}/rest"
# 2. Polling Log MikroTik setiap 5 detik hingga ketemu indikasi BGP selesai
print("Memonitor log MikroTik untuk indikasi selesai...")
found_completion = False
start_time = time.time()
max_wait_time = 600 # 10 menit maksimal wait
import re
while time.time() - start_time < max_wait_time:
try:
log_res = session.get(f"{api_url}/log", timeout=10)
if log_res.status_code == 200:
logs = log_res.json()
# Batasi pengecekan pada 50 baris terakhir log
recent_logs = logs[-50:] if len(logs) > 50 else logs
for lg in recent_logs:
msg = lg.get("message", "")
if re.search(r"BGP Export.*selesai total", msg):
print(f" -> Indikator selesai terdeteksi di log: '{msg}'")
found_completion = True
break
if found_completion:
break
except Exception as e:
pass
time.sleep(5)
if not found_completion:
print(" -> Waktu tunggu habis tapi tidak menemukan indikator log 'selesai total'.")
print(" -> Melanjutkan mencoba membaca bgp-export...")
print("Mengambil address-list 'bgp-export' dari router...")
try:
res = session.get(f"{api_url}/ip/firewall/address-list",
params={"list": "bgp-export", ".proplist": "address"},
timeout=60)
if res.status_code == 200:
data = res.json()
routes = [r.get("address") for r in data if r.get("address")]
# Hapus default routes
routes = [r for r in routes if r not in ("0.0.0.0/0", "::/0")]
print(f" -> Berhasil: {len(routes)} rute lokal")
return list(set(routes))
else:
print(f" -> Error: {res.status_code} - {res.text[:100]}")
return []
except Exception as e:
print(f" -> Gagal: {e}")
return []
def generate_address_list_script(route_list, list_name, filename):
"""Membentuk file .rsc yang berisi perintah create address-list MikroTik"""
if not route_list:
print(f"List kosong, tidak ada rute LOKAL yang ditemukan.")
return
print(f"Membuat file {filename} dengan {len(route_list)} subnet IP...")
with open(filename, "w") as f:
f.write(f"# Dibuat otomatis via Script API Python\n")
f.write(f"/ip firewall address-list\n")
# Bersihkan list lama sebelum memasukkan yang baru
f.write(f"remove [find list=\"{list_name}\"]\n")
for ip in route_list:
f.write(f"add list={list_name} address=\"{ip}\"\n")
print(f"File {filename} berhasil dibuat.")
if __name__ == "__main__":
if not all([BGP_ROUTER_IP, BGP_ROUTER_USER, BGP_ROUTER_PASSWORD]):
print("Error: Variabel kredensial/BGP_ROUTER_IP belum diset dengan benar di file .env")
exit(1)
print("--- Memulai Proses Ekstraksi Ringan Routing LOKAL ---")
local_ips = get_local_bgp_routes()
if local_ips:
print(f"\nRingkasan:")
print(f"Total Subnet IP Lokal & CDN: {len(local_ips)}")
# SAFETY CROSS-CHECK: Pastikan jumlah rute masuk akal
# Karena rata-rata BGP lokal ada ~15.000+, kita set batas minimal aman 13.000
if len(local_ips) < 13000:
print(f"\n[ERROR] Validasi GAGAL! Rute yang diekstrak hanya {len(local_ips)}.")
print("Terdapat kemungkinan proses export di Router BGP belum selesai atau terputus.")
print("Membatalkan seluruh deployment untuk mencegah router distribusi kehilangan address list.")
exit(1)
print(f"Membuat file routing-lokal.rsc dengan {len(local_ips)} subnet IP...")
# Generate script address-list khusus untuk trafik Lokal
generate_address_list_script(local_ips, "ip-lokal", "routing-lokal.rsc")
print("\nSelesai! File routing-lokal.rsc siap di-upload ke router distribusi.")
print("Di Router Distribusi jalankan perintah: /import file-name=routing-lokal.rsc")
else:
print("\nGagal mengambil rute BGP lokal. File routing-lokal.rsc tidak dibuat.")
exit(1)