Add scan concurrency and login delay sliders
Serialised logins now sleep `login_delay` seconds between each SSH auth to prevent AD/LDAP lockout. Both max sessions (1-10) and login delay (0-15s) are configurable via UI sliders in the header and passed as JSON to all scan endpoints. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+9
-4
@@ -2,7 +2,9 @@
|
||||
import re
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from functools import partial
|
||||
from netmiko import ConnectHandler, NetmikoTimeoutException, NetmikoAuthenticationException
|
||||
from config import SSH_USERNAME, SSH_PASSWORD, SSH_PORT, SSH_TIMEOUT, DEVICE_TYPE
|
||||
from parser import (parse_lldp_neighbors, parse_mgmt_ip_from_interfaces,
|
||||
@@ -15,7 +17,7 @@ logger = logging.getLogger(__name__)
|
||||
_login_lock = threading.Semaphore(1)
|
||||
|
||||
|
||||
def connect_and_query(ip):
|
||||
def connect_and_query(ip, login_delay=3):
|
||||
device = {
|
||||
"device_type": DEVICE_TYPE,
|
||||
"host": ip,
|
||||
@@ -43,6 +45,8 @@ def connect_and_query(ip):
|
||||
with _login_lock:
|
||||
conn = ConnectHandler(**device)
|
||||
_pt.Transport._preferred_keys = _orig_preferred_keys
|
||||
if login_delay > 0:
|
||||
time.sleep(login_delay)
|
||||
|
||||
try:
|
||||
hostname = conn.find_prompt().replace('#', '').replace('>', '').strip()
|
||||
@@ -175,13 +179,14 @@ def _aruba_firmware(version_output):
|
||||
|
||||
# ── Scan orchestration ────────────────────────────────────────────────────────
|
||||
|
||||
def scan_all_switches(ip_list, progress_callback=None, max_workers=5):
|
||||
def scan_all_switches(ip_list, progress_callback=None, max_workers=5, login_delay=3):
|
||||
results = []
|
||||
total = len(ip_list)
|
||||
done = 0
|
||||
|
||||
_scan = partial(connect_and_query, login_delay=login_delay)
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
future_to_ip = {executor.submit(connect_and_query, ip): ip for ip in ip_list}
|
||||
future_to_ip = {executor.submit(_scan, ip): ip for ip in ip_list}
|
||||
|
||||
for future in as_completed(future_to_ip):
|
||||
ip = future_to_ip[future]
|
||||
@@ -189,7 +194,7 @@ def scan_all_switches(ip_list, progress_callback=None, max_workers=5):
|
||||
result = future.result()
|
||||
except Exception as e:
|
||||
result = {"success": False, "ip": ip, "error": str(e)}
|
||||
import time; time.sleep(2) # avoid RADIUS lockout
|
||||
time.sleep(2) # avoid RADIUS lockout between result processing
|
||||
|
||||
results.append(result)
|
||||
done += 1
|
||||
|
||||
Reference in New Issue
Block a user