rust_cni/libcni/
api.rs

1// Copyright (c) 2024 https://github.com/divinerapier/cni-rs
2use serde::{Deserialize, Serialize};
3
4use super::CNIError;
5
6use super::exec::RawExec;
7use crate::libcni::exec::{Exec, ExecArgs};
8use crate::libcni::result::result100;
9use crate::libcni::result::{APIResult, ResultCNI};
10use crate::libcni::types::NetworkConfig;
11use std::collections::HashMap;
12pub trait CNI {
13    fn add_network_list(
14        &self,
15        net: NetworkConfigList,
16        rt: RuntimeConf,
17    ) -> ResultCNI<Box<dyn APIResult>>;
18
19    fn check_network_list(&self, net: NetworkConfigList, rt: RuntimeConf) -> ResultCNI<()>;
20
21    fn delete_network_list(&self, net: NetworkConfigList, rt: RuntimeConf) -> ResultCNI<()>;
22
23    fn get_network_list_cached_result(
24        &self,
25        net: NetworkConfigList,
26        rt: RuntimeConf,
27    ) -> ResultCNI<Box<dyn APIResult>>;
28
29    fn add_network(
30        &self,
31        name: String,
32        cni_version: String,
33        net: NetworkConfig,
34        prev_result: Option<Box<dyn APIResult>>,
35        rt: RuntimeConf,
36    ) -> ResultCNI<Box<dyn APIResult>>;
37
38    fn check_network(
39        &self,
40        name: String,
41        cni_version: String,
42        prev_result: Option<Box<dyn APIResult>>,
43        net: NetworkConfig,
44        rt: RuntimeConf,
45    ) -> ResultCNI<()>;
46    fn delete_network(
47        &self,
48        name: String,
49        cni_version: String,
50
51        net: NetworkConfig,
52        rt: RuntimeConf,
53    ) -> ResultCNI<()>;
54
55    fn get_network_cached_result(
56        &self,
57        net: NetworkConfig,
58        rt: RuntimeConf,
59    ) -> ResultCNI<Box<dyn APIResult>>;
60
61    fn get_network_cached_config(
62        &self,
63        net: NetworkConfig,
64        rt: RuntimeConf,
65    ) -> ResultCNI<(Vec<u8>, RuntimeConf)>;
66
67    fn validate_network_list(&self, net: NetworkConfigList) -> ResultCNI<Vec<String>>;
68
69    fn validate_network(&self, net: NetworkConfig) -> ResultCNI<Vec<String>>;
70}
71
72#[derive(Default, Clone, Serialize, Deserialize)]
73pub struct NetworkConfigList {
74    pub name: String,
75    pub cni_version: String,
76    pub disable_check: bool,
77    pub plugins: Vec<NetworkConfig>,
78    pub bytes: Vec<u8>,
79}
80
81#[derive(Default, Clone)]
82pub struct RuntimeConf {
83    pub container_id: String,
84    pub net_ns: String,
85    pub if_name: String,
86    pub args: Vec<[String; 2]>,
87    pub capability_args: HashMap<String, String>,
88    pub cache_dir: String,
89}
90#[derive(Default)]
91pub struct CNIConfig {
92    pub path: Vec<String>,
93    pub exec: RawExec,
94    pub cache_dir: String,
95}
96
97impl CNIConfig {
98    // fn cache_add(
99    //     &self,
100    //     type_result: Box<dyn APIResult>,
101    //     config: Vec<u8>,
102    //     netname: String,
103    //     rt: &RuntimeConf,
104    // ) -> Result<(), String> {
105    //     Ok(())
106    // }
107
108    fn build_new_config(
109        &self,
110        name: String,
111        cni_version: String,
112        orig: &NetworkConfig,
113        prev_result: Option<Box<dyn APIResult>>,
114        _rt: &RuntimeConf,
115    ) -> Result<NetworkConfig, String> {
116        let mut json_object = json::parse(String::from_utf8_lossy(&orig.bytes).as_ref()).unwrap();
117
118        json_object.insert("name", name).unwrap();
119        json_object.insert("cniVersion", cni_version).unwrap();
120
121        if let Some(prev_result) = prev_result {
122            json_object
123                .insert("prevResult", prev_result.get_json())
124                .unwrap();
125        }
126        let new_bytes = json_object.dump().as_bytes().to_vec();
127        //need to update RutimeConfig
128        Ok(NetworkConfig {
129            network: serde_json::from_slice(&new_bytes).unwrap(),
130            bytes: new_bytes,
131        })
132    }
133}
134
135impl CNI for CNIConfig {
136    fn add_network_list(
137        &self,
138        net: NetworkConfigList,
139        rt: RuntimeConf,
140    ) -> ResultCNI<Box<dyn APIResult>> {
141        let mut r = None;
142
143        for x in net.plugins {
144            let r1 = self.add_network(
145                net.name.clone(),
146                net.cni_version.clone(),
147                x.clone(),
148                r,
149                rt.clone(),
150            )?;
151            r = Some(r1);
152            //add r to cached
153            // self.cacheAdd();
154        }
155        match r {
156            Some(r) => Ok(r),
157            None => Err(Box::new(CNIError::ExecuteError("()".to_string()))),
158        }
159    }
160
161    fn check_network_list(&self, net: NetworkConfigList, rt: RuntimeConf) -> ResultCNI<()> {
162        net.plugins.into_iter().try_for_each(|x| {
163            self.check_network(
164                net.name.clone(),
165                net.cni_version.clone(),
166                None,
167                x,
168                rt.clone(),
169            )
170        })?;
171        Ok(())
172    }
173
174    fn delete_network_list(&self, net: NetworkConfigList, rt: RuntimeConf) -> ResultCNI<()> {
175        net.plugins.into_iter().try_for_each(|x| {
176            self.delete_network(net.name.clone(), net.cni_version.clone(), x, rt.clone())
177        })?;
178        Ok(())
179    }
180
181    fn get_network_list_cached_result(
182        &self,
183        _net: NetworkConfigList,
184        _rt: RuntimeConf,
185    ) -> ResultCNI<Box<dyn APIResult>> {
186        todo!()
187    }
188
189    fn add_network(
190        &self,
191        name: String,
192        cni_version: String,
193        net: NetworkConfig,
194        prev_result: Option<Box<dyn APIResult>>,
195        rt: RuntimeConf,
196    ) -> ResultCNI<Box<dyn APIResult>> {
197        //ensureexec todo!()
198        let plugin_path = self
199            .exec
200            .find_in_path(net.network._type.clone(), self.path.clone())
201            .unwrap();
202
203        let environ = ExecArgs {
204            command: "ADD".to_string(),
205            containerd_id: rt.container_id.clone(),
206            netns: rt.net_ns.clone(),
207            plugin_args: rt.args.clone(),
208            plugin_args_str: String::default(),
209            ifname: rt.if_name.clone(),
210            path: self.path[0].clone(),
211        };
212
213        let new_conf = self.build_new_config(name, cni_version, &net, prev_result, &rt);
214        if let Ok(new_conf) = new_conf {
215            let r_result =
216                self.exec
217                    .exec_plugins(plugin_path, &new_conf.bytes, environ.to_env())?;
218            let pre_result_json: result100::Result = serde_json::from_slice(&r_result)
219                .map_err(|e| e.to_string())
220                .unwrap_or_else(|e| {
221                    println!("Failed to parse JSON: {}", e);
222                    result100::Result::default()
223                });
224            println!("cni_result {}", pre_result_json.get_json());
225            return Ok(Box::new(pre_result_json));
226        }
227        Err(Box::new(CNIError::ExecuteError("()".to_string())))
228    }
229
230    fn check_network(
231        &self,
232        name: String,
233        cni_version: String,
234        prev_result: Option<Box<dyn APIResult>>,
235        net: NetworkConfig,
236        rt: RuntimeConf,
237    ) -> ResultCNI<()> {
238        let plugin_path = self
239            .exec
240            .find_in_path(net.network._type.clone(), self.path.clone())
241            .unwrap();
242        let environ = ExecArgs {
243            command: "CHECK".to_string(),
244            containerd_id: rt.container_id.clone(),
245            netns: rt.net_ns.clone(),
246            plugin_args: rt.args.clone(),
247            plugin_args_str: String::default(),
248            ifname: rt.if_name.clone(),
249            path: self.path[0].clone(),
250        };
251        let new_conf = self.build_new_config(name, cni_version, &net, prev_result, &rt);
252        if let Ok(new_conf) = new_conf {
253            self.exec
254                .exec_plugins(plugin_path, &new_conf.bytes, environ.to_env())?;
255        }
256        Ok(())
257    }
258    fn delete_network(
259        &self,
260        name: String,
261        cni_version: String,
262        net: NetworkConfig,
263        rt: RuntimeConf,
264    ) -> ResultCNI<()> {
265        let environ = ExecArgs {
266            command: "DEL".to_string(),
267            containerd_id: rt.container_id,
268            netns: rt.net_ns,
269            plugin_args: rt.args,
270            plugin_args_str: String::default(),
271            ifname: rt.if_name,
272            path: self.path[0].clone(),
273        };
274
275        let plugin_path = self
276            .exec
277            .find_in_path(net.network._type, self.path.clone())
278            .unwrap();
279
280        // add network name and version
281        let mut json_object = json::parse(String::from_utf8_lossy(&net.bytes).as_ref()).unwrap();
282        json_object.insert("name", name).unwrap();
283        json_object.insert("cniVersion", cni_version).unwrap();
284        let new_stdin_data = json_object.dump().as_bytes().to_vec();
285
286        self.exec
287            .exec_plugins(plugin_path, &new_stdin_data, environ.to_env())?;
288
289        Ok(())
290    }
291
292    fn get_network_cached_result(
293        &self,
294        _net: NetworkConfig,
295        _rt: RuntimeConf,
296    ) -> ResultCNI<Box<dyn APIResult>> {
297        // let net_name = net.network.name.clone();
298
299        todo!()
300    }
301
302    fn get_network_cached_config(
303        &self,
304        _net: NetworkConfig,
305        _rt: RuntimeConf,
306    ) -> ResultCNI<(Vec<u8>, RuntimeConf)> {
307        todo!()
308    }
309
310    fn validate_network_list(&self, _net: NetworkConfigList) -> ResultCNI<Vec<String>> {
311        todo!()
312    }
313
314    fn validate_network(&self, _net: NetworkConfig) -> ResultCNI<Vec<String>> {
315        todo!()
316    }
317}