Skip to content

Commit 3783763

Browse files
feat: configurable CIDR ranges, improved map drawer & noise filtering
- Add Settings UI for managing SDN pod CIDR ranges with backend API - Propagate network config from Settings through orchestrator/gRPC to ingestion service - Improve map drawer: correct Service node labels, simplify IP display - Add aggregated workload drawer with pod details table, cluster badges - Filter sdn-infrastructure noise entries in Integration Hub dependency summaries - Maintain full backward compatibility with hardcoded CIDR defaults Made-with: Cursor
1 parent 5f16a0a commit 3783763

9 files changed

Lines changed: 664 additions & 137 deletions

File tree

backend/routers/settings.py

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Enterprise feature for global configuration management
44
"""
55

6-
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
6+
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks, Response
77
from pydantic import BaseModel, Field
88
from typing import Optional, List, Dict, Any
99
import structlog
@@ -226,6 +226,159 @@ async def get_analysis_limits_defaults():
226226
return AnalysisLimits()
227227

228228

229+
# ============================================
230+
# Network Configuration (SDN Pod CIDR Ranges)
231+
# ============================================
232+
233+
class PodCIDRRange(BaseModel):
234+
"""A single SDN pod network CIDR range for gateway detection"""
235+
cidr: str = Field(..., pattern=r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}$')
236+
label: str = Field(..., min_length=1, max_length=100)
237+
enabled: bool = Field(True)
238+
is_default: bool = Field(False)
239+
240+
241+
class NetworkConfig(BaseModel):
242+
"""Network configuration for SDN gateway detection and CIDR classification"""
243+
sdn_pod_cidrs: List[PodCIDRRange] = Field(default_factory=lambda: [
244+
PodCIDRRange(cidr="10.128.0.0/14", label="OpenShift", enabled=True, is_default=True),
245+
PodCIDRRange(cidr="10.244.0.0/16", label="Flannel / kubeadm", enabled=True, is_default=True),
246+
PodCIDRRange(cidr="10.42.0.0/16", label="K3s / RKE2", enabled=True, is_default=True),
247+
PodCIDRRange(cidr="192.168.0.0/16", label="Kind / Minikube", enabled=False, is_default=True),
248+
])
249+
250+
251+
class NetworkConfigResponse(NetworkConfig):
252+
"""Response model including metadata"""
253+
updated_at: Optional[str] = None
254+
updated_by: Optional[int] = None
255+
256+
257+
@router.get("/network-config", response_model=NetworkConfigResponse)
258+
async def get_network_config(
259+
current_user: dict = Depends(get_current_user)
260+
):
261+
"""
262+
Get current network CIDR configuration.
263+
264+
Accessible to all authenticated users.
265+
Returns Pydantic defaults if not configured.
266+
"""
267+
try:
268+
query = """
269+
SELECT value, updated_at, updated_by
270+
FROM system_settings
271+
WHERE key = 'network_config'
272+
"""
273+
row = await database.fetch_one(query)
274+
275+
if row:
276+
value = row['value']
277+
if isinstance(value, str):
278+
value = json.loads(value)
279+
280+
return NetworkConfigResponse(
281+
**value,
282+
updated_at=str(row['updated_at']) if row['updated_at'] else None,
283+
updated_by=row['updated_by']
284+
)
285+
286+
logger.info("No network config configured, returning defaults")
287+
return NetworkConfigResponse()
288+
289+
except Exception as e:
290+
logger.error("Failed to get network config", error=str(e))
291+
return NetworkConfigResponse()
292+
293+
294+
@router.put("/network-config", response_model=NetworkConfigResponse)
295+
async def update_network_config(
296+
config: NetworkConfig,
297+
current_user: dict = Depends(get_current_user)
298+
):
299+
"""
300+
Update network CIDR configuration.
301+
302+
**Admin only** - Requires 'Super Admin' or 'Admin' role.
303+
304+
These settings control SDN gateway detection and IP classification
305+
across all new analysis sessions.
306+
"""
307+
check_admin_role(current_user)
308+
309+
try:
310+
query = """
311+
INSERT INTO system_settings (key, value, description, updated_at, updated_by)
312+
VALUES (
313+
'network_config',
314+
CAST(:value AS jsonb),
315+
'Network CIDR configuration for SDN gateway detection',
316+
NOW(),
317+
:user_id
318+
)
319+
ON CONFLICT (key) DO UPDATE SET
320+
value = CAST(:value AS jsonb),
321+
updated_at = NOW(),
322+
updated_by = :user_id
323+
RETURNING updated_at
324+
"""
325+
326+
result = await database.fetch_one(query, {
327+
"value": json.dumps(config.dict()),
328+
"user_id": current_user.get('user_id')
329+
})
330+
331+
logger.info(
332+
"Network config updated",
333+
user_id=current_user.get('user_id'),
334+
username=current_user.get('username'),
335+
cidr_count=len(config.sdn_pod_cidrs)
336+
)
337+
338+
return NetworkConfigResponse(
339+
**config.dict(),
340+
updated_at=str(result['updated_at']) if result else None,
341+
updated_by=current_user.get('user_id')
342+
)
343+
344+
except HTTPException:
345+
raise
346+
except Exception as e:
347+
logger.error("Failed to update network config", error=str(e))
348+
raise HTTPException(
349+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
350+
detail=f"Failed to update network config: {str(e)}"
351+
)
352+
353+
354+
@router.get("/network-config/defaults", response_model=NetworkConfig, responses={204: {"description": "Not configured"}})
355+
async def get_network_config_defaults():
356+
"""
357+
Get current network config (no authentication required).
358+
359+
Used by the analysis orchestrator to pass CIDR configuration
360+
to the ingestion service during collection startup.
361+
Returns 204 if not explicitly configured -- orchestrator should
362+
let PodDiscovery use its hardcoded defaults for backward compatibility.
363+
"""
364+
try:
365+
query = """
366+
SELECT value FROM system_settings
367+
WHERE key = 'network_config'
368+
"""
369+
row = await database.fetch_one(query)
370+
371+
if row:
372+
value = row['value']
373+
if isinstance(value, str):
374+
value = json.loads(value)
375+
return NetworkConfig(**value)
376+
except Exception as e:
377+
logger.warning("Failed to read network config from DB in /defaults", error=str(e))
378+
379+
return Response(status_code=204)
380+
381+
229382
# ============================================
230383
# SMTP Settings
231384
# ============================================

0 commit comments

Comments
 (0)