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 print(f"Menghapus address-list '{list_name}' lama di router...") del_payload = {"script": f"/ip/firewall/address-list/remove [find list=\"{list_name}\"]"} try: res_del = session.post(f"{api_url}/execute", json=del_payload, timeout=30) if res_del.status_code not in (200, 201): print(f"Warning saat menghapus list (abaikan jika baru): {res_del.text}") except Exception as e: print(f"Warning execute remove list: {e}") # Beri waktu luang agar RouterOS mengeksekusi penghapusan di background import time time.sleep(2) # 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.")