FastAPI
The KNS-3-Simulator exposes a FastAPI REST service that bridges Prometheus-scraped cluster metrics with an NS-3 network simulation backend. The API collects real-time node metrics from Prometheus, feeds them into the NS-3 simulator, and returns scored placement results for the KNS-3 scheduler to act on.
Application Structure
Section titled “Application Structure”Directoryapp/
- main.py FastAPI app factory and router registration
- config.py Environment-driven configuration
- models.py Pydantic request/response models
Directoryroutes/
- health.py Root info and health check endpoints
Directoryprometheus/
- client.py PromQL queries and metric fetching logic
- routes.py Prometheus-related API endpoints
Directorysimulation/
- routes.py Simulation trigger endpoints
- runner.py NS-3 subprocess invocation
Data Models
Section titled “Data Models”Defined in app/models.py using Pydantic v2.
NodeMetrics
Section titled “NodeMetrics”Input metrics for a single Kubernetes node:
| Field | Type | Default | Description |
|---|---|---|---|
name |
str |
required | Node name (e.g. worker-node-1) |
latency |
float |
required | Latency in milliseconds (≥ 0) |
packetLoss |
float |
0.001 |
Packet loss ratio (0.0 – 1.0) |
bandwidth |
float |
1000 |
Bandwidth in Mbps (> 0) |
congestion |
float |
50000000 |
Congestion in bytes/sec (≥ 0) |
WeightsConfig
Section titled “WeightsConfig”Optional scoring weights for the simulation. All values must be in [0, 1]:
| Field | Description |
|---|---|
latency |
Weight for latency metric |
throughput |
Weight for throughput metric |
packetLoss |
Weight for packet loss metric |
utilization |
Weight for utilization metric |
SimulationRequest
Section titled “SimulationRequest”Body for POST /simulate/custom:
| Field | Type | Default | Description |
|---|---|---|---|
nodes |
List[NodeMetrics] |
required | At least one node required |
simulationTime |
float |
10.0 |
Simulation duration in seconds (0–60) |
podPlacementNode |
str | None |
- | Restrict simulation to a specific node |
weights |
WeightsConfig | None |
None |
Custom scoring weights (uses NS-3 defaults if omitted) |
SimulationResponse
Section titled “SimulationResponse”Returned by both simulation endpoints:
{ "success": true, "performance": { "simulationDuration": 1.23, "nodesEvaluated": 3, "weights": { "latency": 0.4, "throughput": 0.25, "packetLoss": 0.2, "utilization": 0.15 } }, "results": [ { "nodeName": "worker-node-1", "metrics": { "avgLatency": 12.5, "minLatency": 8.1, "maxLatency": 21.3, "packetLossRate": 0.002, "throughput": 45.6, "avgUtilization": 0.31, "packetsSent": 1000, "packetsReceived": 998, "score": 82.4 } } ]}API Endpoints
Section titled “API Endpoints”System
Section titled “System”Returns API metadata and a list of all registered routes.
GET /health
Section titled “GET /health”Health check. Reports whether the NS-3 binary exists and whether Prometheus is reachable.
{ "status": "healthy", "ns3_home": "/code/kns-3-sim", "ns3_accessible": true, "prometheus_url": "http://host.docker.internal:9090", "prometheus_accessible": true}Status is "degraded" if either dependency is unavailable.
Prometheus
Section titled “Prometheus”GET /prometheus/nodes
Section titled “GET /prometheus/nodes”Returns all Kubernetes node names discovered via up{job="node-exporter"}.
{ "nodes": ["worker-node-1", "worker-node-2", "worker-node-3"] }GET /prometheus/metrics
Section titled “GET /prometheus/metrics”Fetches real-time metrics for all discovered nodes.
{ "nodes": [ { "name": "worker-node-1", "latency": 10.0, "packetLoss": 0.001, "bandwidth": 1250000000, "congestion": 48000000 } ]}GET /prometheus/metrics/{node_name}
Section titled “GET /prometheus/metrics/{node_name}”Fetches real-time metrics for a single named node.
GET /prometheus/debug
Section titled “GET /prometheus/debug”Debug endpoint. Returns the raw node-to-IP mapping and the list of IPs seen by the blackbox exporter, useful for verifying that node-exporter labels align with blackbox probe targets.
{ "node_exporter_nodes": ["worker-node-1"], "blackbox_probe_ips": ["192.168.1.10"], "node_ip_mapping": { "worker-node-1": "192.168.1.10" }}Simulation
Section titled “Simulation”GET /simulate?node_name=<optional>&simulation_time=<optional>
Section titled “GET /simulate?node_name=<optional>&simulation_time=<optional>”Pulls live metrics from Prometheus automatically and runs the NS-3 simulation. If node_name is omitted, all discovered nodes are evaluated.
| Query parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
node_name |
str |
- | optional | Restrict simulation to a specific node |
simulation_time |
float |
10.0 |
0–60 s | NS-3 simulated duration in seconds |
Rate limit: 10 requests per minute per IP.
POST /simulate/custom
Section titled “POST /simulate/custom”Accepts a SimulationRequest body with manually specified node metrics and parameters. Useful for testing without a live Prometheus instance.
Rate limit: 10 requests per minute per IP.
Prometheus Integration
Section titled “Prometheus Integration”The app/prometheus/client.py module handles all Prometheus communication via the HTTP API (/api/v1/query). Query results are cached with a 30-second TTL (up to 128 entries) to reduce Prometheus load during bursts.
Node Discovery
Section titled “Node Discovery”up{job="node-exporter"}Node names are resolved from the kubernetes_io_hostname, instance, or node metric labels (tried in that order).
Node-to-IP Mapping
Section titled “Node-to-IP Mapping”up{job="node-exporter"}The node_name and node_ip labels are used to build an IP lookup table. This table is required because the blackbox exporter probes nodes by IP while node-exporter labels use hostnames.
Metrics Collected per Node
Section titled “Metrics Collected per Node”| Metric | PromQL Query | Fallback |
|---|---|---|
| Latency | probe_icmp_duration_seconds{instance="<ip>", phase="rtt"} |
10.0 ms |
| Packet Loss | 1 - avg_over_time(probe_success{node_ip="<ip>"}[5m]) |
0.001 |
| Bandwidth | node_network_speed_bytes{node_ip="<ip>", device!~"lo|veth.*|docker0"} |
1.25 GB/s |
| Congestion | rate(node_network_transmit_bytes_total{node_ip=~".*<ip>.*", device!~"lo|veth.*|docker0"}[5m]) |
50 MB/s |
- Latency from
probe_icmp_duration_secondsis in seconds and converted to milliseconds. - Bandwidth takes the maximum across all matching interfaces.
- Congestion sums the transmit rate across all matching interfaces.
- Packet loss is clamped to [0.0, 1.0].
Error Handling
Section titled “Error Handling”All Prometheus queries raise HTTPException(503) on connection failure and HTTPException(500) on a non-success status in the API response. Individual metric functions return sensible defaults when no data is found, so a partial Prometheus outage degrades gracefully rather than failing the entire simulation request.
NS-3 Integration
Section titled “NS-3 Integration”The app/simulation/runner.py module invokes the pre-compiled NS-3 binary as a subprocess.
- The
SimulationRequestis serialised to JSON viamodel_dump(exclude_none=True). - The binary is called as
<NS3_SCRIPT> --jsonInput=-and the JSON is written to stdin to avoid shell-quoting issues with complex payloads. - The subprocess is given a 30-second timeout; expiry raises
HTTPException(504). - stdout is parsed as JSON and deserialised into a
SimulationResponse. - A non-zero exit code combined with
"error"in stderr raisesHTTPException(500).
Interactive API Documentation
Section titled “Interactive API Documentation”FastAPI’s built-in Swagger UI is available at /docs when the service is running.
