]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/config/media_pool.rs
6f72ac420994ac9a5a61e6968e08700b9dbcb4ea
[proxmox-backup.git] / src / api2 / config / media_pool.rs
1 use anyhow::{bail, Error};
2 use ::serde::{Deserialize, Serialize};
3
4 use proxmox_router::{Router, RpcEnvironment, Permission};
5 use proxmox_schema::api;
6
7 use pbs_api_types::{
8 Authid, MediaPoolConfig, MediaPoolConfigUpdater, MEDIA_POOL_NAME_SCHEMA,
9 PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
10 };
11
12 use pbs_config::CachedUserInfo;
13
14 #[api(
15 protected: true,
16 input: {
17 properties: {
18 config: {
19 type: MediaPoolConfig,
20 flatten: true,
21 },
22 },
23 },
24 access: {
25 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
26 },
27 )]
28 /// Create a new media pool
29 pub fn create_pool(
30 config: MediaPoolConfig,
31 ) -> Result<(), Error> {
32
33 let _lock = pbs_config::media_pool::lock()?;
34
35 let (mut section_config, _digest) = pbs_config::media_pool::config()?;
36
37 if section_config.sections.get(&config.name).is_some() {
38 bail!("Media pool '{}' already exists", config.name);
39 }
40
41 section_config.set_data(&config.name, "pool", &config)?;
42
43 pbs_config::media_pool::save_config(&section_config)?;
44
45 Ok(())
46 }
47
48 #[api(
49 returns: {
50 description: "The list of configured media pools (with config digest).",
51 type: Array,
52 items: {
53 type: MediaPoolConfig,
54 },
55 },
56 access: {
57 description: "List configured media pools filtered by Tape.Audit privileges",
58 permission: &Permission::Anybody,
59 },
60 )]
61 /// List media pools
62 pub fn list_pools(
63 mut rpcenv: &mut dyn RpcEnvironment,
64 ) -> Result<Vec<MediaPoolConfig>, Error> {
65 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
66 let user_info = CachedUserInfo::new()?;
67
68 let (config, digest) = pbs_config::media_pool::config()?;
69
70 let list = config.convert_to_typed_array::<MediaPoolConfig>("pool")?;
71
72 let list = list
73 .into_iter()
74 .filter(|pool| {
75 let privs = user_info.lookup_privs(&auth_id, &["tape", "pool", &pool.name]);
76 privs & PRIV_TAPE_AUDIT != 0
77 })
78 .collect();
79
80 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
81
82 Ok(list)
83 }
84
85 #[api(
86 input: {
87 properties: {
88 name: {
89 schema: MEDIA_POOL_NAME_SCHEMA,
90 },
91 },
92 },
93 returns: {
94 type: MediaPoolConfig,
95 },
96 access: {
97 permission: &Permission::Privilege(&["tape", "pool", "{name}"], PRIV_TAPE_AUDIT, false),
98 },
99 )]
100 /// Get media pool configuration
101 pub fn get_config(name: String) -> Result<MediaPoolConfig, Error> {
102
103 let (config, _digest) = pbs_config::media_pool::config()?;
104
105 let data: MediaPoolConfig = config.lookup("pool", &name)?;
106
107 Ok(data)
108 }
109
110 #[api()]
111 #[derive(Serialize, Deserialize)]
112 #[allow(non_camel_case_types)]
113 /// Deletable property name
114 pub enum DeletableProperty {
115 /// Delete media set allocation policy.
116 allocation,
117 /// Delete pool retention policy
118 retention,
119 /// Delete media set naming template
120 template,
121 /// Delete encryption fingerprint
122 encrypt,
123 /// Delete comment
124 comment,
125 }
126
127 #[api(
128 protected: true,
129 input: {
130 properties: {
131 name: {
132 schema: MEDIA_POOL_NAME_SCHEMA,
133 },
134 update: {
135 type: MediaPoolConfigUpdater,
136 flatten: true,
137 },
138 delete: {
139 description: "List of properties to delete.",
140 type: Array,
141 optional: true,
142 items: {
143 type: DeletableProperty,
144 }
145 },
146 },
147 },
148 access: {
149 permission: &Permission::Privilege(&["tape", "pool", "{name}"], PRIV_TAPE_MODIFY, false),
150 },
151 )]
152 /// Update media pool settings
153 pub fn update_pool(
154 name: String,
155 update: MediaPoolConfigUpdater,
156 delete: Option<Vec<DeletableProperty>>,
157 ) -> Result<(), Error> {
158
159 let _lock = pbs_config::media_pool::lock()?;
160
161 let (mut config, _digest) = pbs_config::media_pool::config()?;
162
163 let mut data: MediaPoolConfig = config.lookup("pool", &name)?;
164
165 if let Some(delete) = delete {
166 for delete_prop in delete {
167 match delete_prop {
168 DeletableProperty::allocation => { data.allocation = None; },
169 DeletableProperty::retention => { data.retention = None; },
170 DeletableProperty::template => { data.template = None; },
171 DeletableProperty::encrypt => { data.encrypt = None; },
172 DeletableProperty::comment => { data.comment = None; },
173 }
174 }
175 }
176
177 if update.allocation.is_some() { data.allocation = update.allocation; }
178 if update.retention.is_some() { data.retention = update.retention; }
179 if update.template.is_some() { data.template = update.template; }
180 if update.encrypt.is_some() { data.encrypt = update.encrypt; }
181
182 if let Some(comment) = update.comment {
183 let comment = comment.trim();
184 if comment.is_empty() {
185 data.comment = None;
186 } else {
187 data.comment = Some(comment.to_string());
188 }
189 }
190
191 config.set_data(&name, "pool", &data)?;
192
193 pbs_config::media_pool::save_config(&config)?;
194
195 Ok(())
196 }
197
198 #[api(
199 protected: true,
200 input: {
201 properties: {
202 name: {
203 schema: MEDIA_POOL_NAME_SCHEMA,
204 },
205 },
206 },
207 access: {
208 permission: &Permission::Privilege(&["tape", "pool", "{name}"], PRIV_TAPE_MODIFY, false),
209 },
210 )]
211 /// Delete a media pool configuration
212 pub fn delete_pool(name: String) -> Result<(), Error> {
213
214 let _lock = pbs_config::media_pool::lock()?;
215
216 let (mut config, _digest) = pbs_config::media_pool::config()?;
217
218 match config.sections.get(&name) {
219 Some(_) => { config.sections.remove(&name); },
220 None => bail!("delete pool '{}' failed - no such pool", name),
221 }
222
223 pbs_config::media_pool::save_config(&config)?;
224
225 Ok(())
226 }
227
228 const ITEM_ROUTER: Router = Router::new()
229 .get(&API_METHOD_GET_CONFIG)
230 .put(&API_METHOD_UPDATE_POOL)
231 .delete(&API_METHOD_DELETE_POOL);
232
233
234 pub const ROUTER: Router = Router::new()
235 .get(&API_METHOD_LIST_POOLS)
236 .post(&API_METHOD_CREATE_POOL)
237 .match_all("name", &ITEM_ROUTER);