1 use ::serde
::{Deserialize, Serialize}
;
6 use proxmox_router
::{http_bail, Permission, Router, RpcEnvironment}
;
7 use proxmox_schema
::{api, param_bail}
;
10 Authid
, TapeBackupJobConfig
, TapeBackupJobConfigUpdater
, JOB_ID_SCHEMA
, PRIV_TAPE_AUDIT
,
11 PRIV_TAPE_MODIFY
, PROXMOX_CONFIG_DIGEST_SCHEMA
,
14 use pbs_config
::CachedUserInfo
;
21 description
: "List configured jobs.",
23 items
: { type: TapeBackupJobConfig }
,
26 description
: "List configured tape jobs filtered by Tape.Audit privileges",
27 permission
: &Permission
::Anybody
,
30 /// List all tape backup jobs
31 pub fn list_tape_backup_jobs(
33 rpcenv
: &mut dyn RpcEnvironment
,
34 ) -> Result
<Vec
<TapeBackupJobConfig
>, Error
> {
35 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
36 let user_info
= CachedUserInfo
::new()?
;
38 let (config
, digest
) = pbs_config
::tape_job
::config()?
;
40 let list
= config
.convert_to_typed_array
::<TapeBackupJobConfig
>("backup")?
;
45 let privs
= user_info
.lookup_privs(&auth_id
, &["tape", "job", &job
.id
]);
46 privs
& PRIV_TAPE_AUDIT
!= 0
50 rpcenv
["digest"] = hex
::encode(&digest
).into();
60 type: TapeBackupJobConfig
,
66 permission
: &Permission
::Privilege(&["tape", "job"], PRIV_TAPE_MODIFY
, false),
69 /// Create a new tape backup job.
70 pub fn create_tape_backup_job(
71 job
: TapeBackupJobConfig
,
72 _rpcenv
: &mut dyn RpcEnvironment
,
73 ) -> Result
<(), Error
> {
74 let _lock
= pbs_config
::tape_job
::lock()?
;
76 let (mut config
, _digest
) = pbs_config
::tape_job
::config()?
;
78 if config
.sections
.get(&job
.id
).is_some() {
79 param_bail
!("id", "job '{}' already exists.", job
.id
);
82 config
.set_data(&job
.id
, "backup", &job
)?
;
84 pbs_config
::tape_job
::save_config(&config
)?
;
86 crate::server
::jobstate
::create_state_file("tape-backup-job", &job
.id
)?
;
95 schema
: JOB_ID_SCHEMA
,
99 returns
: { type: TapeBackupJobConfig }
,
101 permission
: &Permission
::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_AUDIT
, false),
104 /// Read a tape backup job configuration.
105 pub fn read_tape_backup_job(
107 rpcenv
: &mut dyn RpcEnvironment
,
108 ) -> Result
<TapeBackupJobConfig
, Error
> {
109 let (config
, digest
) = pbs_config
::tape_job
::config()?
;
111 let job
= config
.lookup("backup", &id
)?
;
113 rpcenv
["digest"] = hex
::encode(&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
135 /// Delete the 'group_filter' property
144 schema
: JOB_ID_SCHEMA
,
147 type: TapeBackupJobConfigUpdater
,
151 description
: "List of properties to delete.",
155 type: DeletableProperty
,
160 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
165 permission
: &Permission
::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_MODIFY
, false),
168 /// Update the tape backup job
169 pub fn update_tape_backup_job(
171 update
: TapeBackupJobConfigUpdater
,
172 delete
: Option
<Vec
<DeletableProperty
>>,
173 digest
: Option
<String
>,
174 ) -> Result
<(), Error
> {
175 let _lock
= pbs_config
::tape_job
::lock()?
;
177 let (mut config
, expected_digest
) = pbs_config
::tape_job
::config()?
;
179 let mut data
: TapeBackupJobConfig
= config
.lookup("backup", &id
)?
;
181 if let Some(ref digest
) = digest
{
182 let digest
= <[u8; 32]>::from_hex(digest
)?
;
183 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
186 if let Some(delete
) = delete
{
187 for delete_prop
in delete
{
189 DeletableProperty
::EjectMedia
=> {
190 data
.setup
.eject_media
= None
;
192 DeletableProperty
::ExportMediaSet
=> {
193 data
.setup
.export_media_set
= None
;
195 DeletableProperty
::LatestOnly
=> {
196 data
.setup
.latest_only
= None
;
198 DeletableProperty
::NotifyUser
=> {
199 data
.setup
.notify_user
= None
;
201 DeletableProperty
::Schedule
=> {
202 data
.schedule
= None
;
204 DeletableProperty
::Comment
=> {
207 DeletableProperty
::GroupFilter
=> {
208 data
.setup
.group_filter
= None
;
214 if let Some(store
) = update
.setup
.store
{
215 data
.setup
.store
= store
;
217 if let Some(pool
) = update
.setup
.pool
{
218 data
.setup
.pool
= pool
;
220 if let Some(drive
) = update
.setup
.drive
{
221 data
.setup
.drive
= drive
;
224 if update
.setup
.eject_media
.is_some() {
225 data
.setup
.eject_media
= update
.setup
.eject_media
;
227 if update
.setup
.export_media_set
.is_some() {
228 data
.setup
.export_media_set
= update
.setup
.export_media_set
;
230 if update
.setup
.latest_only
.is_some() {
231 data
.setup
.latest_only
= update
.setup
.latest_only
;
233 if update
.setup
.notify_user
.is_some() {
234 data
.setup
.notify_user
= update
.setup
.notify_user
;
236 if update
.setup
.group_filter
.is_some() {
237 data
.setup
.group_filter
= update
.setup
.group_filter
;
240 let schedule_changed
= data
.schedule
!= update
.schedule
;
241 if update
.schedule
.is_some() {
242 data
.schedule
= update
.schedule
;
245 if let Some(comment
) = update
.comment
{
246 let comment
= comment
.trim();
247 if comment
.is_empty() {
250 data
.comment
= Some(comment
.to_string());
254 config
.set_data(&id
, "backup", &data
)?
;
256 pbs_config
::tape_job
::save_config(&config
)?
;
258 if schedule_changed
{
259 crate::server
::jobstate
::update_job_last_run_time("tape-backup-job", &id
)?
;
270 schema
: JOB_ID_SCHEMA
,
274 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
279 permission
: &Permission
::Privilege(&["tape", "job", "{id}"], PRIV_TAPE_MODIFY
, false),
282 /// Remove a tape backup job configuration
283 pub fn delete_tape_backup_job(
285 digest
: Option
<String
>,
286 _rpcenv
: &mut dyn RpcEnvironment
,
287 ) -> Result
<(), Error
> {
288 let _lock
= pbs_config
::tape_job
::lock()?
;
290 let (mut config
, expected_digest
) = pbs_config
::tape_job
::config()?
;
292 if let Some(ref digest
) = digest
{
293 let digest
= <[u8; 32]>::from_hex(digest
)?
;
294 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
297 match config
.lookup
::<TapeBackupJobConfig
>("backup", &id
) {
299 config
.sections
.remove(&id
);
302 http_bail
!(NOT_FOUND
, "job '{}' does not exist.", id
)
306 pbs_config
::tape_job
::save_config(&config
)?
;
308 crate::server
::jobstate
::remove_state_file("tape-backup-job", &id
)?
;
313 const ITEM_ROUTER
: Router
= Router
::new()
314 .get(&API_METHOD_READ_TAPE_BACKUP_JOB
)
315 .put(&API_METHOD_UPDATE_TAPE_BACKUP_JOB
)
316 .delete(&API_METHOD_DELETE_TAPE_BACKUP_JOB
);
318 pub const ROUTER
: Router
= Router
::new()
319 .get(&API_METHOD_LIST_TAPE_BACKUP_JOBS
)
320 .post(&API_METHOD_CREATE_TAPE_BACKUP_JOB
)
321 .match_all("id", &ITEM_ROUTER
);