feat: improve bgp incident visibility

This commit is contained in:
linkong
2026-03-30 17:17:33 +08:00
parent 945786cee5
commit ac63bba2a2
12 changed files with 860 additions and 49 deletions

View File

@@ -15,6 +15,7 @@ from app.core.satellite_tle import build_tle_lines_from_elements
from app.core.time import to_iso8601_utc
from app.db.session import get_db
from app.models.bgp_anomaly import BGPAnomaly
from app.models.bgp_incident import BGPIncident
from app.models.collected_data import CollectedData
from app.services.cable_graph import build_graph_from_data, CableGraph
from app.services.collectors.bgp_common import RIPE_RIS_COLLECTOR_COORDS
@@ -439,6 +440,58 @@ def convert_bgp_collectors_to_geojson() -> Dict[str, Any]:
return {"type": "FeatureCollection", "features": features}
def convert_bgp_incidents_to_geojson(records: List[BGPIncident]) -> Dict[str, Any]:
features = []
for record in records:
regions = record.affected_regions or []
if not regions:
continue
valid_regions = [
region
for region in regions
if isinstance(region, dict)
and isinstance(region.get("latitude"), (int, float))
and isinstance(region.get("longitude"), (int, float))
]
if not valid_regions:
continue
avg_lat = sum(float(region["latitude"]) for region in valid_regions) / len(valid_regions)
avg_lon = sum(float(region["longitude"]) for region in valid_regions) / len(valid_regions)
features.append(
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [avg_lon, avg_lat],
},
"properties": {
"id": record.id,
"incident_key": record.incident_key,
"incident_type": record.incident_type,
"title": record.title,
"summary": record.summary,
"severity": record.severity,
"status": record.status,
"confidence": record.confidence,
"affected_prefixes": record.affected_prefixes or [],
"affected_asns": record.affected_asns or [],
"affected_collectors": record.affected_collectors or [],
"affected_regions": valid_regions,
"related_cables": record.related_cables or [],
"related_ixps": record.related_ixps or [],
"created_at": to_iso8601_utc(record.created_at),
"started_at": to_iso8601_utc(record.started_at),
},
}
)
return {"type": "FeatureCollection", "features": features}
# ============== API Endpoints ==============
@@ -667,6 +720,25 @@ async def get_bgp_anomalies_geojson(
return {**geojson, "count": len(geojson.get("features", []))}
@router.get("/geo/bgp-incidents")
async def get_bgp_incidents_geojson(
severity: Optional[str] = Query(None),
status: Optional[str] = Query("active"),
limit: int = Query(100, ge=1, le=500),
db: AsyncSession = Depends(get_db),
):
stmt = select(BGPIncident).order_by(BGPIncident.created_at.desc()).limit(limit)
if severity:
stmt = stmt.where(BGPIncident.severity == severity)
if status:
stmt = stmt.where(BGPIncident.status == status)
result = await db.execute(stmt)
records = list(result.scalars().all())
geojson = convert_bgp_incidents_to_geojson(records)
return {**geojson, "count": len(geojson.get("features", []))}
@router.get("/geo/bgp-collectors")
async def get_bgp_collectors_geojson():
geojson = convert_bgp_collectors_to_geojson()