Skip to main content

mofa_foundation/secretary/monitoring/
plugins.rs

1//! Concrete event response plugin implementations
2//!
3//! This module contains specific plugin implementations for handling different
4//! types of operational events.
5
6use super::event::{Event, EventType};
7use super::plugin::{BaseEventResponsePlugin, EventResponseConfig, EventResponsePlugin};
8use async_trait::async_trait;
9use mofa_kernel::plugin::{PluginPriority, PluginResult};
10use std::collections::HashMap;
11use std::sync::RwLock;
12
13// ============================================================================
14// Server Fault Response Plugin
15// ============================================================================
16
17/// Plugin for handling server fault events
18///
19/// Workflow:
20/// 1. Attempt to automatically restart the server
21/// 2. Notify the administrator about the fault
22pub struct ServerFaultResponsePlugin {
23    base: BaseEventResponsePlugin,
24    config: RwLock<EventResponseConfig>,
25}
26
27impl ServerFaultResponsePlugin {
28    /// Create a new server fault response plugin
29    pub fn new() -> Self {
30        let handled_event_types = vec![EventType::ServerFault];
31        let workflow_steps = vec![
32            "attempt_auto_restart".to_string(),
33            "notify_administrator".to_string(),
34        ];
35
36        let base = BaseEventResponsePlugin::new(
37            "server-fault-responder",
38            "Server Fault Responder",
39            handled_event_types.clone(), // Clone it to avoid move error
40            workflow_steps,
41        )
42        .with_priority(PluginPriority::High) // Server faults should be handled quickly
43        .with_max_impact_scope("instance");
44
45        let config = RwLock::new(EventResponseConfig {
46            handled_event_types,
47            priority: PluginPriority::High,
48            ..Default::default()
49        });
50
51        Self { base, config }
52    }
53
54    /// Attempt to restart the server automatically
55    async fn attempt_auto_restart(&self, server: &str) -> Result<bool, String> {
56        // Simulate server restart logic
57        println!("Attempting to restart server: {}", server);
58        // In real implementation, this would call an API or execute a command
59
60        // Return success for now
61        Ok(true)
62    }
63
64    /// Notify the administrator about the server fault
65    async fn notify_administrator(&self, event: &Event) -> Result<(), String> {
66        // Simulate notification logic (email, SMS, Slack, etc.)
67        println!("Notifying administrator about server fault:");
68        println!("  Event ID: {}", event.id);
69        println!("  Source: {}", event.source);
70        println!("  Description: {}", event.description);
71
72        Ok(())
73    }
74}
75
76#[async_trait]
77impl EventResponsePlugin for ServerFaultResponsePlugin {
78    fn config(&self) -> &EventResponseConfig {
79        panic!("config() should not be called directly on this plugin");
80    }
81
82    async fn update_config(&mut self, config: EventResponseConfig) -> PluginResult<()> {
83        // Update the local config
84        {
85            let mut current_config = self.config.write().unwrap();
86            *current_config = config.clone();
87        }
88        // Update the base config
89        self.base.update_config(config).await
90    }
91
92    fn can_handle(&self, event: &Event) -> bool {
93        self.base.can_handle(event)
94    }
95
96    async fn handle_event(&mut self, event: Event) -> PluginResult<Event> {
97        self.base.handle_event(event).await
98    }
99
100    async fn execute_workflow(&self, event: &Event) -> PluginResult<HashMap<String, String>> {
101        let mut result = HashMap::new();
102
103        // Step 1: Attempt to automatically restart the server
104        let server_name = event
105            .data
106            .get("server")
107            .and_then(|s| s.as_str())
108            .unwrap_or("unknown");
109
110        let restart_result = self.attempt_auto_restart(server_name).await;
111
112        match restart_result {
113            Ok(success) => {
114                result.insert(
115                    "auto_restart".to_string(),
116                    if success {
117                        "success".to_string()
118                    } else {
119                        "failed".to_string()
120                    },
121                );
122            }
123            Err(err) => {
124                result.insert("auto_restart".to_string(), format!("error: {}", err));
125            }
126        }
127
128        // Step 2: Notify the administrator
129        match self.notify_administrator(event).await {
130            Ok(_) => {
131                result.insert("notify_admin".to_string(), "success".to_string());
132            }
133            Err(err) => {
134                result.insert("notify_admin".to_string(), format!("error: {}", err));
135            }
136        }
137
138        // Add workflow status
139        result.insert(
140            "workflow_status".to_string(),
141            "server_fault_workflow_completed".to_string(),
142        );
143
144        Ok(result)
145    }
146}
147
148#[async_trait]
149impl mofa_kernel::plugin::AgentPlugin for ServerFaultResponsePlugin {
150    fn metadata(&self) -> &mofa_kernel::plugin::PluginMetadata {
151        self.base.metadata()
152    }
153
154    fn state(&self) -> mofa_kernel::plugin::PluginState {
155        self.base.state()
156    }
157
158    async fn load(
159        &mut self,
160        ctx: &mofa_kernel::plugin::PluginContext,
161    ) -> mofa_kernel::plugin::PluginResult<()> {
162        self.base.load(ctx).await
163    }
164
165    async fn init_plugin(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
166        self.base.init_plugin().await
167    }
168
169    async fn start(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
170        self.base.start().await
171    }
172
173    async fn stop(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
174        self.base.stop().await
175    }
176
177    async fn unload(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
178        self.base.unload().await
179    }
180
181    async fn execute(&mut self, input: String) -> mofa_kernel::plugin::PluginResult<String> {
182        self.base.execute(input).await
183    }
184
185    fn as_any(&self) -> &dyn std::any::Any {
186        self
187    }
188
189    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
190        self
191    }
192
193    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
194        self
195    }
196}
197
198impl From<ServerFaultResponsePlugin> for Box<dyn EventResponsePlugin> {
199    fn from(plugin: ServerFaultResponsePlugin) -> Self {
200        Box::new(plugin)
201    }
202}
203
204impl From<ServerFaultResponsePlugin> for Box<dyn mofa_kernel::plugin::AgentPlugin> {
205    fn from(plugin: ServerFaultResponsePlugin) -> Self {
206        Box::new(plugin)
207    }
208}
209
210// ============================================================================
211// Network Attack Response Plugin
212// ============================================================================
213
214/// Plugin for handling network attack events
215///
216/// Workflow:
217/// 1. Block the attacking IP address
218/// 2. Analyze the attack pattern
219/// 3. Notify the security team
220pub struct NetworkAttackResponsePlugin {
221    base: BaseEventResponsePlugin,
222    config: RwLock<EventResponseConfig>,
223}
224
225impl NetworkAttackResponsePlugin {
226    /// Create a new network attack response plugin
227    pub fn new() -> Self {
228        let handled_event_types = vec![EventType::NetworkAttack];
229        let workflow_steps = vec![
230            "block_attacking_ip".to_string(),
231            "analyze_attack_pattern".to_string(),
232            "notify_security_team".to_string(),
233        ];
234
235        let base = BaseEventResponsePlugin::new(
236            "network-attack-responder",
237            "Network Attack Responder",
238            handled_event_types.clone(), // Clone it to avoid move error
239            workflow_steps,
240        )
241        .with_priority(PluginPriority::Critical) // Network attacks require immediate action
242        .with_max_impact_scope("system");
243
244        let config = RwLock::new(EventResponseConfig {
245            handled_event_types,
246            priority: PluginPriority::Critical,
247            ..Default::default()
248        });
249
250        Self { base, config }
251    }
252
253    /// Block the attacking IP address
254    async fn block_attacking_ip(&self, ip: &str) -> Result<bool, String> {
255        // Simulate IP blocking logic
256        println!("Blocking attacking IP: {}", ip);
257        // In real implementation, this would update firewall rules, etc.
258
259        Ok(true)
260    }
261
262    /// Analyze the attack pattern
263    async fn analyze_attack_pattern(&self, event: &Event) -> Result<String, String> {
264        // Simulate attack analysis
265        println!("Analyzing attack pattern for event: {}", event.id);
266
267        Ok("ddos_attack".to_string()) // Dummy analysis result
268    }
269
270    /// Notify the security team about the attack
271    async fn notify_security_team(&self, event: &Event, attack_type: &str) -> Result<(), String> {
272        // Simulate security notification
273        println!("Notifying security team about {} attack:", attack_type);
274        println!("  Event ID: {}", event.id);
275        println!("  Source IP: {:?}", event.data.get("source_ip"));
276
277        Ok(())
278    }
279}
280
281#[async_trait]
282impl EventResponsePlugin for NetworkAttackResponsePlugin {
283    fn config(&self) -> &EventResponseConfig {
284        panic!("config() should not be called directly on this plugin");
285    }
286
287    async fn update_config(&mut self, config: EventResponseConfig) -> PluginResult<()> {
288        // Update the local config
289        {
290            let mut current_config = self.config.write().unwrap();
291            *current_config = config.clone();
292        }
293        // Update the base config
294        self.base.update_config(config).await
295    }
296
297    fn can_handle(&self, event: &Event) -> bool {
298        self.base.can_handle(event)
299    }
300
301    async fn handle_event(&mut self, event: Event) -> PluginResult<Event> {
302        self.base.handle_event(event).await
303    }
304
305    async fn execute_workflow(&self, event: &Event) -> PluginResult<HashMap<String, String>> {
306        let mut result = HashMap::new();
307
308        // Step 1: Block attacking IP
309        let source_ip = event
310            .data
311            .get("source_ip")
312            .and_then(|ip| ip.as_str())
313            .unwrap_or("unknown");
314
315        let block_result = self.block_attacking_ip(source_ip).await;
316        match block_result {
317            Ok(success) => {
318                result.insert(
319                    "block_ip".to_string(),
320                    if success {
321                        "success".to_string()
322                    } else {
323                        "failed".to_string()
324                    },
325                );
326            }
327            Err(err) => {
328                result.insert("block_ip".to_string(), format!("error: {}", err));
329            }
330        }
331
332        // Step 2: Analyze attack pattern
333        let analysis_result = self.analyze_attack_pattern(event).await;
334        let attack_type = match analysis_result {
335            Ok(attack) => {
336                result.insert("attack_analysis".to_string(), attack.clone());
337                attack
338            }
339            Err(err) => {
340                result.insert("attack_analysis".to_string(), format!("error: {}", err));
341                "unknown".to_string()
342            }
343        };
344
345        // Step 3: Notify security team
346        if let Err(err) = self.notify_security_team(event, &attack_type).await {
347            result.insert("notify_security".to_string(), format!("error: {}", err));
348        } else {
349            result.insert("notify_security".to_string(), "success".to_string());
350        }
351
352        // Add workflow status
353        result.insert(
354            "workflow_status".to_string(),
355            "network_attack_workflow_completed".to_string(),
356        );
357
358        Ok(result)
359    }
360}
361
362#[async_trait]
363impl mofa_kernel::plugin::AgentPlugin for NetworkAttackResponsePlugin {
364    fn metadata(&self) -> &mofa_kernel::plugin::PluginMetadata {
365        self.base.metadata()
366    }
367
368    fn state(&self) -> mofa_kernel::plugin::PluginState {
369        self.base.state()
370    }
371
372    async fn load(
373        &mut self,
374        ctx: &mofa_kernel::plugin::PluginContext,
375    ) -> mofa_kernel::plugin::PluginResult<()> {
376        self.base.load(ctx).await
377    }
378
379    async fn init_plugin(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
380        self.base.init_plugin().await
381    }
382
383    async fn start(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
384        self.base.start().await
385    }
386
387    async fn stop(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
388        self.base.stop().await
389    }
390
391    async fn unload(&mut self) -> mofa_kernel::plugin::PluginResult<()> {
392        self.base.unload().await
393    }
394
395    async fn execute(&mut self, input: String) -> mofa_kernel::plugin::PluginResult<String> {
396        self.base.execute(input).await
397    }
398
399    fn as_any(&self) -> &dyn std::any::Any {
400        self
401    }
402
403    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
404        self
405    }
406
407    fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
408        self
409    }
410}
411
412impl From<NetworkAttackResponsePlugin> for Box<dyn EventResponsePlugin> {
413    fn from(plugin: NetworkAttackResponsePlugin) -> Self {
414        Box::new(plugin)
415    }
416}
417
418impl From<NetworkAttackResponsePlugin> for Box<dyn mofa_kernel::plugin::AgentPlugin> {
419    fn from(plugin: NetworkAttackResponsePlugin) -> Self {
420        Box::new(plugin)
421    }
422}