1 use anyhow
::{bail, Error}
;
3 use ::serde
::{Deserialize, Serialize}
;
5 use proxmox
::api
::{api, Router, RpcEnvironment, Permission}
;
8 Authid
, TapeBackupJobConfig
, TapeBackupJobConfigUpdater
,
9 JOB_ID_SCHEMA
, PROXMOX_CONFIG_DIGEST_SCHEMA
,
10 PRIV_TAPE_AUDIT
, PRIV_TAPE_MODIFY
,
13 use crate::config
::cached_user_info
::CachedUserInfo
;
20 description
: "List configured jobs.",
22 items
: { type: TapeBackupJobConfig }
,
25 description
: "List configured tape jobs filtered by Tape.Audit privileges",
26 permission
: &Permission
::Anybody
,
29 /// List all tape backup jobs
30 pub fn list_tape_backup_jobs(
32 mut rpcenv
: &mut dyn RpcEnvironment
,
33 ) -> Result
<Vec
<TapeBackupJobConfig
>, Error
> {
34 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
35 let user_info
= CachedUserInfo
::new()?
;
37 let (config
, digest
) = pbs_config
::tape_job
::config()?
;
39 let list
= config
.convert_to_typed_array
::<TapeBackupJobConfig
>("backup")?
;
44 let privs
= user_info
.lookup_privs(&auth_id
, &["tape", "job", &job
.id
]);
45 privs
& PRIV_TAPE_AUDIT
!= 0
49 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
59 type: TapeBackupJobConfig
,
65 permission
: &Permission
::Privilege(&["tape", "job"], PRIV_TAPE_MODIFY
, false),
68 /// Create a new tape backup job.
69 pub fn create_tape_backup_job(
70 job
: TapeBackupJobConfig
,
71 _rpcenv
: &mut dyn RpcEnvironment
,
72 ) -> Result
<(), Error
> {
73 let _lock
= pbs_config
::tape_job
::lock()?
;
75 let (mut config
, _digest
) = pbs_config
::tape_job
::config()?
;
77 if config
.sections
.get(&job
.id
).is_some() {
78 bail
!("job '{}' already exists.", job
.id
);
81 config
.set_data(&job
.id
, "backup", &job
)?
;
83 pbs_config
::tape_job
::save_config(&config
)?
;
85 crate::server
::jobstate
::create_state_file("tape-backup-job", &job
.id
)?
;
94 schema
: JOB_ID_SCHEMA
,
98 returns
: { type: TapeBackupJobConfig }
,
100 permission
: &Permission
::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_AUDIT
, false),
103 /// Read a tape backup job configuration.
104 pub fn read_tape_backup_job(
106 mut rpcenv
: &mut dyn RpcEnvironment
,
107 ) -> Result
<TapeBackupJobConfig
, Error
> {
109 let (config
, digest
) = pbs_config
::tape_job
::config()?
;
111 let job
= config
.lookup("backup", &id
)?
;
113 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
119 #[derive(Serialize, Deserialize)]
120 #[serde(rename_all="kebab-case")]
121 /// Deletable property name
122 pub enum DeletableProperty
{
123 /// Delete the comment property.
125 /// Delete the job schedule.
127 /// Delete the eject-media property
129 /// Delete the export-media-set property
131 /// Delete the 'latest-only' property
133 /// Delete the 'notify-user' property
142 schema
: JOB_ID_SCHEMA
,
145 type: TapeBackupJobConfigUpdater
,
149 description
: "List of properties to delete.",
153 type: DeletableProperty
,
158 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
163 permission
: &Permission
::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_MODIFY
, false),
166 /// Update the tape backup job
167 pub fn update_tape_backup_job(
169 update
: TapeBackupJobConfigUpdater
,
170 delete
: Option
<Vec
<DeletableProperty
>>,
171 digest
: Option
<String
>,
172 ) -> Result
<(), Error
> {
173 let _lock
= pbs_config
::tape_job
::lock()?
;
175 let (mut config
, expected_digest
) = pbs_config
::tape_job
::config()?
;
177 let mut data
: TapeBackupJobConfig
= config
.lookup("backup", &id
)?
;
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
)?
;
184 if let Some(delete
) = delete
{
185 for delete_prop
in delete
{
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; }
,
190 DeletableProperty
::NotifyUser
=> { data.setup.notify_user = None; }
,
191 DeletableProperty
::Schedule
=> { data.schedule = None; }
,
192 DeletableProperty
::Comment
=> { data.comment = None; }
,
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; }
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; }
206 let schedule_changed
= data
.schedule
!= update
.schedule
;
207 if update
.schedule
.is_some() { data.schedule = update.schedule; }
209 if let Some(comment
) = update
.comment
{
210 let comment
= comment
.trim();
211 if comment
.is_empty() {
214 data
.comment
= Some(comment
.to_string());
218 config
.set_data(&id
, "backup", &data
)?
;
220 pbs_config
::tape_job
::save_config(&config
)?
;
222 if schedule_changed
{
223 crate::server
::jobstate
::update_job_last_run_time("tape-backup-job", &id
)?
;
234 schema
: JOB_ID_SCHEMA
,
238 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
243 permission
: &Permission
::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_MODIFY
, false),
246 /// Remove a tape backup job configuration
247 pub fn delete_tape_backup_job(
249 digest
: Option
<String
>,
250 _rpcenv
: &mut dyn RpcEnvironment
,
251 ) -> Result
<(), Error
> {
252 let _lock
= pbs_config
::tape_job
::lock()?
;
254 let (mut config
, expected_digest
) = pbs_config
::tape_job
::config()?
;
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
)?
;
261 match config
.lookup
::<TapeBackupJobConfig
>("backup", &id
) {
263 config
.sections
.remove(&id
);
265 Err(_
) => { bail!("job '{}' does not exist
.", id) },
268 pbs_config::tape_job::save_config(&config)?;
270 crate::server::jobstate::remove_state_file("tape
-backup
-job
", &id)?;
275 const ITEM_ROUTER: Router = Router::new()
276 .get(&API_METHOD_READ_TAPE_BACKUP_JOB)
277 .put(&API_METHOD_UPDATE_TAPE_BACKUP_JOB)
278 .delete(&API_METHOD_DELETE_TAPE_BACKUP_JOB);
280 pub 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);