API — Chaos control (admin)¶
This page documents all chaos administration endpoints used by the instructor. It covers seven controllers — a unified facade to drive and observe the 6 chaos families.
Controllers covered
| Controller | Prefix | Chaos family |
|---|---|---|
ChaosController |
/api/admin/chaos |
Performance (backend infrastructure) |
BusinessChaosController |
/api/admin/chaos/business and /api/chaos/public/business |
Business (A1–A16) |
FunctionalChaosController |
/api/admin/chaos/functional and /api/chaos/public/functional |
Functional (F1–F4) |
SecurityChaosController |
/api/admin/chaos/security and /api/chaos/public/security |
Security (S1–S12) |
ChaosScriptingController |
/api/admin/chaos/scripting |
Scripting |
ChaosScriptingPublicController |
/api/chaos/public/scripting |
Scripting (public read) |
FrontendChaosController |
/api/chaos/frontend |
Frontend (browser) |
The student page (ChaosStudentController — pedagogical journeys and self-service control) is in chaos-student.md and pedagogique.md.
Cross-cutting principles¶
Authentication¶
All admin endpoints (prefixes /api/admin/chaos/*) require admin authentication:
- Session cookie (
admin_logged_in = true) OR X-Admin-Token: <uuid>header
The check is centralized by AdminAuth.isAdmin(session, token) — see admin.md.
Public read endpoints¶
All /api/chaos/public/* endpoints are read-only and require no authentication. They are intended for student monitoring — allowing the monitoring interface to keep displaying chaos state even without admin login.
These endpoints are excluded from the ChaosInterceptor — they always respond, even when performance chaos is active at saturation. This is a critical property: without this exclusion, a student would lose observability at the very moment they need it most.
Chaos level model¶
The vast majority of chaos use the same 0 to 4 level model:
| Level | Name | Behavior |
|---|---|---|
| 0 | Disabled | Nominal behavior |
| 1 | Junior | First anomaly introduced |
| 2 | Intermediate | Cumulative anomalies |
| 3 | Expert | Advanced anomalies |
| 4 | Master | Maximum level (requires Pro license) |
Performance chaos (infrastructure) instead uses intensities 0-100 per component (CPU, memory, DB pool, etc.) — see below.
Standard response format¶
Errors follow the PerfShop global format ({"error": "..."}) — see conventions.md.
Performance chaos — /api/admin/chaos¶
Performance chaos (backend infrastructure) is driven by intensity parameter and not by level, because each component is tuned independently. The ChaosController aggregates 8 distinct parameters.
Overview¶
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/admin/chaos/status |
Full state (backend + frontend) |
GET |
/api/admin/chaos/public/status |
Same, no auth (monitoring) |
POST |
/api/admin/chaos/reset |
Resets all chaos to 0 |
POST |
/api/admin/chaos/cpu |
CPU saturation |
POST |
/api/admin/chaos/memory |
Controlled memory leak |
POST |
/api/admin/chaos/gc-pressure |
GC pressure (sawtooth pattern) |
POST |
/api/admin/chaos/db-pool |
DB connection pool saturation |
POST |
/api/admin/chaos/thread-pool |
Tomcat thread pool saturation |
POST |
/api/admin/chaos/slow-queries |
SQL query slowdown |
POST |
/api/admin/chaos/deadlock |
DB deadlock probability |
POST |
/api/admin/chaos/network |
Network timeout simulation |
Shared DTO — ChaosConfigRequest¶
All endpoints in this block share the same request DTO:
| Field | Type | Required | Constraint | Usage |
|---|---|---|---|---|
intensity |
Integer | yes | 0–105 | Main intensity (0 = off, 100 = max, 105 = intentional OOM for memory) |
guardrail |
Integer | no | 0–100 | Memory safety cap (% of max heap) — default 80 |
ratio |
Integer | no | 1–5 | CPU multiplier — number of concurrent threads |
POST /api/admin/chaos/cpu¶
Generates CPU load via CpuChaosScheduler. Intensity represents a percentage of CPU time consumed, and ratio multiplies the number of load threads to saturate multiple cores.
Request¶
Response — 200 OK¶
{
"success": true,
"message": "CPU intensity set to 80 ratio=2x",
"status": {
"cpu": 80,
"cpuRatio": 2,
"memoryLeakTarget": 0,
"memoryGuardrail": 80,
"gcPressure": 0,
"dbPool": 0,
"threadPool": 0,
"slowQueries": 0,
"deadlock": 0,
"network": 0
}
}
The message is built from chaos.infra.cpu.set with the intensity and ratio values.
POST /api/admin/chaos/memory¶
Triggers a progressive memory leak via MemoryLeakSimulator. The intensity field is the target (in % of max heap), and guardrail is the safety cap beyond which the simulator refuses to allocate.
Request¶
Special case — intensity: 105 triggers an intentional OOM (the simulator allocates beyond the max heap until OutOfMemoryError). This is reserved for recovery demonstrations and post-mortem heap dump analysis.
Effective formula¶
Example: intensity=90, guardrail=80 → heap target = 72% of max heap. This double constraint lets the instructor set the pedagogical target (intensity) and the safety target (guardrail) independently.
If intensity == 0, the simulator calls clearLeakedMemory() which progressively releases allocated memory.
Response — 200 OK¶
{
"success": true,
"message": "Memory leak target 90%, guardrail=80%",
"status": { "memoryLeakTarget": 90, "memoryGuardrail": 80, "...": "..." }
}
If intensity == 105, the message becomes Memory leak target OOM, guardrail=80%.
POST /api/admin/chaos/gc-pressure¶
Activates the GcPressureSimulator which allocates short-lived objects to force the GC to work. The resulting pattern in Grafana is characteristic: sawtooth with a period of ~4 seconds (4-slot circular buffer × 1s retention).
Request¶
Response — 200 OK¶
{
"success": true,
"message": "GC pressure intensity set to 70",
"status": { "gcPressure": 70, "...": "..." }
}
Recent catalog addition
The gc-pressure endpoint was added after the documentation overhaul prompts were written. It complements the traditional memory chaos: memory generates a linear leak (rising curve), gc-pressure generates a stable oscillation (sawtooth). Both can be combined to simulate a service under GC pressure and under memory leak.
If intensity == 0, the simulator calls clearBuffer() which empties the circular buffer.
POST /api/admin/chaos/db-pool¶
Saturates the HikariCP connection pool via DbPoolChaosScheduler. Intensity represents the % of connections permanently held by "dormant" ones that monopolize the pool without releasing.
Request¶
Response — 200 OK¶
{
"success": true,
"message": "DB pool saturation intensity set to 60",
"status": { "dbPool": 60, "...": "..." }
}
POST /api/admin/chaos/thread-pool¶
Saturates the Tomcat thread pool. Incoming requests must wait for a thread to free up.
Request¶
Response — 200 OK¶
{
"success": true,
"message": "Thread pool saturation intensity set to 80",
"status": { "threadPool": 80, "...": "..." }
}
POST /api/admin/chaos/slow-queries¶
Slows down certain SQL queries by inserting SLEEP()s or forcing the planner into full scans. Intensity is the probability that a query is slowed down and the duration of the slowdown.
Request¶
Response — 200 OK¶
{
"success": true,
"message": "Slow query intensity set to 50",
"status": { "slowQueries": 50, "...": "..." }
}
POST /api/admin/chaos/deadlock¶
Injects a deadlock probability into concurrent transactions (typically on orders and order_items). Raises SQLIntegrityConstraintViolationException on the client side.
Request¶
Response — 200 OK¶
{
"success": true,
"message": "Deadlock intensity set to 30",
"status": { "deadlock": 30, "...": "..." }
}
Deadlocks directly affect OrderController.getUserOrders() via applyDeadlockChaosPublic() — see orders.md.
POST /api/admin/chaos/network¶
Simulates network timeouts on outgoing calls (database, simulated external services). Intensity controls the probability and duration of slowdowns.
Request¶
Response — 200 OK¶
{
"success": true,
"message": "Network timeout intensity set to 40",
"status": { "network": 40, "...": "..." }
}
GET /api/admin/chaos/status¶
Returns the consolidated backend + frontend state.
Auth: admin
Response — 200 OK¶
{
"backend": {
"cpu": 80,
"cpuRatio": 2,
"memoryLeakTarget": 0,
"memoryGuardrail": 80,
"gcPressure": 0,
"dbPool": 0,
"threadPool": 0,
"slowQueries": 0,
"deadlock": 0,
"network": 0
},
"frontend": {
"cpuBurn": 0,
"memoryLeak": 0,
"domFlood": 0,
"fetchFlood": 0,
"doubleFetch": 0
}
}
GET /api/admin/chaos/public/status¶
Public endpoint (no authentication) returning the consolidated backend + frontend + business + functional state. Used by student monitoring.
Path under /admin but public
The endpoint is exposed under the prefix /api/admin/chaos/public/status — under /admin/ for routing consistency, but without auth. This choice seems counter-intuitive but it keeps all chaos statuses under a single tree in ChaosController.
Response — 200 OK¶
{
"backend": { "...": "..." },
"frontend": { "...": "..." },
"business": { "level": 0, "anomalies": [], "activeCount": 0 },
"functional": { "level": 0, "anomalies": [], "activeCount": 0 }
}
POST /api/admin/chaos/reset¶
Resets all chaos to 0 in a single operation:
chaosService.resetAll()→ backend infrastructurememoryLeakSimulator.clearLeakedMemory()→ releases leaked memorygcPressureSimulator.clearBuffer()→ empties the GC bufferfrontendChaosController.resetState()→ resets frontend stateschaosScriptingService.resetAll()→ clears scripting tokensbusinessChaosService.reset()→ business level → 0securityChaosService.reset()→ security level → 0functionalChaosService.reset()→ functional level → 0
Response — 200 OK¶
{
"success": true,
"message": "All chaos intensities reset to 0",
"status": { /* full state at 0 */ }
}
DB reset not included
The reset does not modify the database. Modifications already applied by chaos (A15 history corruption, S12 superadmin promotion, A16 non-replenished stocks) remain persistent. A true "clean reset" additionally requires docker compose down -v to bring everything back to a fresh state.
Business chaos — /api/admin/chaos/business and /api/chaos/public/business¶
Business chaos is driven by a single parameter: the global level (0–4). Each level activates a cumulative set of A1–A16 anomalies. See the full list in chaos/business.md.
Overview¶
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/admin/chaos/business |
Admin | Set the level (0-4) |
GET |
/api/admin/chaos/business/status |
Admin | Status + counters |
POST |
/api/admin/chaos/business/reset |
Admin | Reset level and counters |
POST |
/api/admin/chaos/business/logs/clear |
Admin | Empty the activity log |
GET |
/api/chaos/public/business/status |
None | Public status (monitoring) |
GET |
/api/chaos/public/business/logs |
None | Public activity log |
GET |
/api/chaos/public/business/anomalies |
None | Pedagogical catalog for a level |
POST /api/admin/chaos/business¶
Request¶
Response — 200 OK¶
{
"success": true,
"status": {
"level": 3,
"levelName": "Level 3 — Expert",
"anomaliesActive": ["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11"],
"counters": {
"A1": 0, "A2": 0, "A3": 0, "A4": 0, "A5": 0,
"A6": 0, "A7": 0, "A8": 0, "A9": 0, "A10": 0, "A11": 0
}
}
}
Error codes¶
| Code | Cause |
|---|---|
| 400 | Level outside [0–4] (chaos.error.level_range) |
| 401 | Not authenticated |
GET /api/chaos/public/business/anomalies¶
Pedagogical catalog: returns the list of anomalies active for a given level, with their localized descriptions.
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
level (query) |
integer | 3 |
Level to retrieve the catalog for |
Response — 200 OK¶
{
"level": 3,
"levelName": "Level 3 — Expert",
"count": 11,
"anomalies": [
{ "id": "A1", "name": "Incorrect VAT", "detail": "VAT rate 19.6% applied instead of 20% — total amount slightly underestimated" },
{ "id": "A11", "name": "Session token not invalidated", "detail": "Token valid 30s after logout — replay attack possible" }
]
}
This endpoint is used by the student monitoring frontend to display the pedagogical sheet for each level.
Functional chaos — /api/admin/chaos/functional and /api/chaos/public/functional¶
Same model as Business chaos, with 4 F1–F4 anomalies instead of 16.
Overview¶
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/admin/chaos/functional |
Set level |
GET |
/api/admin/chaos/functional/status |
Status |
POST |
/api/admin/chaos/functional/reset |
Reset |
POST |
/api/admin/chaos/functional/logs/clear |
Empty log |
GET |
/api/chaos/public/functional/status |
Public status |
GET |
/api/chaos/public/functional/logs |
Public log |
GET |
/api/chaos/public/functional/anomalies?level=N |
Catalog |
Structure identical to Business chaos — see the examples above. The only difference is that level=4 includes F4 (silent corruption), the most vicious anomaly in the catalog. See chaos/functional.md.
Security chaos — /api/admin/chaos/security and /api/chaos/public/security¶
Same model, with 12 S1–S12 faults. Level 4 activates the S10/S11/S12 faults which make AdminPortalController visible and vulnerable — see admin-portal.md.
Overview¶
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/admin/chaos/security |
Set level |
GET |
/api/admin/chaos/security/status |
Status |
POST |
/api/admin/chaos/security/reset |
Reset |
POST |
/api/admin/chaos/security/logs/clear |
Empty log |
GET |
/api/chaos/public/security/status |
Public status |
GET |
/api/chaos/public/security/logs |
Public log |
GET |
/api/chaos/public/security/faults?level=N |
Catalog |
Level 4 = hidden portal active
Setting Security chaos to level 4 immediately activates AdminPortalController — the /api/admin/portal/* endpoints stop returning 404 and become exploitable. Dropping the level below 4 re-hides the portal.
Response of GET /public/security/faults?level=4¶
{
"level": 4,
"levelName": "Level 4 — Master",
"count": 12,
"faults": [
{ "id": "S1", "name": "SQL Injection", "detail": "Parameter q= injected in native SQL — /api/products/search" },
{ "id": "S12", "name": "IDOR Privilege Escalation", "detail": "PUT /api/admin/portal/accounts/{id}/promote — superAdmin check bypassable" }
]
}
Scripting chaos — /api/admin/chaos/scripting and /api/chaos/public/scripting¶
Scripting chaos controls the complexity of anti-replay headers required on the checkout journey. Level names follow a specific gradation, defined in the chaos.scripting.level.* i18n keys:
| Level | Name | Required headers |
|---|---|---|
| 0 | Disabled | None |
| 1 | Junior | X-Session-Token, X-Request-ID |
| 2 | Intermediate | + X-Action-Token renewed at each step |
| 3 | Expert | + X-CSRF-Token, X-Step-Token, X-Signature (HMAC) |
| 4 | Maestro | Same + HMAC key derived from sessionToken |
Overview¶
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/admin/chaos/scripting |
Admin | Set level (0-4) |
GET |
/api/admin/chaos/scripting/status |
Admin | Status + active bundles |
POST |
/api/admin/chaos/scripting/reset |
Admin | Clears all bundles |
GET |
/api/admin/chaos/scripting/logs |
Admin | Activity log |
DELETE |
/api/admin/chaos/scripting/logs |
Admin | Empty the log |
GET |
/api/chaos/public/scripting/status |
None | Public status |
GET |
/api/chaos/public/scripting/logs |
None | Public log |
Separate public controller
Unlike other families where the same controller handles both admin and public routes, Scripting chaos uses two separate controllers:
ChaosScriptingController→/api/admin/chaos/scripting(admin)ChaosScriptingPublicController→/api/chaos/public/scripting(public)
This split reflects a strict separation between the control interface and the monitoring interface.
POST /api/admin/chaos/scripting¶
Request¶
Response — 200 OK¶
{
"success": true,
"status": {
"level": 2,
"levelName": "Intermediate",
"activeBundles": 0,
"rotationCount": 0
}
}
Error codes¶
| Code | Cause |
|---|---|
| 400 | Level outside [0–4] (chaos.scripting.error.level_range) — message: level must be 0, 1, 2, 3 or 4 |
| 401 | Not authenticated |
POST /api/admin/chaos/scripting/reset¶
Clears all active bundles (session tokens of all users in a checkout journey) and resets the level to 0.
Response — 200 OK¶
Immediate effect on students
A reset while a student is mid-checkout immediately breaks their session — the next step will return a Scripting chaos error (invalid token). This is acceptable in training since students can restart the journey, but should be avoided in a live demonstration without warning.
Frontend chaos — /api/chaos/frontend¶
Frontend chaos is handled by a relay controller: the backend only stores a state that is then polled by the React frontend every 5 seconds and interpreted browser-side.
Overview¶
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/chaos/frontend/state |
None | Current state (polled by the frontend) |
POST |
/api/chaos/frontend/state |
Admin | State update |
GET /api/chaos/frontend/state¶
Returns the current state of the 4 frontend chaos. Endpoint continuously polled by the React frontend, without authentication.
Response — 200 OK¶
Each value is an intensity 0–100.
| Chaos | Description |
|---|---|
cpuBurn |
JavaScript loops that consume the browser CPU |
memoryLeak |
Progressive allocation of un-released JS objects |
domFlood |
Massive DOM element insertion |
fetchFlood |
Multiplication of fetch() calls to /api/products |
doubleFetch |
Systematic double-calling of requests (race conditions) |
POST /api/chaos/frontend/state¶
Updates the frontend intensities.
Auth: admin
Request¶
Only the keys transmitted are updated — the others keep their value. Values outside [0,100] are clamped:
Response — 200 OK¶
{
"success": true,
"state": {
"cpuBurn": 50,
"memoryLeak": 0,
"domFlood": 30,
"fetchFlood": 0,
"doubleFetch": 0
}
}
curl example — full control sequence¶
# 1. Admin login and token retrieval
TOKEN=$(curl -s -H "Content-Type: application/json" \
-d '{"email":"admin@perfshop.fr","password":"admin"}' \
http://localhost:9080/api/admin/login | jq -r '.adminToken')
# 2. Enable Performance chaos CPU at 80% with ratio 2
curl -H "X-Admin-Token: $TOKEN" -H "Content-Type: application/json" \
-d '{"intensity":80,"ratio":2}' \
http://localhost:9080/api/admin/chaos/cpu
# 3. Enable Business chaos level 3 (11 anomalies)
curl -H "X-Admin-Token: $TOKEN" -H "Content-Type: application/json" \
-d '{"level":3}' \
http://localhost:9080/api/admin/chaos/business
# 4. Enable Security chaos level 4 (activates hidden portal)
curl -H "X-Admin-Token: $TOKEN" -H "Content-Type: application/json" \
-d '{"level":4}' \
http://localhost:9080/api/admin/chaos/security
# 5. Enable Frontend chaos — CPU burn 50%
curl -H "X-Admin-Token: $TOKEN" -H "Content-Type: application/json" \
-d '{"cpuBurn":50,"domFlood":30}' \
http://localhost:9080/api/chaos/frontend/state
# 6. Check consolidated state
curl -H "X-Admin-Token: $TOKEN" http://localhost:9080/api/admin/chaos/status
# 7. Global reset when done
curl -H "X-Admin-Token: $TOKEN" -X POST \
http://localhost:9080/api/admin/chaos/reset
Cross-cutting points of attention¶
Recommended reset order
For a complete reset, prefer POST /api/admin/chaos/reset which calls all individual resets in the right order. Per-family resets (business/reset, security/reset, etc.) do not touch performance chaos or the frontend — a partial reset can leave artifacts.
Reset does not touch the database
No reset endpoint modifies the database. Stock corrections (A16), account promotions (S12), history corruptions (A15) are persistent. Only docker compose down -v restores the initial state.
Observability: monitoring uses the public endpoints
The 4 chaos controllers (Performance, Business, Functional, Security) + Scripting expose /api/chaos/public/* endpoints that the student monitoring polls periodically. These endpoints are designed to be monitored without authentication — they only expose the chaos state, never sensitive data.
Related links¶
chaos/performance.md— detail of the 8 Performance chaos parameterschaos/business.md— A1–A16 catalogchaos/functional.md— F1–F4 catalogchaos/security.md— S1–S12 catalogchaos/scripting.md— headers and bundleschaos/frontend.md— detail of the 5 browser chaoschaos-student.md— self-service student controladmin-portal.md— hidden portal activated by Security level 4