rust_cni/
namespace.rs

1use log::{debug, error, info, trace};
2use std::{collections::HashMap, sync::Arc};
3
4use crate::libcni::{
5    self,
6    api::{RuntimeConf, CNI},
7};
8
9pub struct Network {
10    pub cni: Arc<Box<dyn CNI + Send + Sync>>,
11    pub config: libcni::api::NetworkConfigList,
12    pub ifname: String,
13}
14
15impl Network {
16    pub fn attach(&self, ns: &Namespace) -> Result<(), String> {
17        debug!(
18            "Attaching network {} with interface {}",
19            self.config.name, self.ifname
20        );
21
22        match self
23            .cni
24            .add_network_list(self.config.clone(), ns.config(self.ifname.clone()))
25        {
26            Ok(result) => {
27                info!(
28                    "Successfully attached network {} to namespace",
29                    self.config.name
30                );
31                trace!("Network attachment result: {:?}", result.get_json());
32                Ok(())
33            }
34            Err(e) => Err(e.to_string()),
35        }
36    }
37
38    pub fn remove(&self, ns: &Namespace) -> Result<(), String> {
39        debug!(
40            "Removing network {} with interface {}",
41            self.config.name, self.ifname
42        );
43
44        match self
45            .cni
46            .delete_network_list(self.config.clone(), ns.config(self.ifname.clone()))
47        {
48            Ok(_) => {
49                info!(
50                    "Successfully removed network {} from namespace",
51                    self.config.name
52                );
53                Ok(())
54            }
55            Err(e) => {
56                let err_msg = format!("Failed to remove network {}: {}", self.config.name, e);
57                error!("{}", err_msg);
58                Err(err_msg)
59            }
60        }
61    }
62
63    pub fn check(&self, ns: &Namespace) -> Result<(), String> {
64        debug!(
65            "Checking network {} with interface {}",
66            self.config.name, self.ifname
67        );
68
69        match self
70            .cni
71            .check_network_list(self.config.clone(), ns.config(self.ifname.clone()))
72        {
73            Ok(_) => {
74                debug!("Network {} is properly configured", self.config.name);
75                Ok(())
76            }
77            Err(e) => {
78                let err_msg = format!("Network check failed for {}: {}", self.config.name, e);
79                error!("{}", err_msg);
80                Err(err_msg)
81            }
82        }
83    }
84
85    pub fn get_stats(&self, ns: &Namespace) -> Result<String, String> {
86        debug!(
87            "Getting stats for network {} with interface {}",
88            self.config.name, self.ifname
89        );
90
91        match self
92            .cni
93            .get_network_list_cached_result(self.config.clone(), ns.config(self.ifname.clone()))
94        {
95            Ok(result) => {
96                let stats_json = result.get_json().dump();
97                trace!("Network stats: {}", stats_json);
98                Ok(stats_json)
99            }
100            Err(e) => {
101                let err_msg = format!(
102                    "Failed to get stats for network {}: {}",
103                    self.config.name, e
104                );
105                error!("{}", err_msg);
106                Err(err_msg)
107            }
108        }
109    }
110}
111
112#[derive(Clone, Default)]
113pub struct Namespace {
114    id: String,
115    path: String,
116    capability_args: HashMap<String, String>,
117    args: HashMap<String, String>,
118}
119
120impl Namespace {
121    pub fn new(id: String, path: String) -> Self {
122        debug!(
123            "Creating new namespace for container {} at path {}",
124            id, path
125        );
126        Self {
127            id,
128            path,
129            capability_args: HashMap::default(),
130            args: HashMap::default(),
131        }
132    }
133
134    pub fn with_args(mut self, args: HashMap<String, String>) -> Self {
135        debug!("Adding {} arguments to namespace", args.len());
136        self.args = args;
137        self
138    }
139
140    pub fn with_capabilities(mut self, capabilities: HashMap<String, String>) -> Self {
141        debug!("Adding {} capabilities to namespace", capabilities.len());
142        self.capability_args = capabilities;
143        self
144    }
145
146    pub fn add_arg(&mut self, key: &str, value: &str) {
147        debug!("Adding argument {}={} to namespace", key, value);
148        self.args.insert(key.to_string(), value.to_string());
149    }
150
151    pub fn add_capability(&mut self, key: &str, value: &str) {
152        debug!("Adding capability {}={} to namespace", key, value);
153        self.capability_args
154            .insert(key.to_string(), value.to_string());
155    }
156
157    pub fn config(&self, ifname: String) -> libcni::api::RuntimeConf {
158        trace!(
159            "Creating runtime config for namespace with interface {}",
160            ifname
161        );
162        let args = self
163            .args
164            .iter()
165            .map(|(key, val)| [key.clone(), val.clone()])
166            .collect();
167
168        RuntimeConf {
169            container_id: self.id.clone(),
170            net_ns: self.path.clone(),
171            if_name: ifname,
172            args,
173            capability_args: self.capability_args.clone(),
174            cache_dir: String::default(),
175        }
176    }
177
178    pub fn get_id(&self) -> &str {
179        &self.id
180    }
181
182    pub fn get_path(&self) -> &str {
183        &self.path
184    }
185}