1use serde::{Deserialize, Serialize};
3
4use crate::libcni::result::ResultCNI;
5use crate::libcni::CNIError;
6use std::process::Stdio;
7use std::{collections::HashMap, io::Write};
8
9#[derive(Default, Serialize, Deserialize)]
10pub struct ExecArgs {
11 pub(crate) command: String,
12 pub(crate) containerd_id: String,
13 pub(crate) netns: String,
14 pub(crate) plugin_args: Vec<[String; 2]>,
15 pub(crate) plugin_args_str: String,
16 pub(crate) ifname: String,
17 pub(crate) path: String,
18}
19
20impl ExecArgs {
21 pub fn to_env(&self) -> Vec<String> {
22 let mut result_env = Vec::default();
23 std::env::set_var("CNI_COMMAND", self.command.clone());
25 std::env::set_var("CNI_CONTAINERID", self.containerd_id.clone());
26 std::env::set_var("CNI_NETNS", self.netns.clone());
27 std::env::set_var("CNI_ARGS", self.plugin_args_str.clone());
28 std::env::set_var("CNI_IFNAME", self.ifname.clone());
29 std::env::set_var("CNI_PATH", self.path.clone());
30
31 for (k, v) in std::env::vars() {
32 result_env.push((k + "=" + &v).to_string());
33 }
34 result_env
35 }
36}
37pub trait Exec {
38 fn exec_plugins(
39 &self,
40 plugin_path: String,
41 stdin_data: &[u8],
42 environ: Vec<String>,
43 ) -> super::ResultCNI<Vec<u8>>;
44 fn find_in_path(&self, plugin: String, paths: Vec<String>) -> ResultCNI<String>;
45 fn decode(&self, data: &[u8]) -> ResultCNI<()>;
46}
47
48#[derive(Default)]
49pub struct RawExec {}
50
51impl Exec for RawExec {
52 fn exec_plugins(
53 &self,
54 plugin_path: String,
55 stdin_data: &[u8],
56 environ: Vec<String>,
57 ) -> ResultCNI<Vec<u8>> {
58 let envs: HashMap<String, String> = environ
59 .iter()
60 .map(|key| key.split('=').collect::<Vec<&str>>())
61 .map(|kv| (kv[0].to_string(), kv[1].to_string()))
62 .collect();
63
64 println!(
65 "send plugin to {:?}\n\n",
66 String::from_utf8(stdin_data.to_vec()).unwrap()
67 );
68
69 let mut plugin_cmd = std::process::Command::new(plugin_path)
70 .stdin(Stdio::piped())
71 .stdout(Stdio::piped())
72 .stderr(Stdio::piped())
73 .envs(envs)
74 .spawn()
75 .expect("start plugin error");
76
77 let mut stdin = plugin_cmd.stdin.take().unwrap();
78 stdin.write_all(stdin_data).unwrap();
79 drop(stdin);
81
82 let output = plugin_cmd.wait_with_output().unwrap();
83
84 let std_out_json: serde_json::Value =
86 serde_json::from_slice(&output.stdout).unwrap_or_default();
87 if std_out_json.get("code").is_some() {
88 let msg = String::from_utf8_lossy(&output.stdout.clone()).to_string();
89 println!("error:{}", msg);
90 return Err(Box::new(CNIError::ExecuteError(msg)));
91 }
92
93 Ok(output.stdout)
94 }
95
96 fn find_in_path(&self, plugin: String, paths: Vec<String>) -> ResultCNI<String> {
97 if !paths.is_empty() {
98 return Ok(paths[0].clone() + "/" + &plugin);
99 }
100
101 Ok(String::default())
102 }
103
104 fn decode(&self, _data: &[u8]) -> ResultCNI<()> {
105 todo!()
106 }
107}
108
109