]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/traffic_control.rs
router change made one level of rpcenv mut superfluous
[proxmox-backup.git] / src / api2 / config / traffic_control.rs
CommitLineData
bfd12e87 1use ::serde::{Deserialize, Serialize};
dc7a5b34 2use anyhow::Error;
25877d05 3use hex::FromHex;
dc7a5b34 4use serde_json::Value;
bfd12e87 5
dc7a5b34 6use proxmox_router::{http_bail, ApiMethod, Permission, Router, RpcEnvironment};
8d6425aa 7use proxmox_schema::{api, param_bail};
bfd12e87
DM
8
9use 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
28pub 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.
57pub 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(&section_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.
91pub 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
107pub 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.
153pub 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.
252pub 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
274const 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
279pub 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);