rust_cni/libcni/
exec.rs

1// Copyright (c) 2024 https://github.com/divinerapier/cni-rs
2use 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        //get ose env
24        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        //stdin over close fifo
80        drop(stdin);
81
82        let output = plugin_cmd.wait_with_output().unwrap();
83
84        // println!("{:?}",output.stdout);
85        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// struct BufferedStdin<'a> {
110//     buf: &'a [u8],
111// }
112
113// impl<'a> BufferedStdin<'a> {
114//     fn new(buf: &'a [u8]) -> BufferedStdin {
115//         BufferedStdin { buf }
116//     }
117// }
118
119// impl<'a> Into<Stdio> for BufferedStdin<'a> {
120//     fn into(self) -> Stdio {
121//         todo!()
122//     }
123// }