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:
2026-05-12 20:22:01 +00:00
parent d3a761baf5
commit c8de2620c8
4 changed files with 95 additions and 14 deletions
+9 -4
View File
@@ -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