]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/tape_backup_job.rs
move acl to pbs_config workspaces, pbs_api_types cleanups
[proxmox-backup.git] / src / api2 / config / tape_backup_job.rs
CommitLineData
0b90c67f 1use anyhow::{bail, Error};
be327dbc
DM
2use serde_json::Value;
3use ::serde::{Deserialize, Serialize};
4
0b90c67f 5use proxmox::api::{api, Router, RpcEnvironment, Permission};
e3619d41
DM
6
7use pbs_api_types::{
cdc83c4e
DM
8 Authid, TapeBackupJobConfig, TapeBackupJobConfigUpdater,
9 JOB_ID_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA,
8cc3760e 10 PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
e3619d41 11};
be327dbc 12
8cc3760e 13use crate::config::cached_user_info::CachedUserInfo;
be327dbc
DM
14
15#[api(
16 input: {
17 properties: {},
18 },
19 returns: {
20 description: "List configured jobs.",
21 type: Array,
22 items: { type: TapeBackupJobConfig },
23 },
396fd747
DM
24 access: {
25 description: "List configured tape jobs filtered by Tape.Audit privileges",
26 permission: &Permission::Anybody,
27 },
be327dbc
DM
28)]
29/// List all tape backup jobs
30pub fn list_tape_backup_jobs(
31 _param: Value,
32 mut rpcenv: &mut dyn RpcEnvironment,
33) -> Result<Vec<TapeBackupJobConfig>, Error> {
396fd747
DM
34 let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
35 let user_info = CachedUserInfo::new()?;
be327dbc 36
e3619d41 37 let (config, digest) = pbs_config::tape_job::config()?;
be327dbc 38
396fd747
DM
39 let list = config.convert_to_typed_array::<TapeBackupJobConfig>("backup")?;
40
41 let list = list
42 .into_iter()
43 .filter(|job| {
44 let privs = user_info.lookup_privs(&auth_id, &["tape", "job", &job.id]);
45 privs & PRIV_TAPE_AUDIT != 0
46 })
47 .collect();
be327dbc
DM
48
49 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
50
51 Ok(list)
52}
53
54#[api(
55 protected: true,
56 input: {
57 properties: {
58 job: {
59 type: TapeBackupJobConfig,
60 flatten: true,
61 },
62 },
63 },
396fd747
DM
64 access: {
65 permission: &Permission::Privilege(&["tape", "job"], PRIV_TAPE_MODIFY, false),
66 },
be327dbc
DM
67)]
68/// Create a new tape backup job.
69pub fn create_tape_backup_job(
70 job: TapeBackupJobConfig,
71 _rpcenv: &mut dyn RpcEnvironment,
72) -> Result<(), Error> {
e3619d41 73 let _lock = pbs_config::tape_job::lock()?;
be327dbc 74
e3619d41 75 let (mut config, _digest) = pbs_config::tape_job::config()?;
be327dbc
DM
76
77 if config.sections.get(&job.id).is_some() {
78 bail!("job '{}' already exists.", job.id);
79 }
80
81 config.set_data(&job.id, "backup", &job)?;
82
e3619d41 83 pbs_config::tape_job::save_config(&config)?;
be327dbc 84
8513626b
DM
85 crate::server::jobstate::create_state_file("tape-backup-job", &job.id)?;
86
be327dbc
DM
87 Ok(())
88}
89
90#[api(
91 input: {
92 properties: {
93 id: {
94 schema: JOB_ID_SCHEMA,
95 },
96 },
97 },
98 returns: { type: TapeBackupJobConfig },
396fd747
DM
99 access: {
100 permission: &Permission::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_AUDIT, false),
101 },
be327dbc
DM
102)]
103/// Read a tape backup job configuration.
104pub fn read_tape_backup_job(
105 id: String,
106 mut rpcenv: &mut dyn RpcEnvironment,
107) -> Result<TapeBackupJobConfig, Error> {
108
e3619d41 109 let (config, digest) = pbs_config::tape_job::config()?;
be327dbc
DM
110
111 let job = config.lookup("backup", &id)?;
112
113 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
114
115 Ok(job)
116}
117
118#[api()]
119#[derive(Serialize, Deserialize)]
120#[serde(rename_all="kebab-case")]
be327dbc
DM
121/// Deletable property name
122pub enum DeletableProperty {
123 /// Delete the comment property.
fe291ab7 124 Comment,
be327dbc 125 /// Delete the job schedule.
fe291ab7 126 Schedule,
8513626b 127 /// Delete the eject-media property
fe291ab7 128 EjectMedia,
8513626b 129 /// Delete the export-media-set property
fe291ab7 130 ExportMediaSet,
21e3ed34
DM
131 /// Delete the 'latest-only' property
132 LatestOnly,
9152a007
DC
133 /// Delete the 'notify-user' property
134 NotifyUser,
be327dbc
DM
135}
136
137#[api(
138 protected: true,
139 input: {
140 properties: {
0b90c67f
DM
141 id: {
142 schema: JOB_ID_SCHEMA,
143 },
cdc83c4e
DM
144 update: {
145 type: TapeBackupJobConfigUpdater,
146 flatten: true,
be327dbc
DM
147 },
148 delete: {
149 description: "List of properties to delete.",
150 type: Array,
151 optional: true,
152 items: {
153 type: DeletableProperty,
154 }
155 },
156 digest: {
157 optional: true,
158 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
159 },
160 },
161 },
396fd747
DM
162 access: {
163 permission: &Permission::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_MODIFY, false),
164 },
be327dbc
DM
165)]
166/// Update the tape backup job
167pub fn update_tape_backup_job(
0b90c67f 168 id: String,
cdc83c4e 169 update: TapeBackupJobConfigUpdater,
0b90c67f 170 delete: Option<Vec<DeletableProperty>>,
be327dbc
DM
171 digest: Option<String>,
172) -> Result<(), Error> {
e3619d41 173 let _lock = pbs_config::tape_job::lock()?;
be327dbc 174
e3619d41 175 let (mut config, expected_digest) = pbs_config::tape_job::config()?;
be327dbc 176
0b90c67f 177 let mut data: TapeBackupJobConfig = config.lookup("backup", &id)?;
be327dbc
DM
178
179 if let Some(ref digest) = digest {
180 let digest = proxmox::tools::hex_to_digest(digest)?;
181 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
182 }
183
0b90c67f
DM
184 if let Some(delete) = delete {
185 for delete_prop in delete {
186 match delete_prop {
187 DeletableProperty::EjectMedia => { data.setup.eject_media = None; },
188 DeletableProperty::ExportMediaSet => { data.setup.export_media_set = None; },
189 DeletableProperty::LatestOnly => { data.setup.latest_only = None; },
9152a007 190 DeletableProperty::NotifyUser => { data.setup.notify_user = None; },
0b90c67f
DM
191 DeletableProperty::Schedule => { data.schedule = None; },
192 DeletableProperty::Comment => { data.comment = None; },
193 }
194 }
195 }
be327dbc 196
cdc83c4e
DM
197 if let Some(store) = update.setup.store { data.setup.store = store; }
198 if let Some(pool) = update.setup.pool { data.setup.pool = pool; }
199 if let Some(drive) = update.setup.drive { data.setup.drive = drive; }
0b90c67f 200
cdc83c4e
DM
201 if update.setup.eject_media.is_some() { data.setup.eject_media = update.setup.eject_media; };
202 if update.setup.export_media_set.is_some() { data.setup.export_media_set = update.setup.export_media_set; }
203 if update.setup.latest_only.is_some() { data.setup.latest_only = update.setup.latest_only; }
204 if update.setup.notify_user.is_some() { data.setup.notify_user = update.setup.notify_user; }
0b90c67f 205
cdc83c4e
DM
206 let schedule_changed = data.schedule != update.schedule;
207 if update.schedule.is_some() { data.schedule = update.schedule; }
0b90c67f 208
cdc83c4e 209 if let Some(comment) = update.comment {
0b90c67f
DM
210 let comment = comment.trim();
211 if comment.is_empty() {
212 data.comment = None;
213 } else {
214 data.comment = Some(comment.to_string());
215 }
216 }
217
218 config.set_data(&id, "backup", &data)?;
be327dbc 219
e3619d41 220 pbs_config::tape_job::save_config(&config)?;
be327dbc 221
951fe0cb 222 if schedule_changed {
37a634f5 223 crate::server::jobstate::update_job_last_run_time("tape-backup-job", &id)?;
951fe0cb
DC
224 }
225
be327dbc
DM
226 Ok(())
227}
228
229#[api(
230 protected: true,
231 input: {
232 properties: {
233 id: {
234 schema: JOB_ID_SCHEMA,
235 },
236 digest: {
237 optional: true,
238 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
239 },
240 },
241 },
396fd747
DM
242 access: {
243 permission: &Permission::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_MODIFY, false),
244 },
be327dbc
DM
245)]
246/// Remove a tape backup job configuration
247pub fn delete_tape_backup_job(
248 id: String,
249 digest: Option<String>,
250 _rpcenv: &mut dyn RpcEnvironment,
251) -> Result<(), Error> {
e3619d41 252 let _lock = pbs_config::tape_job::lock()?;
be327dbc 253
e3619d41 254 let (mut config, expected_digest) = pbs_config::tape_job::config()?;
be327dbc
DM
255
256 if let Some(ref digest) = digest {
257 let digest = proxmox::tools::hex_to_digest(digest)?;
258 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
259 }
260
261 match config.lookup::<TapeBackupJobConfig>("backup", &id) {
262 Ok(_job) => {
263 config.sections.remove(&id);
264 },
265 Err(_) => { bail!("job '{}' does not exist.", id) },
266 };
267
e3619d41 268 pbs_config::tape_job::save_config(&config)?;
be327dbc 269
8513626b
DM
270 crate::server::jobstate::remove_state_file("tape-backup-job", &id)?;
271
be327dbc
DM
272 Ok(())
273}
274
275const ITEM_ROUTER: Router = Router::new()
276 .get(&API_METHOD_READ_TAPE_BACKUP_JOB)
4961404c 277 .put(&API_METHOD_UPDATE_TAPE_BACKUP_JOB)
be327dbc
DM
278 .delete(&API_METHOD_DELETE_TAPE_BACKUP_JOB);
279
280pub const ROUTER: Router = Router::new()
281 .get(&API_METHOD_LIST_TAPE_BACKUP_JOBS)
282 .post(&API_METHOD_CREATE_TAPE_BACKUP_JOB)
283 .match_all("id", &ITEM_ROUTER);