From 1c472dbe24db0911dfe155c949436c839ad114fa Mon Sep 17 00:00:00 2001 From: dv Date: Wed, 8 Apr 2026 16:59:49 +0300 Subject: [PATCH] =?UTF-8?q?=D1=8F=20=D1=83=D1=81=D1=82=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/services/device_discovery.py | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/backend/app/services/device_discovery.py b/backend/app/services/device_discovery.py index a4fc6e7..236a2df 100644 --- a/backend/app/services/device_discovery.py +++ b/backend/app/services/device_discovery.py @@ -424,8 +424,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, str]]: - """Return list of (external_id, host_ip, rack_name) from the racks table.""" +) -> list[tuple[str, str, str, str | None]]: + """Return list of (external_id, host_ip, rack_name, rack_type) from the racks table.""" if via_tunnel and tunnel_host and tunnel_ssh_user and tunnel_ssh_password: async with asyncssh.connect( tunnel_host, @@ -446,14 +446,15 @@ 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, str]]: - """Return list of (external_id, host_ip, rack_name) from the racks table.""" +async def _fetch_rack_hosts(dsn: str, table: str) -> list[tuple[str, str, str, str | None]]: + """Return list of (external_id, host_ip, rack_name, rack_type) from the racks table.""" async with await psycopg.AsyncConnection.connect(dsn) as conn: cursor = await conn.execute( - f"SELECT id, data->>'host' AS host, name FROM \"{table}\" WHERE data->>'host' IS NOT NULL" + f"SELECT id, data->>'host' AS host, name, data->>'rack_type' AS rack_type " + f"FROM \"{table}\" WHERE data->>'host' IS NOT NULL" ) rows = await cursor.fetchall() - return [(str(r[0]), str(r[1]), str(r[2] or r[0])) for r in rows if r[1]] + return [(str(r[0]), str(r[1]), str(r[2] or r[0]), r[3] or None) for r in rows if r[1]] # ── Main entry point ────────────────────────────────────────────────────────── @@ -608,18 +609,21 @@ async def discover_via_ssh( # If a rack with that name doesn't exist yet in our racks table, create it now. from app.models.rack import Rack rack_id_mapping: dict[str, int] = {} - for ext_id, _, _ in rack_hosts: + for ext_id, _, _, rack_type_db in rack_hosts: existing_rack_row = (await db.execute( select(Rack).where(Rack.object_id == obj.id, Rack.name == ext_id) )).scalar_one_or_none() if existing_rack_row: rack_id_mapping[ext_id] = existing_rack_row.id + if rack_type_db and not existing_rack_row.rack_type: + existing_rack_row.rack_type = rack_type_db + logger.info(f"[ssh_discovery] Updated rack '{ext_id}' rack_type={rack_type_db}") else: - new_rack = Rack(object_id=obj.id, name=ext_id) + new_rack = Rack(object_id=obj.id, name=ext_id, rack_type=rack_type_db) db.add(new_rack) await db.flush() # get the new PK rack_id_mapping[ext_id] = new_rack.id - logger.info(f"[ssh_discovery] Created rack entry '{ext_id}' (id={new_rack.id})") + logger.info(f"[ssh_discovery] Created rack entry '{ext_id}' rack_type={rack_type_db} (id={new_rack.id})") # Step 1b: Add main CAPS server and DB server as devices # verified=True means we successfully connected to this host during this discovery run @@ -697,7 +701,7 @@ async def discover_via_ssh( if infra_devices: await db.flush() - for rack_idx, (external_id, rack_host, rack_name) in enumerate(rack_hosts): + for rack_idx, (external_id, rack_host, rack_name, _rack_type_db) in enumerate(rack_hosts): await _emit("disc_rack_start", { "rack_name": rack_name, "rack_host": rack_host, @@ -822,7 +826,7 @@ async def discover_via_ssh( discovered_device_ips.add(rack_host) # rack PC itself is a known device # Get all rack IPs to exclude them from device discovery - all_rack_ips = [host for _, host, _ in rack_hosts] + all_rack_ips = [host for _, host, _, _ in rack_hosts] await _emit("disc_action", {"message": f"Парсинг конфигурации {rack_name}..."}) devices_found = _parse_config(config_text, rack_host, all_rack_ips) logger.info(f"[ssh_discovery] Found {len(devices_found)} devices from plugins in {rack_host}") @@ -956,7 +960,7 @@ async def discover_via_ssh( # Step 2.5: Discover slave racks via ARP neighbor tables # Filter out already-known IPs: rack hosts, discovered devices, infra IPs, common gateways - all_rack_ips_set = {host for _, host, _ in rack_hosts} + all_rack_ips_set = {host for _, host, _, _ in rack_hosts} infra_ips = {ip for ip in [obj.server_ip, db_host] if ip} common_gateways = {ip for ip in neighbor_candidates if ip.endswith(".1") or ip.endswith(".254")} slave_candidates = ( @@ -980,7 +984,7 @@ async def discover_via_ssh( slave_identifier = "" slave_config_text = "" master_ip_for_slave = "" - for _, master_host, _ in rack_hosts: + for _, master_host, _, _ in rack_hosts: ok, identifier, slave_cfg = await _check_if_slave( host=candidate_ip, port=ssh_port, @@ -995,7 +999,7 @@ async def discover_via_ssh( master_ip_for_slave = master_host # Derive slave name from master's external_id: "lane-1-1" → "lane-1-1-slave" master_ext_id = next( - (ext_id for ext_id, host, _ in rack_hosts if host == master_host), + (ext_id for ext_id, host, _, _ in rack_hosts if host == master_host), master_host, ) slave_identifier = f"{master_ext_id}-slave"