]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/traffic_control.rs
api: tape: don't allow overwriting of ids in changer/drive config
[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
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.
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)?;
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
106pub 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.
152pub 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.
251pub 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
273const 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
278pub 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);