clawft_kernel/workload_ctl/
host_node_admin.rs1use std::sync::Arc;
12
13use async_trait::async_trait;
14use serde_json::{Value, json};
15
16use super::host_service::{WorkloadHostService, refuse};
17use super::msg::{CtlRequest, Refusal, RefusalCode};
18
19pub const EVENT_NODE_ADMIN_REQUEST: &str = "node_admin.request";
21pub const EVENT_NODE_ADMIN_RESULT: &str = "node_admin.result";
23
24#[async_trait]
28pub trait NodeAdmin: Send + Sync {
29 async fn call(&self, method: &str, requester: &str, body: &Value) -> Result<Value, String>;
32}
33
34impl WorkloadHostService {
35 pub fn set_node_admin(&self, hook: Arc<dyn NodeAdmin>) -> bool {
37 self.node_admin.set(hook).is_ok()
38 }
39
40 pub(super) async fn node_admin_op(&self, req: &CtlRequest) -> Result<Value, Refusal> {
41 let Some(hook) = self.node_admin.get() else {
42 return Err(refuse(
43 RefusalCode::UnknownMethod,
44 format!("{}: node administration is not enabled on this node", req.method),
45 ));
46 };
47 self.record(
48 EVENT_NODE_ADMIN_REQUEST,
49 json!({ "node": self.node_id(), "method": req.method, "requester": req.requester,
50 "decision_id": req.decision_id }),
51 );
52 let out = hook.call(&req.method, &req.requester, &req.body).await;
53 self.record(
54 EVENT_NODE_ADMIN_RESULT,
55 json!({ "node": self.node_id(), "method": req.method, "requester": req.requester,
56 "decision_id": req.decision_id, "ok": out.is_ok(),
57 "error": out.as_ref().err() }),
58 );
59 out.map_err(|e| refuse(RefusalCode::Runtime, e))
60 }
61}