feat: improve bgp incident visibility
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user