diff --git a/backend/app/services/device_discovery.py b/backend/app/services/device_discovery.py index 6307bd5..7887e84 100644 --- a/backend/app/services/device_discovery.py +++ b/backend/app/services/device_discovery.py @@ -110,10 +110,12 @@ def _parse_config(config_text: str, rack_host: str) -> list[DiscoveredDevice]: plugin_name = section[len("plugin:"):] if any(plugin_name.startswith(prefix) for prefix in _SKIP_PLUGIN_PREFIXES): + logger.debug(f"[ssh_discovery] Plugin {plugin_name} - IGNORED (prefix in skip list: {_SKIP_PLUGIN_PREFIXES})") continue cls = parser.get(section, "cls", fallback="") if not cls: + logger.debug(f"[ssh_discovery] Plugin {plugin_name} - IGNORED (no 'cls' field)") continue # Collect all URI-like values in this section @@ -123,9 +125,18 @@ def _parse_config(config_text: str, rack_host: str) -> list[DiscoveredDevice]: if not raw: continue ip = _extract_ip(raw) - if not ip or ip == rack_host or ip in seen_ips: + if not ip: + logger.debug(f"[ssh_discovery] Plugin {plugin_name} field {field_name}='{raw}' - IGNORED (not a valid network IP)") continue + if ip == rack_host: + logger.debug(f"[ssh_discovery] IP {ip} from plugin {plugin_name} - IGNORED (matches rack_host)") + continue + if ip in seen_ips: + logger.debug(f"[ssh_discovery] IP {ip} from plugin {plugin_name} - IGNORED (duplicate, already seen)") + continue + seen_ips.add(ip) + logger.debug(f"[ssh_discovery] IP {ip} from plugin {plugin_name} - EXTRACTED (cls={cls}, category={_cls_to_category(cls)}, role={_cls_to_role(cls, plugin_name)})") discovered.append(DiscoveredDevice( ip=ip, category=_cls_to_category(cls), @@ -489,22 +500,22 @@ async def discover_via_ssh( if existing is not None: changes = [] if existing.category != found.category and existing.source == "auto_ssh": - existing.category = found.category changes.append(f"category: {existing.category}→{found.category}") + existing.category = found.category if existing.role == "other" and found.role != "other": - existing.role = found.role changes.append(f"role: other→{found.role}") + existing.role = found.role # Update hostname if it was never set or still auto-generated if not existing.hostname or existing.hostname.startswith("rack"): if existing.hostname != hostname: + changes.append(f"hostname: '{existing.hostname}'→'{hostname}'") existing.hostname = hostname - changes.append(f"hostname: {existing.hostname}→{hostname}") if changes: - logger.info(f"[ssh_discovery] Device {found.ip} ({hostname}) - UPDATED ({', '.join(changes)})") + logger.info(f"[ssh_discovery] {found.ip} ({found.plugin_name}) - UPDATED: {', '.join(changes)}") result.updated += 1 else: - logger.debug(f"[ssh_discovery] Device {found.ip} ({hostname}) - SKIPPED (no changes, category={existing.category}, role={existing.role}, hostname={existing.hostname})") + logger.info(f"[ssh_discovery] {found.ip} ({found.plugin_name}) - SKIPPED: already exists with same values (source={existing.source}, category={existing.category}, role={existing.role}, hostname={existing.hostname})") result.skipped += 1 else: db.add(Device( @@ -516,10 +527,10 @@ async def discover_via_ssh( source="auto_ssh", device_meta={"plugin": found.plugin_name, "cls": found.cls}, )) - logger.info(f"[ssh_discovery] Device {found.ip} ({hostname}) - ADDED (category={found.category}, role={found.role})") + logger.info(f"[ssh_discovery] {found.ip} ({found.plugin_name}) - ADDED: category={found.category}, role={found.role}, hostname={hostname}, source=auto_ssh") result.created += 1 except Exception as exc: - logger.error(f"[ssh_discovery] Error upserting {found.ip}: {exc}") + logger.error(f"[ssh_discovery] {found.ip} ({found.plugin_name}) - ERROR: {exc}") result.errors.append(f"Error upserting {found.ip}: {exc}") # Flush after each rack so that subsequent SELECTs (for other racks @@ -532,7 +543,7 @@ async def discover_via_ssh( result.errors.append(f"Flush error after rack {rack_host}: {exc}") # Step 3: Discover MikroTik via SSH_CLIENT - logger.info(f"[ssh_discovery] Attempting to discover MikroTik via SSH_CLIENT on {obj.server_ip or 'main_server'}") + logger.info(f"[ssh_discovery] Step 3: Attempting to discover MikroTik via SSH_CLIENT on {obj.server_ip or 'main_server'}") mikrotik_ip = await _discover_mikrotik_via_ssh_client( host=obj.server_ip or rack_hosts[0][1], port=obj.ssh_port or 22, @@ -540,7 +551,7 @@ async def discover_via_ssh( password=ssh_password, ) if mikrotik_ip: - logger.info(f"[ssh_discovery] Discovered MikroTik at {mikrotik_ip}") + logger.info(f"[ssh_discovery] MikroTik found via SSH_CLIENT at {mikrotik_ip}") try: existing = (await db.execute( select(Device).where( @@ -550,7 +561,7 @@ async def discover_via_ssh( )).scalar_one_or_none() if existing is not None: - logger.debug(f"[ssh_discovery] Device {mikrotik_ip} (mikrotik) - SKIPPED (already exists, category={existing.category}, hostname={existing.hostname})") + logger.info(f"[ssh_discovery] {mikrotik_ip} (mikrotik) - SKIPPED: already exists (source={existing.source}, category={existing.category}, hostname={existing.hostname})") result.skipped += 1 else: db.add(Device( @@ -561,18 +572,18 @@ async def discover_via_ssh( role="other", source="auto_ssh", )) - logger.info(f"[ssh_discovery] Device {mikrotik_ip} (mikrotik) - ADDED (category=router, role=other)") + logger.info(f"[ssh_discovery] {mikrotik_ip} (mikrotik) - ADDED: category=router, role=other, hostname=mikrotik, source=auto_ssh") result.created += 1 except Exception as exc: - logger.error(f"[ssh_discovery] Error upserting {mikrotik_ip}: {exc}") + logger.error(f"[ssh_discovery] {mikrotik_ip} (mikrotik) - ERROR: {exc}") result.errors.append(f"Error upserting {mikrotik_ip}: {exc}") await db.flush() else: - logger.debug(f"[ssh_discovery] No MikroTik found via SSH_CLIENT") + logger.info(f"[ssh_discovery] MikroTik: No IP found via SSH_CLIENT (reason: SSH_CLIENT env var not available or parsing failed)") # Step 4: Discover Proxmox via port 8006 scan - logger.info(f"[ssh_discovery] Attempting to discover Proxmox servers via port 8006 scan on {obj.server_ip or 'main_server'}") + logger.info(f"[ssh_discovery] Step 4: Attempting to discover Proxmox servers via port 8006 scan on {obj.server_ip or 'main_server'}") proxmox_ips = await _discover_proxmox_via_port_scan( host=obj.server_ip or rack_hosts[0][1], port=obj.ssh_port or 22, @@ -580,7 +591,7 @@ async def discover_via_ssh( password=ssh_password, ) if proxmox_ips: - logger.info(f"[ssh_discovery] Discovered {len(proxmox_ips)} Proxmox server(s): {proxmox_ips}") + logger.info(f"[ssh_discovery] Proxmox discovery found {len(proxmox_ips)} server(s) on port 8006: {proxmox_ips}") for idx, proxmox_ip in enumerate(proxmox_ips, 1): hostname = f"proxmox_{idx}" try: @@ -592,7 +603,7 @@ async def discover_via_ssh( )).scalar_one_or_none() if existing is not None: - logger.debug(f"[ssh_discovery] Device {proxmox_ip} ({hostname}) - SKIPPED (already exists, category={existing.category}, hostname={existing.hostname})") + logger.info(f"[ssh_discovery] {proxmox_ip} ({hostname}) - SKIPPED: already exists (source={existing.source}, category={existing.category}, hostname={existing.hostname})") result.skipped += 1 else: db.add(Device( @@ -603,14 +614,14 @@ async def discover_via_ssh( role="other", source="auto_ssh", )) - logger.info(f"[ssh_discovery] Device {proxmox_ip} ({hostname}) - ADDED (category=vm, role=other)") + logger.info(f"[ssh_discovery] {proxmox_ip} ({hostname}) - ADDED: category=vm, role=other, hostname={hostname}, source=auto_ssh") result.created += 1 except Exception as exc: - logger.error(f"[ssh_discovery] Error upserting {proxmox_ip}: {exc}") + logger.error(f"[ssh_discovery] {proxmox_ip} ({hostname}) - ERROR: {exc}") result.errors.append(f"Error upserting {proxmox_ip}: {exc}") await db.flush() else: - logger.debug(f"[ssh_discovery] No Proxmox servers found via port 8006 scan") + logger.info(f"[ssh_discovery] Proxmox: No servers found via port 8006 scan (reason: no hosts responding on port 8006)") return result