mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 00:50:46 +08:00
fix(managed-ne): prevent ume-sync route conflicts and prefer host_name
Ensure fixed managed-ne paths are matched before /{ne_id} so deleting UME-synced NEs no longer triggers managed_ne_not_found, and use UME host_name as the synced display name to align managed NE naming with inventory host identity.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3a35b54f0e
commit
c5973eec69
3 changed files with 64 additions and 18 deletions
|
|
@ -83,21 +83,6 @@ def api_create_managed_ne(body: ManagedNeCreate, db: Session = Depends(get_db)):
|
|||
return create_managed_ne(db, body).model_dump()
|
||||
|
||||
|
||||
@router.get("/{ne_id}")
|
||||
def api_get_managed_ne(ne_id: str, db: Session = Depends(get_db)):
|
||||
return get_managed_ne(db, ne_id).model_dump()
|
||||
|
||||
|
||||
@router.patch("/{ne_id}")
|
||||
def api_update_managed_ne(ne_id: str, body: ManagedNeUpdate, db: Session = Depends(get_db)):
|
||||
return update_managed_ne(db, ne_id, body).model_dump()
|
||||
|
||||
|
||||
@router.delete("/{ne_id}")
|
||||
def api_delete_managed_ne(ne_id: str, db: Session = Depends(get_db)):
|
||||
return delete_managed_ne(db, ne_id)
|
||||
|
||||
|
||||
@router.get("/import/template")
|
||||
def api_managed_ne_import_template(format: str = Query(default="xlsx")):
|
||||
filename, payload, media_type = build_managed_ne_import_template(format)
|
||||
|
|
@ -165,3 +150,18 @@ def api_connect_test(body: ConnectTestRequest, db: Session = Depends(get_db)):
|
|||
raise HTTPException(status_code=404, detail=f"managed_ne_not_found: {','.join(missing[:5])}")
|
||||
submitted = schedule_connect_tests(ids)
|
||||
return {"ok": True, "submitted": submitted}
|
||||
|
||||
|
||||
@router.get("/{ne_id}")
|
||||
def api_get_managed_ne(ne_id: str, db: Session = Depends(get_db)):
|
||||
return get_managed_ne(db, ne_id).model_dump()
|
||||
|
||||
|
||||
@router.patch("/{ne_id}")
|
||||
def api_update_managed_ne(ne_id: str, body: ManagedNeUpdate, db: Session = Depends(get_db)):
|
||||
return update_managed_ne(db, ne_id, body).model_dump()
|
||||
|
||||
|
||||
@router.delete("/{ne_id}")
|
||||
def api_delete_managed_ne(ne_id: str, db: Session = Depends(get_db)):
|
||||
return delete_managed_ne(db, ne_id)
|
||||
|
|
|
|||
|
|
@ -564,7 +564,7 @@ def sync_ume_inventory_to_managed_ne(db: Session) -> UmeManagedSyncResult:
|
|||
if existing is None:
|
||||
existing = db.query(ManagedNE).filter(ManagedNE.ip_address == ip).first()
|
||||
device_type, vendor = _infer_managed_ne_type_vendor(str(inv.ne_type or ""), str(inv.vendor or ""))
|
||||
display_name = str(inv.ne_name or "").strip() or ip
|
||||
display_name = str(inv.host_name or "").strip() or str(inv.ne_name or "").strip() or ip
|
||||
existing_tags = str(existing.tags or "").strip() if existing is not None else ""
|
||||
if existing is None:
|
||||
existing = ManagedNE(
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ from sqlalchemy.pool import StaticPool
|
|||
from netx_api.config import settings
|
||||
from netx_api.db import Base, get_db
|
||||
from netx_api.main import app
|
||||
from netx_api.models import ManagedNE # noqa: F401 — register table on Base
|
||||
from netx_api.models import ManagedNE, UmeInventoryNE # noqa: F401 — register table on Base
|
||||
from netx_api.ne_connect import hostname_probe_command, parse_hostname_from_output
|
||||
from netx_api.ne_crypto import decrypt_secret, encrypt_secret
|
||||
from netx_api.ne_service import create_managed_ne, import_managed_ne
|
||||
from netx_api.ne_service import UME_SYNC_SOURCE, create_managed_ne, import_managed_ne
|
||||
from netx_api.ne_schemas import ManagedNeCreate
|
||||
|
||||
|
||||
|
|
@ -68,6 +68,7 @@ class ManagedNeApiTests(unittest.TestCase):
|
|||
poolclass=StaticPool,
|
||||
)
|
||||
ManagedNE.__table__.create(bind=self.engine, checkfirst=True)
|
||||
UmeInventoryNE.__table__.create(bind=self.engine, checkfirst=True)
|
||||
self.Session = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)
|
||||
|
||||
def override_get_db():
|
||||
|
|
@ -184,6 +185,51 @@ class ManagedNeApiTests(unittest.TestCase):
|
|||
)
|
||||
self.assertEqual(r.status_code, 503, r.text)
|
||||
|
||||
def test_delete_ume_sync_route_not_captured_by_ne_id(self):
|
||||
"""DELETE /ume-sync must not match DELETE /{ne_id} with ne_id='ume-sync'."""
|
||||
db = self.Session()
|
||||
db.add(
|
||||
ManagedNE(
|
||||
ip_address="10.0.0.99",
|
||||
source=UME_SYNC_SOURCE,
|
||||
source_ref="ume-ne-1",
|
||||
tags="UME",
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
r = self.client.delete("/v1/managed-ne/ume-sync")
|
||||
self.assertEqual(r.status_code, 200, r.text)
|
||||
self.assertEqual(r.json()["deleted"], 1)
|
||||
|
||||
r2 = self.client.delete("/v1/managed-ne/ume-sync")
|
||||
self.assertEqual(r2.status_code, 200, r2.text)
|
||||
self.assertEqual(r2.json()["deleted"], 0)
|
||||
|
||||
def test_ume_sync_prefers_host_name_for_display_name(self):
|
||||
db = self.Session()
|
||||
db.add(
|
||||
UmeInventoryNE(
|
||||
ne_id="ume-ne-100",
|
||||
ip_address="10.0.0.100",
|
||||
ne_name="Resource-Name-100",
|
||||
host_name="Host-Name-100",
|
||||
vendor="ZTE",
|
||||
ne_type="ZXR10",
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
synced = self.client.post("/v1/managed-ne/ume-sync")
|
||||
self.assertEqual(synced.status_code, 200, synced.text)
|
||||
|
||||
listed = self.client.get("/v1/managed-ne", params={"keyword": "10.0.0.100"})
|
||||
self.assertEqual(listed.status_code, 200, listed.text)
|
||||
self.assertEqual(listed.json()["total"], 1, listed.text)
|
||||
self.assertEqual(listed.json()["items"][0]["name"], "Host-Name-100")
|
||||
|
||||
@patch("netx_api.ne_connect._probe_device", return_value=("pass", "ok", None))
|
||||
def test_connect_test(self, _mock_probe):
|
||||
r = self.client.post(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue