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