Files
iix/deploy_routes.py

163 lines
5.8 KiB
Python

import os
import requests
import json
import traceback
import paramiko
from scp import SCPClient
def get_routers_from_config(config_path, isp_name="dimensi"):
"""Mengambil list router dari config.json billing-mcp"""
try:
with open(config_path, 'r') as f:
config = json.load(f)
isp_data = config.get("isps", {}).get(isp_name)
if not isp_data:
print(f"ISP {isp_name} tidak ditemukan dalam config.")
return []
routers = isp_data.get("routers", {})
router_list = []
for name, data in routers.items():
if name.startswith(f"router-{isp_name}"):
router_list.append({
"name": name,
"host": data.get("host"),
"port": data.get("port"),
"user": data.get("user"),
"pass": data.get("pass")
})
return router_list
except Exception as e:
print(f"Error membaca config.json: {e}")
return []
def deploy_via_rest_api(router, rsc_filepath="routing-lokal.rsc"):
"""Mengirim rute IP satu per satu via REST API Session"""
host = router["host"]
user = router["user"]
password = router["pass"]
name = router["name"]
port = router["port"]
api_url = f"http://{host}/rest"
if port != 80:
api_url = f"http://{host}:{port}/rest"
print(f"\n--- Memproses {name} [{host}:{port}] via API ---")
if not os.path.exists(rsc_filepath):
print(f"Error: {rsc_filepath} tidak ditemukan!")
return
# Parsing list name dan IPs dari file rsc
ips = []
list_name = "ip-lokal" # Default
with open(rsc_filepath, 'r') as f:
for line in f:
line = line.strip()
if line.startswith("remove [find"):
import re
match = re.search(r'list="([^"]+)"', line)
if match:
list_name = match.group(1)
elif line.startswith("add list="):
import re
match = re.search(r'address="([^"]+)"', line)
if match:
ips.append(match.group(1))
if not ips:
print("Tidak ada IP yang ditemukan di dalam file RSC.")
return
print(f"Ditemukan {len(ips)} subnet untuk dimasukkan pada list '{list_name}'.")
session = requests.Session()
session.auth = (user, password)
session.verify = False
# 1. Menghapus list lama di router (loop sampai benar-benar bersih)
print(f"Menghapus address-list '{list_name}' lama di router...")
del_payload = {"script": f"/ip/firewall/address-list/remove [find list=\"{list_name}\"]"}
for attempt in range(100):
try:
session.post(f"{api_url}/execute", json=del_payload, timeout=60)
except Exception as e:
print(f" Warning execute remove: {e}")
import time
time.sleep(5)
# Verifikasi: cek apakah sudah benar-benar kosong
try:
res_check = session.get(f"{api_url}/ip/firewall/address-list",
params={"list": list_name, ".proplist": ".id"}, timeout=10)
remaining = len(res_check.json()) if res_check.status_code == 200 else -1
except:
remaining = -1
if remaining == 0:
print(f" Address-list '{list_name}' bersih (percobaan {attempt + 1})")
break
elif remaining > 0:
print(f" Sisa {remaining} entry, menghapus ulang... (round {attempt + 1})")
else:
print(f" Gagal verifikasi, lanjut...")
break
else:
print(f" Warning: address-list belum bersih setelah 100 percobaan")
import time
time.sleep(1)
# 2. Add IP lewat eksekusi Batch Script (Mencegah Payload Too Large)
print(f"Mengirim {len(ips)} address ke router secara batch... (±500 list per request)")
success_count = 0
fail_count = 0
start_time = time.time()
chunk_size = 500
for i in range(0, len(ips), chunk_size):
chunk_ips = ips[i:i + chunk_size]
# Buat kumpulan string baris perintah MikroTik dibungkus error handler
# agar jika ada 1 IP invalid, tidak menghentikan keseluruhan 500 IP lainnya (abort script)
commands = [f"do {{ /ip/firewall/address-list/add list={list_name} address={ip} }} on-error={{}}" for ip in chunk_ips]
script_code = "\n".join(commands)
payload = {
"script": script_code
}
try:
# Karena execution berjalan di background, kita bisa beri jeda aman antar batch
res = session.post(f"{api_url}/execute", json=payload, timeout=30)
if res.status_code in (200, 201):
success_count += len(chunk_ips)
else:
fail_count += len(chunk_ips)
print(f"Error pada batch {i}-{i+chunk_size}: {res.text}")
time.sleep(0.5) # Hindari CPU router Spike 100%
except Exception as e:
fail_count += len(chunk_ips)
print(f"Exception batch {i}-{i+chunk_size}: {e}")
print(f"Progress batch terkirim: {min(i+chunk_size, len(ips))}/{len(ips)}...")
elapsed = time.time() - start_time
print(f"Selesai! {name} terupdate dalam {elapsed:.1f} dtk.")
print(f"Berhasil: {success_count} IPs, Gagal: {fail_count} IPs.")
if __name__ == "__main__":
config_path = "/home/wartana/myApp/billing-mcp/config.json"
routers = get_routers_from_config(config_path, "dimensi")
if routers:
print(f"Ditemukan {len(routers)} router distribusi dimensi.")
for r in routers:
deploy_via_rest_api(r, "routing-lokal.rsc")
else:
print("Tidak ada router target di config.")