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
+19 -6
View File
@@ -34,10 +34,12 @@ def _reschedule(interval_minutes):
logger.info(f"Auto-scan scheduled every {interval_minutes} minutes")
def _trigger_scan_background(dept: str = None):
def _trigger_scan_background(dept: str = None, workers: int = 5, login_delay: int = 3):
"""Run scan in a background thread. dept=None → all switches."""
if not scanner.scan_state["running"]:
t = threading.Thread(target=scanner.run_scan, kwargs={"dept": dept}, daemon=True)
t = threading.Thread(target=scanner.run_scan,
kwargs={"dept": dept, "workers": workers, "login_delay": login_delay},
daemon=True)
t.start()
@@ -55,12 +57,20 @@ def index():
return render_template("index.html")
def _scan_params():
body = request.get_json(silent=True) or {}
workers = max(1, min(10, int(body.get("workers", 5))))
login_delay = max(0, min(30, int(body.get("login_delay", 3))))
return workers, login_delay
@app.route("/api/scan", methods=["POST"])
def api_scan():
"""Scan all active switches (no dept filter)."""
if scanner.scan_state["running"]:
return jsonify({"error": "Scan already running"}), 409
_trigger_scan_background(dept=None)
workers, login_delay = _scan_params()
_trigger_scan_background(dept=None, workers=workers, login_delay=login_delay)
return jsonify({"status": "started", "dept": None})
@@ -74,7 +84,8 @@ def api_scan_clear():
conn.execute("DELETE FROM links")
conn.commit()
conn.close()
_trigger_scan_background(dept=None)
workers, login_delay = _scan_params()
_trigger_scan_background(dept=None, workers=workers, login_delay=login_delay)
return jsonify({"status": "started", "cleared": True})
@@ -83,7 +94,8 @@ def api_scan_elec():
"""Scan only ELEC department switches."""
if scanner.scan_state["running"]:
return jsonify({"error": "Scan already running"}), 409
_trigger_scan_background(dept="ELEC")
workers, login_delay = _scan_params()
_trigger_scan_background(dept="ELEC", workers=workers, login_delay=login_delay)
return jsonify({"status": "started", "dept": "ELEC"})
@@ -92,7 +104,8 @@ def api_scan_gw():
"""Scan only GW department switches."""
if scanner.scan_state["running"]:
return jsonify({"error": "Scan already running"}), 409
_trigger_scan_background(dept="GW")
workers, login_delay = _scan_params()
_trigger_scan_background(dept="GW", workers=workers, login_delay=login_delay)
return jsonify({"status": "started", "dept": "GW"})