diff --git a/backend/app/services/device_discovery.py b/backend/app/services/device_discovery.py index 443bf81..e784c91 100644 --- a/backend/app/services/device_discovery.py +++ b/backend/app/services/device_discovery.py @@ -224,8 +224,8 @@ async def _get_rack_hosts_direct( tunnel_ssh_port: int = 22, tunnel_ssh_user: str | None = None, tunnel_ssh_password: str | None = None, -) -> list[tuple[str, str]]: - """Return list of (external_id, host_ip) from the racks table.""" +) -> list[tuple[str, str, str]]: + """Return list of (external_id, host_ip, rack_name) from the racks table.""" if via_tunnel and tunnel_host and tunnel_ssh_user and tunnel_ssh_password: async with asyncssh.connect( tunnel_host, @@ -246,13 +246,14 @@ async def _get_rack_hosts_direct( return await _fetch_rack_hosts(dsn, table) -async def _fetch_rack_hosts(dsn: str, table: str) -> list[tuple[str, str]]: +async def _fetch_rack_hosts(dsn: str, table: str) -> list[tuple[str, str, str]]: + """Return list of (external_id, host_ip, rack_name) from the racks table.""" async with await psycopg.AsyncConnection.connect(dsn) as conn: cursor = await conn.execute( - f"SELECT id, data->>'host' AS host FROM \"{table}\" WHERE data->>'host' IS NOT NULL" + f"SELECT id, data->>'host' AS host, name FROM \"{table}\" WHERE data->>'host' IS NOT NULL" ) rows = await cursor.fetchall() - return [(str(r[0]), str(r[1])) for r in rows if r[1]] + return [(str(r[0]), str(r[1]), str(r[2] or r[0])) for r in rows if r[1]] # ── Main entry point ────────────────────────────────────────────────────────── @@ -372,7 +373,7 @@ async def discover_via_ssh( return result # Step 2: SSH into each rack, parse config, upsert devices - for external_id, rack_host in rack_hosts: + for external_id, rack_host, rack_name in rack_hosts: # Resolve config_path override from the embedded device's connection_params existing_rack_pc = (await db.execute( select(Device).where( @@ -402,6 +403,9 @@ async def discover_via_ssh( devices_found = _parse_config(config_text, rack_host) for found in devices_found: + # Hostname: "rack{rack_name}-{plugin_name}", e.g. "rack01-camera_grz" + hostname = f"rack{rack_name}-{found.plugin_name}" + try: existing = (await db.execute( select(Device).where( @@ -418,12 +422,18 @@ async def discover_via_ssh( if existing.role == "other" and found.role != "other": existing.role = found.role changed = True + # Update hostname if it was never set or still auto-generated + if not existing.hostname or existing.hostname.startswith("rack"): + if existing.hostname != hostname: + existing.hostname = hostname + changed = True result.updated += 1 if changed else 0 result.skipped += 0 if changed else 1 else: db.add(Device( object_id=obj.id, ip=found.ip, + hostname=hostname, category=found.category, role=found.role, source="auto_ssh",