]>
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 | ||
16f6766a | 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)?; | |
16f6766a | 98 | rpcenv["digest"] = hex::encode(digest).into(); |
bfd12e87 DM |
99 | Ok(data) |
100 | } | |
101 | ||
102 | #[api()] | |
103 | #[derive(Serialize, Deserialize)] | |
4fe77c36 | 104 | #[serde(rename_all = "kebab-case")] |
bfd12e87 DM |
105 | /// Deletable property name |
106 | pub enum DeletableProperty { | |
107 | /// Delete the rate_in property. | |
a2055c38 | 108 | RateIn, |
bfd12e87 | 109 | /// Delete the burst_in property. |
a2055c38 | 110 | BurstIn, |
bfd12e87 | 111 | /// Delete the rate_out property. |
a2055c38 | 112 | RateOut, |
bfd12e87 | 113 | /// Delete the burst_out property. |
a2055c38 | 114 | BurstOut, |
bfd12e87 | 115 | /// Delete the comment property. |
a2055c38 | 116 | Comment, |
bfd12e87 | 117 | /// Delete the timeframe property |
a2055c38 | 118 | Timeframe, |
bfd12e87 DM |
119 | } |
120 | ||
121 | // fixme: use TrafficControlUpdater | |
122 | #[api( | |
123 | protected: true, | |
124 | input: { | |
125 | properties: { | |
126 | name: { | |
127 | schema: TRAFFIC_CONTROL_ID_SCHEMA, | |
128 | }, | |
129 | update: { | |
130 | type: TrafficControlRuleUpdater, | |
131 | flatten: true, | |
132 | }, | |
133 | delete: { | |
134 | description: "List of properties to delete.", | |
135 | type: Array, | |
136 | optional: true, | |
137 | items: { | |
138 | type: DeletableProperty, | |
139 | } | |
140 | }, | |
141 | digest: { | |
142 | optional: true, | |
143 | schema: PROXMOX_CONFIG_DIGEST_SCHEMA, | |
144 | }, | |
145 | }, | |
146 | }, | |
147 | access: { | |
148 | permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false), | |
149 | }, | |
150 | )] | |
151 | /// Update traffic control configuration. | |
152 | pub fn update_traffic_control( | |
153 | name: String, | |
154 | update: TrafficControlRuleUpdater, | |
155 | delete: Option<Vec<DeletableProperty>>, | |
156 | digest: Option<String>, | |
157 | ) -> Result<(), Error> { | |
bfd12e87 DM |
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 { | |
a2055c38 | 172 | DeletableProperty::RateIn => { |
dc7a5b34 TL |
173 | data.limit.rate_in = None; |
174 | } | |
a2055c38 | 175 | DeletableProperty::RateOut => { |
dc7a5b34 TL |
176 | data.limit.rate_out = None; |
177 | } | |
a2055c38 | 178 | DeletableProperty::BurstIn => { |
dc7a5b34 TL |
179 | data.limit.burst_in = None; |
180 | } | |
a2055c38 | 181 | DeletableProperty::BurstOut => { |
dc7a5b34 TL |
182 | data.limit.burst_out = None; |
183 | } | |
a2055c38 | 184 | DeletableProperty::Comment => { |
dc7a5b34 TL |
185 | data.comment = None; |
186 | } | |
a2055c38 | 187 | DeletableProperty::Timeframe => { |
dc7a5b34 TL |
188 | data.timeframe = None; |
189 | } | |
bfd12e87 DM |
190 | } |
191 | } | |
192 | } | |
193 | ||
194 | if let Some(comment) = update.comment { | |
195 | let comment = comment.trim().to_string(); | |
196 | if comment.is_empty() { | |
197 | data.comment = None; | |
198 | } else { | |
199 | data.comment = Some(comment); | |
200 | } | |
201 | } | |
202 | ||
56472190 DM |
203 | if update.limit.rate_in.is_some() { |
204 | data.limit.rate_in = update.limit.rate_in; | |
205 | } | |
206 | ||
207 | if update.limit.rate_out.is_some() { | |
208 | data.limit.rate_out = update.limit.rate_out; | |
209 | } | |
210 | ||
211 | if update.limit.burst_in.is_some() { | |
212 | data.limit.burst_in = update.limit.burst_in; | |
213 | } | |
214 | ||
215 | if update.limit.burst_out.is_some() { | |
216 | data.limit.burst_out = update.limit.burst_out; | |
217 | } | |
bfd12e87 | 218 | |
dc7a5b34 TL |
219 | if let Some(network) = update.network { |
220 | data.network = network; | |
221 | } | |
222 | if update.timeframe.is_some() { | |
223 | data.timeframe = update.timeframe; | |
224 | } | |
bfd12e87 DM |
225 | |
226 | config.set_data(&name, "rule", &data)?; | |
227 | ||
228 | pbs_config::traffic_control::save_config(&config)?; | |
229 | ||
230 | Ok(()) | |
231 | } | |
232 | ||
233 | #[api( | |
234 | protected: true, | |
235 | input: { | |
236 | properties: { | |
237 | name: { | |
238 | schema: TRAFFIC_CONTROL_ID_SCHEMA, | |
239 | }, | |
240 | digest: { | |
241 | optional: true, | |
242 | schema: PROXMOX_CONFIG_DIGEST_SCHEMA, | |
243 | }, | |
244 | }, | |
245 | }, | |
246 | access: { | |
247 | permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false), | |
248 | }, | |
249 | )] | |
250 | /// Remove a traffic control rule from the configuration file. | |
251 | pub fn delete_traffic_control(name: String, digest: Option<String>) -> Result<(), Error> { | |
bfd12e87 DM |
252 | let _lock = pbs_config::traffic_control::lock_config()?; |
253 | ||
254 | let (mut config, expected_digest) = pbs_config::traffic_control::config()?; | |
255 | ||
256 | if let Some(ref digest) = digest { | |
25877d05 | 257 | let digest = <[u8; 32]>::from_hex(digest)?; |
bfd12e87 DM |
258 | crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?; |
259 | } | |
260 | ||
261 | match config.sections.get(&name) { | |
dc7a5b34 TL |
262 | Some(_) => { |
263 | config.sections.remove(&name); | |
264 | } | |
dcd1518e | 265 | None => http_bail!(NOT_FOUND, "traffic control rule '{}' does not exist.", name), |
bfd12e87 DM |
266 | } |
267 | ||
268 | pbs_config::traffic_control::save_config(&config)?; | |
269 | ||
270 | Ok(()) | |
271 | } | |
272 | ||
bfd12e87 DM |
273 | const ITEM_ROUTER: Router = Router::new() |
274 | .get(&API_METHOD_READ_TRAFFIC_CONTROL) | |
275 | .put(&API_METHOD_UPDATE_TRAFFIC_CONTROL) | |
276 | .delete(&API_METHOD_DELETE_TRAFFIC_CONTROL); | |
277 | ||
278 | pub const ROUTER: Router = Router::new() | |
279 | .get(&API_METHOD_LIST_TRAFFIC_CONTROLS) | |
280 | .post(&API_METHOD_CREATE_TRAFFIC_CONTROL) | |
281 | .match_all("name", &ITEM_ROUTER); |