haiku вайб 2

This commit is contained in:
dv 2026-04-08 11:46:32 +03:00
parent cdee38d433
commit 47b0928b2a

View file

@ -11,6 +11,7 @@ Limitations (devices not discoverable automatically):
- Physical MikroTik router (not in rack configs) - Physical MikroTik router (not in rack configs)
""" """
import logging
import re import re
from configparser import RawConfigParser from configparser import RawConfigParser
from dataclasses import dataclass, field from dataclasses import dataclass, field
@ -26,6 +27,8 @@ from app.models.device import Device
from app.models.object import Object from app.models.object import Object
from app.services.crypto import decrypt from app.services.crypto import decrypt
logger = logging.getLogger(__name__)
# ── URI extraction ──────────────────────────────────────────────────────────── # ── URI extraction ────────────────────────────────────────────────────────────
_SERIAL_SCHEMES = {"serial", "com"} _SERIAL_SCHEMES = {"serial", "com"}
@ -183,7 +186,7 @@ async def _discover_mikrotik_via_ssh_client(
if parts: if parts:
return parts[0] return parts[0]
except Exception as e: except Exception as e:
print(f"[ssh_discovery] Failed to discover MikroTik via SSH_CLIENT: {e}") logger.warning(f"[ssh_discovery] Failed to discover MikroTik via SSH_CLIENT: {e}")
return None return None
@ -218,7 +221,7 @@ async def _discover_proxmox_via_port_scan(
ips = [line.strip() for line in result.stdout.strip().split('\n') if line.strip()] ips = [line.strip() for line in result.stdout.strip().split('\n') if line.strip()]
return ips return ips
except Exception as e: except Exception as e:
print(f"[ssh_discovery] Failed to discover Proxmox servers via port scan: {e}") logger.warning(f"[ssh_discovery] Failed to discover Proxmox servers via port scan: {e}")
return [] return []
@ -467,9 +470,9 @@ async def discover_via_ssh(
result.errors.append(f"SSH to {rack_host} failed: {exc}") result.errors.append(f"SSH to {rack_host} failed: {exc}")
continue continue
print(f"[ssh_discovery] Processing rack {rack_host} ({rack_name})") logger.info(f"[ssh_discovery] Processing rack {rack_host} ({rack_name})")
devices_found = _parse_config(config_text, rack_host) devices_found = _parse_config(config_text, rack_host)
print(f"[ssh_discovery] Found {len(devices_found)} devices from plugins in {rack_host}") logger.info(f"[ssh_discovery] Found {len(devices_found)} devices from plugins in {rack_host}")
for found in devices_found: for found in devices_found:
# Hostname: "rack{rack_name}-{plugin_name}", e.g. "rack01-camera_grz" # Hostname: "rack{rack_name}-{plugin_name}", e.g. "rack01-camera_grz"
@ -484,23 +487,25 @@ async def discover_via_ssh(
)).scalar_one_or_none() )).scalar_one_or_none()
if existing is not None: if existing is not None:
changed = False changes = []
if existing.category != found.category and existing.source == "auto_ssh": if existing.category != found.category and existing.source == "auto_ssh":
existing.category = found.category existing.category = found.category
changed = True changes.append(f"category: {existing.category}{found.category}")
if existing.role == "other" and found.role != "other": if existing.role == "other" and found.role != "other":
existing.role = found.role existing.role = found.role
changed = True changes.append(f"role: other→{found.role}")
# Update hostname if it was never set or still auto-generated # Update hostname if it was never set or still auto-generated
if not existing.hostname or existing.hostname.startswith("rack"): if not existing.hostname or existing.hostname.startswith("rack"):
if existing.hostname != hostname: if existing.hostname != hostname:
existing.hostname = hostname existing.hostname = hostname
changed = True changes.append(f"hostname: {existing.hostname}{hostname}")
action = "UPDATED" if changed else "SKIPPED" if changes:
print(f"[ssh_discovery] Device {found.ip} ({hostname}) - {action}") logger.info(f"[ssh_discovery] Device {found.ip} ({hostname}) - UPDATED ({', '.join(changes)})")
result.updated += 1 if changed else 0 result.updated += 1
result.skipped += 0 if changed else 1 else:
logger.debug(f"[ssh_discovery] Device {found.ip} ({hostname}) - SKIPPED (no changes, category={existing.category}, role={existing.role}, hostname={existing.hostname})")
result.skipped += 1
else: else:
db.add(Device( db.add(Device(
object_id=obj.id, object_id=obj.id,
@ -511,10 +516,10 @@ async def discover_via_ssh(
source="auto_ssh", source="auto_ssh",
device_meta={"plugin": found.plugin_name, "cls": found.cls}, device_meta={"plugin": found.plugin_name, "cls": found.cls},
)) ))
print(f"[ssh_discovery] Device {found.ip} ({hostname}) - ADDED") logger.info(f"[ssh_discovery] Device {found.ip} ({hostname}) - ADDED (category={found.category}, role={found.role})")
result.created += 1 result.created += 1
except Exception as exc: except Exception as exc:
print(f"[ssh_discovery] Error upserting {found.ip}: {exc}") logger.error(f"[ssh_discovery] Error upserting {found.ip}: {exc}")
result.errors.append(f"Error upserting {found.ip}: {exc}") result.errors.append(f"Error upserting {found.ip}: {exc}")
# Flush after each rack so that subsequent SELECTs (for other racks # Flush after each rack so that subsequent SELECTs (for other racks
@ -527,7 +532,7 @@ async def discover_via_ssh(
result.errors.append(f"Flush error after rack {rack_host}: {exc}") result.errors.append(f"Flush error after rack {rack_host}: {exc}")
# Step 3: Discover MikroTik via SSH_CLIENT # Step 3: Discover MikroTik via SSH_CLIENT
print(f"[ssh_discovery] Attempting to discover MikroTik via SSH_CLIENT on {obj.server_ip or 'main_server'}") logger.info(f"[ssh_discovery] Attempting to discover MikroTik via SSH_CLIENT on {obj.server_ip or 'main_server'}")
mikrotik_ip = await _discover_mikrotik_via_ssh_client( mikrotik_ip = await _discover_mikrotik_via_ssh_client(
host=obj.server_ip or rack_hosts[0][1], host=obj.server_ip or rack_hosts[0][1],
port=obj.ssh_port or 22, port=obj.ssh_port or 22,
@ -535,7 +540,7 @@ async def discover_via_ssh(
password=ssh_password, password=ssh_password,
) )
if mikrotik_ip: if mikrotik_ip:
print(f"[ssh_discovery] Discovered MikroTik at {mikrotik_ip}") logger.info(f"[ssh_discovery] Discovered MikroTik at {mikrotik_ip}")
try: try:
existing = (await db.execute( existing = (await db.execute(
select(Device).where( select(Device).where(
@ -545,7 +550,7 @@ async def discover_via_ssh(
)).scalar_one_or_none() )).scalar_one_or_none()
if existing is not None: if existing is not None:
print(f"[ssh_discovery] Device {mikrotik_ip} (mikrotik) - SKIPPED") logger.debug(f"[ssh_discovery] Device {mikrotik_ip} (mikrotik) - SKIPPED (already exists, category={existing.category}, hostname={existing.hostname})")
result.skipped += 1 result.skipped += 1
else: else:
db.add(Device( db.add(Device(
@ -556,18 +561,18 @@ async def discover_via_ssh(
role="other", role="other",
source="auto_ssh", source="auto_ssh",
)) ))
print(f"[ssh_discovery] Device {mikrotik_ip} (mikrotik) - ADDED") logger.info(f"[ssh_discovery] Device {mikrotik_ip} (mikrotik) - ADDED (category=router, role=other)")
result.created += 1 result.created += 1
except Exception as exc: except Exception as exc:
print(f"[ssh_discovery] Error upserting {mikrotik_ip}: {exc}") logger.error(f"[ssh_discovery] Error upserting {mikrotik_ip}: {exc}")
result.errors.append(f"Error upserting {mikrotik_ip}: {exc}") result.errors.append(f"Error upserting {mikrotik_ip}: {exc}")
await db.flush() await db.flush()
else: else:
print(f"[ssh_discovery] No MikroTik found via SSH_CLIENT") logger.debug(f"[ssh_discovery] No MikroTik found via SSH_CLIENT")
# Step 4: Discover Proxmox via port 8006 scan # Step 4: Discover Proxmox via port 8006 scan
print(f"[ssh_discovery] Attempting to discover Proxmox servers via port 8006 scan on {obj.server_ip or 'main_server'}") logger.info(f"[ssh_discovery] Attempting to discover Proxmox servers via port 8006 scan on {obj.server_ip or 'main_server'}")
proxmox_ips = await _discover_proxmox_via_port_scan( proxmox_ips = await _discover_proxmox_via_port_scan(
host=obj.server_ip or rack_hosts[0][1], host=obj.server_ip or rack_hosts[0][1],
port=obj.ssh_port or 22, port=obj.ssh_port or 22,
@ -575,7 +580,7 @@ async def discover_via_ssh(
password=ssh_password, password=ssh_password,
) )
if proxmox_ips: if proxmox_ips:
print(f"[ssh_discovery] Discovered {len(proxmox_ips)} Proxmox server(s): {proxmox_ips}") logger.info(f"[ssh_discovery] Discovered {len(proxmox_ips)} Proxmox server(s): {proxmox_ips}")
for idx, proxmox_ip in enumerate(proxmox_ips, 1): for idx, proxmox_ip in enumerate(proxmox_ips, 1):
hostname = f"proxmox_{idx}" hostname = f"proxmox_{idx}"
try: try:
@ -587,7 +592,7 @@ async def discover_via_ssh(
)).scalar_one_or_none() )).scalar_one_or_none()
if existing is not None: if existing is not None:
print(f"[ssh_discovery] Device {proxmox_ip} ({hostname}) - SKIPPED") logger.debug(f"[ssh_discovery] Device {proxmox_ip} ({hostname}) - SKIPPED (already exists, category={existing.category}, hostname={existing.hostname})")
result.skipped += 1 result.skipped += 1
else: else:
db.add(Device( db.add(Device(
@ -598,14 +603,14 @@ async def discover_via_ssh(
role="other", role="other",
source="auto_ssh", source="auto_ssh",
)) ))
print(f"[ssh_discovery] Device {proxmox_ip} ({hostname}) - ADDED") logger.info(f"[ssh_discovery] Device {proxmox_ip} ({hostname}) - ADDED (category=vm, role=other)")
result.created += 1 result.created += 1
except Exception as exc: except Exception as exc:
print(f"[ssh_discovery] Error upserting {proxmox_ip}: {exc}") logger.error(f"[ssh_discovery] Error upserting {proxmox_ip}: {exc}")
result.errors.append(f"Error upserting {proxmox_ip}: {exc}") result.errors.append(f"Error upserting {proxmox_ip}: {exc}")
await db.flush() await db.flush()
else: else:
print(f"[ssh_discovery] No Proxmox servers found via port 8006 scan") logger.debug(f"[ssh_discovery] No Proxmox servers found via port 8006 scan")
return result return result