Skip to main content

mockforge_intelligence/handlers/
failure_designer.rs

1//! Failure design HTTP handlers with a typed downstream Chaos provider.
2use axum::{extract::State, response::Json};
3use serde::{de::DeserializeOwned, Deserialize, Serialize};
4use serde_json::{json, Value};
5
6/// Operations supplied by the application's existing failure designer.
7pub trait FailureDesignerProvider: Clone + Send + Sync + 'static {
8    /// Concrete rule accepted by the existing engine.
9    type Rule: DeserializeOwned + Serialize + Send + Sync + 'static;
10    /// Concrete scenario returned by that engine.
11    type Scenario: Serialize;
12    /// Validate without generating a scenario.
13    fn validate_rule(&self, rule: &Self::Rule) -> Result<(), String>;
14    /// Generate the original typed scenario.
15    fn rule_to_scenario(&self, rule: &Self::Rule) -> Result<Self::Scenario, String>;
16    /// Generate the route configuration consumed by the runtime.
17    fn generate_route_chaos_config(&self, rule: &Self::Rule) -> Result<Value, String>;
18    /// Generate a hook for webhook rules, or retain the original null for other rules.
19    fn webhook_hook(&self, rule: &Self::Rule) -> Result<Option<Value>, String>;
20}
21
22/// Request to validate a failure design rule
23#[derive(Debug, Deserialize)]
24pub struct ValidateRuleRequest<R> {
25    /// Rule to validate
26    pub rule: R,
27}
28
29/// Request to generate chaos scenario from rule
30#[derive(Debug, Deserialize)]
31pub struct GenerateScenarioRequest<R> {
32    /// Rule to convert
33    pub rule: R,
34}
35
36/// Response for rule validation
37#[derive(Debug, Serialize)]
38pub struct ValidateRuleResponse {
39    /// Success flag
40    pub success: bool,
41    /// Validation errors (if any)
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub error: Option<String>,
44}
45
46/// Response for scenario generation
47#[derive(Debug, Serialize)]
48pub struct GenerateScenarioResponse<C> {
49    /// Success flag
50    pub success: bool,
51    /// Generated chaos scenario
52    pub scenario: C,
53    /// Route chaos configuration (JSON)
54    pub route_chaos_config: Value,
55    /// Webhook hook configuration (if applicable)
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub webhook_hook: Option<Value>,
58}
59
60/// Validate a failure design rule
61///
62/// POST /api/v1/chaos/failure-designer/validate
63pub async fn validate_rule<S: FailureDesignerProvider>(
64    State(state): State<S>,
65    Json(request): Json<ValidateRuleRequest<S::Rule>>,
66) -> Json<Value> {
67    let designer = &state;
68    match designer.validate_rule(&request.rule) {
69        Ok(()) => Json(json!({
70            "success": true,
71        })),
72        Err(e) => Json(json!({
73            "success": false,
74            "error": e,
75        })),
76    }
77}
78
79/// Generate chaos scenario from failure design rule
80///
81/// POST /api/v1/chaos/failure-designer/generate
82pub async fn generate_scenario<S: FailureDesignerProvider>(
83    State(state): State<S>,
84    Json(request): Json<GenerateScenarioRequest<S::Rule>>,
85) -> Result<Json<Value>, String> {
86    let designer = &state;
87
88    // Generate chaos scenario
89    let scenario = designer
90        .rule_to_scenario(&request.rule)
91        .map_err(|e| format!("Failed to generate scenario: {}", e))?;
92
93    // Generate route chaos config
94    let route_chaos_config = designer
95        .generate_route_chaos_config(&request.rule)
96        .map_err(|e| format!("Failed to generate route chaos config: {}", e))?;
97
98    // Generate webhook hook if applicable
99    let webhook_hook = designer
100        .webhook_hook(&request.rule)
101        .map_err(|e| format!("Failed to generate webhook hook: {}", e))?;
102
103    Ok(Json(json!({
104        "success": true,
105        "scenario": scenario,
106        "route_chaos_config": route_chaos_config,
107        "webhook_hook": webhook_hook,
108    })))
109}
110
111/// Preview generated configuration
112///
113/// POST /api/v1/chaos/failure-designer/preview
114pub async fn preview_config<S: FailureDesignerProvider>(
115    State(state): State<S>,
116    Json(request): Json<GenerateScenarioRequest<S::Rule>>,
117) -> Result<Json<Value>, String> {
118    let designer = &state;
119
120    // Validate rule first
121    designer
122        .validate_rule(&request.rule)
123        .map_err(|e| format!("Validation failed: {}", e))?;
124
125    // Generate all configurations
126    let scenario = designer
127        .rule_to_scenario(&request.rule)
128        .map_err(|e| format!("Failed to generate scenario: {}", e))?;
129
130    let route_chaos_config = designer
131        .generate_route_chaos_config(&request.rule)
132        .map_err(|e| format!("Failed to generate route chaos config: {}", e))?;
133
134    let webhook_hook = designer
135        .webhook_hook(&request.rule)
136        .map_err(|e| format!("Failed to generate webhook hook: {}", e))?;
137
138    Ok(Json(json!({
139        "success": true,
140        "rule": request.rule,
141        "scenario": scenario,
142        "route_chaos_config": route_chaos_config,
143        "webhook_hook": webhook_hook,
144    })))
145}