]>
Commit | Line | Data |
---|---|---|
bfd12e87 DM |
1 | use anyhow::{bail, Error}; |
2 | use serde_json::Value; | |
3 | use ::serde::{Deserialize, Serialize}; | |
25877d05 | 4 | use hex::FromHex; |
bfd12e87 DM |
5 | |
6 | use proxmox_router::{ApiMethod, Router, RpcEnvironment, Permission}; | |
7 | use proxmox_schema::api; | |
8 | ||
9 | use pbs_api_types::{ | |
10 | TrafficControlRule, TrafficControlRuleUpdater, | |
11 | PROXMOX_CONFIG_DIGEST_SCHEMA, TRAFFIC_CONTROL_ID_SCHEMA, | |
12 | PRIV_SYS_AUDIT, PRIV_SYS_MODIFY, | |
13 | }; | |
14 | ||
15 | #[api( | |
16 | input: { | |
17 | properties: {}, | |
18 | }, | |
19 | returns: { | |
20 | description: "The list of configured traffic control rules (with config digest).", | |
21 | type: Array, | |
22 | items: { type: TrafficControlRule }, | |
23 | }, | |
24 | access: { | |
25 | permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false), | |
26 | }, | |
27 | )] | |
28 | /// List traffic control rules | |
29 | pub fn list_traffic_controls( | |
30 | _param: Value, | |
31 | _info: &ApiMethod, | |
32 | mut rpcenv: &mut dyn RpcEnvironment, | |
33 | ) -> Result<Vec<TrafficControlRule>, Error> { | |
34 | let (config, digest) = pbs_config::traffic_control::config()?; | |
35 | ||
36 | let list: Vec<TrafficControlRule> = config.convert_to_typed_array("rule")?; | |
37 | ||
25877d05 | 38 | rpcenv["digest"] = hex::encode(&digest).into(); |
bfd12e87 DM |
39 | |
40 | Ok(list) | |
41 | } | |
42 | ||
43 | #[api( | |
44 | protected: true, | |
45 | input: { | |
46 | properties: { | |
47 | config: { | |
48 | type: TrafficControlRule, | |
49 | flatten: true, | |
50 | }, | |
51 | }, | |
52 | }, | |
53 | access: { | |
54 | permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false), | |
55 | }, | |
56 | )] | |
57 | /// Create new traffic control rule. | |
58 | pub fn create_traffic_control(config: TrafficControlRule) -> Result<(), Error> { | |
59 | ||
60 | let _lock = pbs_config::traffic_control::lock_config()?; | |
61 | ||
62 | let (mut section_config, _digest) = pbs_config::traffic_control::config()?; | |
63 | ||
64 | if section_config.sections.get(&config.name).is_some() { | |
65 | bail!("traffic control rule '{}' already exists.", config.name); | |
66 | } | |
67 | ||
68 | section_config.set_data(&config.name, "rule", &config)?; | |
69 | ||
70 | pbs_config::traffic_control::save_config(§ion_config)?; | |
71 | ||
72 | Ok(()) | |
73 | } | |
74 | ||
75 | #[api( | |
76 | input: { | |
77 | properties: { | |
78 | name: { | |
79 | schema: TRAFFIC_CONTROL_ID_SCHEMA, | |
80 | }, | |
81 | }, | |
82 | }, | |
83 | returns: { type: TrafficControlRule }, | |
84 | access: { | |
85 | permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false), | |
86 | } | |
87 | )] | |
88 | /// Read traffic control configuration data. | |
89 | pub fn read_traffic_control( | |
90 | name: String, | |
91 | _info: &ApiMethod, | |
92 | mut rpcenv: &mut dyn RpcEnvironment, | |
93 | ) -> Result<TrafficControlRule, Error> { | |
94 | let (config, digest) = pbs_config::traffic_control::config()?; | |
95 | let data: TrafficControlRule = config.lookup("rule", &name)?; | |
25877d05 | 96 | rpcenv["digest"] = hex::encode(&digest).into(); |
bfd12e87 DM |
97 | Ok(data) |
98 | } | |
99 | ||
100 | #[api()] | |
101 | #[derive(Serialize, Deserialize)] | |
102 | #[allow(non_camel_case_types)] | |
4fe77c36 | 103 | #[serde(rename_all = "kebab-case")] |
bfd12e87 DM |
104 | /// Deletable property name |
105 | pub enum DeletableProperty { | |
106 | /// Delete the rate_in property. | |
107 | rate_in, | |
108 | /// Delete the burst_in property. | |
109 | burst_in, | |
110 | /// Delete the rate_out property. | |
111 | rate_out, | |
112 | /// Delete the burst_out property. | |
113 | burst_out, | |
114 | /// Delete the comment property. | |
115 | comment, | |
116 | /// Delete the timeframe property | |
117 | timeframe, | |
118 | } | |
119 | ||
120 | // fixme: use TrafficControlUpdater | |
121 | #[api( | |
122 | protected: true, | |
123 | input: { | |
124 | properties: { | |
125 | name: { | |
126 | schema: TRAFFIC_CONTROL_ID_SCHEMA, | |
127 | }, | |
128 | update: { | |
129 | type: TrafficControlRuleUpdater, | |
130 | flatten: true, | |
131 | }, | |
132 | delete: { | |
133 | description: "List of properties to delete.", | |
134 | type: Array, | |
135 | optional: true, | |
136 | items: { | |
137 | type: DeletableProperty, | |
138 | } | |
139 | }, | |
140 | digest: { | |
141 | optional: true, | |
142 | schema: PROXMOX_CONFIG_DIGEST_SCHEMA, | |
143 | }, | |
144 | }, | |
145 | }, | |
146 | access: { | |
147 | permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false), | |
148 | }, | |
149 | )] | |
150 | /// Update traffic control configuration. | |
151 | pub fn update_traffic_control( | |
152 | name: String, | |
153 | update: TrafficControlRuleUpdater, | |
154 | delete: Option<Vec<DeletableProperty>>, | |
155 | digest: Option<String>, | |
156 | ) -> Result<(), Error> { | |
157 | ||
158 | let _lock = pbs_config::traffic_control::lock_config()?; | |
159 | ||
160 | let (mut config, expected_digest) = pbs_config::traffic_control::config()?; | |
161 | ||
162 | if let Some(ref digest) = digest { | |
25877d05 | 163 | let digest = <[u8; 32]>::from_hex(digest)?; |
bfd12e87 DM |
164 | crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?; |
165 | } | |
166 | ||
167 | let mut data: TrafficControlRule = config.lookup("rule", &name)?; | |
168 | ||
169 | if let Some(delete) = delete { | |
170 | for delete_prop in delete { | |
171 | match delete_prop { | |
56472190 DM |
172 | DeletableProperty::rate_in => { data.limit.rate_in = None; }, |
173 | DeletableProperty::rate_out => { data.limit.rate_out = None; }, | |
174 | DeletableProperty::burst_in => { data.limit.burst_in = None; }, | |
175 | DeletableProperty::burst_out => { data.limit.burst_out = None; }, | |
bfd12e87 DM |
176 | DeletableProperty::comment => { data.comment = None; }, |
177 | DeletableProperty::timeframe => { data.timeframe = None; }, | |
178 | } | |
179 | } | |
180 | } | |
181 | ||
182 | if let Some(comment) = update.comment { | |
183 | let comment = comment.trim().to_string(); | |
184 | if comment.is_empty() { | |
185 | data.comment = None; | |
186 | } else { | |
187 | data.comment = Some(comment); | |
188 | } | |
189 | } | |
190 | ||
56472190 DM |
191 | if update.limit.rate_in.is_some() { |
192 | data.limit.rate_in = update.limit.rate_in; | |
193 | } | |
194 | ||
195 | if update.limit.rate_out.is_some() { | |
196 | data.limit.rate_out = update.limit.rate_out; | |
197 | } | |
198 | ||
199 | if update.limit.burst_in.is_some() { | |
200 | data.limit.burst_in = update.limit.burst_in; | |
201 | } | |
202 | ||
203 | if update.limit.burst_out.is_some() { | |
204 | data.limit.burst_out = update.limit.burst_out; | |
205 | } | |
bfd12e87 | 206 | |
bfd12e87 DM |
207 | if let Some(network) = update.network { data.network = network; } |
208 | if update.timeframe.is_some() { data.timeframe = update.timeframe; } | |
209 | ||
210 | config.set_data(&name, "rule", &data)?; | |
211 | ||
212 | pbs_config::traffic_control::save_config(&config)?; | |
213 | ||
214 | Ok(()) | |
215 | } | |
216 | ||
217 | #[api( | |
218 | protected: true, | |
219 | input: { | |
220 | properties: { | |
221 | name: { | |
222 | schema: TRAFFIC_CONTROL_ID_SCHEMA, | |
223 | }, | |
224 | digest: { | |
225 | optional: true, | |
226 | schema: PROXMOX_CONFIG_DIGEST_SCHEMA, | |
227 | }, | |
228 | }, | |
229 | }, | |
230 | access: { | |
231 | permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false), | |
232 | }, | |
233 | )] | |
234 | /// Remove a traffic control rule from the configuration file. | |
235 | pub fn delete_traffic_control(name: String, digest: Option<String>) -> Result<(), Error> { | |
236 | ||
237 | let _lock = pbs_config::traffic_control::lock_config()?; | |
238 | ||
239 | let (mut config, expected_digest) = pbs_config::traffic_control::config()?; | |
240 | ||
241 | if let Some(ref digest) = digest { | |
25877d05 | 242 | let digest = <[u8; 32]>::from_hex(digest)?; |
bfd12e87 DM |
243 | crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?; |
244 | } | |
245 | ||
246 | match config.sections.get(&name) { | |
247 | Some(_) => { config.sections.remove(&name); }, | |
248 | None => bail!("traffic control rule '{}' does not exist.", name), | |
249 | } | |
250 | ||
251 | pbs_config::traffic_control::save_config(&config)?; | |
252 | ||
253 | Ok(()) | |
254 | } | |
255 | ||
256 | ||
257 | const ITEM_ROUTER: Router = Router::new() | |
258 | .get(&API_METHOD_READ_TRAFFIC_CONTROL) | |
259 | .put(&API_METHOD_UPDATE_TRAFFIC_CONTROL) | |
260 | .delete(&API_METHOD_DELETE_TRAFFIC_CONTROL); | |
261 | ||
262 | pub const ROUTER: Router = Router::new() | |
263 | .get(&API_METHOD_LIST_TRAFFIC_CONTROLS) | |
264 | .post(&API_METHOD_CREATE_TRAFFIC_CONTROL) | |
265 | .match_all("name", &ITEM_ROUTER); |