Skip to content

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.

  • 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

Defined in app/models.py using Pydantic v2.

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)

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

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)

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
}
}
]
}

Returns API metadata and a list of all registered routes.

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.

Returns all Kubernetes node names discovered via up{job="node-exporter"}.

{ "nodes": ["worker-node-1", "worker-node-2", "worker-node-3"] }

Fetches real-time metrics for all discovered nodes.

{
"nodes": [
{
"name": "worker-node-1",
"latency": 10.0,
"packetLoss": 0.001,
"bandwidth": 1250000000,
"congestion": 48000000
}
]
}

Fetches real-time metrics for a single named node.

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" }
}

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.

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.

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.

up{job="node-exporter"}

Node names are resolved from the kubernetes_io_hostname, instance, or node metric labels (tried in that order).

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.

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_seconds is 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].

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.

The app/simulation/runner.py module invokes the pre-compiled NS-3 binary as a subprocess.

  1. The SimulationRequest is serialised to JSON via model_dump(exclude_none=True).
  2. The binary is called as <NS3_SCRIPT> --jsonInput=- and the JSON is written to stdin to avoid shell-quoting issues with complex payloads.
  3. The subprocess is given a 30-second timeout; expiry raises HTTPException(504).
  4. stdout is parsed as JSON and deserialised into a SimulationResponse.
  5. A non-zero exit code combined with "error" in stderr raises HTTPException(500).

FastAPI’s built-in Swagger UI is available at /docs when the service is running.