diff --git a/src/api2/tape/backup.rs b/src/api2/tape/backup.rs index 522b4097..f10a71e3 100644 --- a/src/api2/tape/backup.rs +++ b/src/api2/tape/backup.rs @@ -1,7 +1,7 @@ use std::path::Path; use std::sync::Arc; -use anyhow::{bail, Error}; +use anyhow::{bail, format_err, Error}; use serde_json::Value; use proxmox::{ @@ -17,9 +17,18 @@ use crate::{ task_log, config::{ self, - tape_job::TapeBackupJobConfig, + tape_job::{ + TapeBackupJobConfig, + TapeBackupJobStatus, + }, + }, + server::{ + jobstate::{ + Job, + JobState, + compute_schedule_status, + }, }, - server::jobstate::Job, backup::{ DataStore, BackupDir, @@ -54,9 +63,49 @@ const TAPE_BACKUP_JOB_ROUTER: Router = Router::new() .post(&API_METHOD_RUN_TAPE_BACKUP_JOB); pub const ROUTER: Router = Router::new() + .get(&API_METHOD_LIST_TAPE_BACKUP_JOBS) .post(&API_METHOD_BACKUP) .match_all("id", &TAPE_BACKUP_JOB_ROUTER); +#[api( + returns: { + description: "List configured thape backup jobs and their status", + type: Array, + items: { type: TapeBackupJobStatus }, + }, +)] +/// List all tape backup jobs +pub fn list_tape_backup_jobs( + _param: Value, + mut rpcenv: &mut dyn RpcEnvironment, +) -> Result, Error> { + + let (config, digest) = config::tape_job::config()?; + + let job_list_iter = config + .convert_to_typed_array("backup")? + .into_iter() + .filter(|_job: &TapeBackupJobConfig| { + // fixme: check access permission + true + }); + + let mut list = Vec::new(); + + for job in job_list_iter { + let last_state = JobState::load("tape-backup-job", &job.id) + .map_err(|err| format_err!("could not open statefile for {}: {}", &job.id, err))?; + + let status = compute_schedule_status(&last_state, job.schedule.as_deref())?; + + list.push(TapeBackupJobStatus { config: job, status }); + } + + rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); + + Ok(list) +} + pub fn do_tape_backup_job( mut job: Job, tape_job: TapeBackupJobConfig, diff --git a/src/config/tape_job.rs b/src/config/tape_job.rs index 970fb7fb..913eaa06 100644 --- a/src/config/tape_job.rs +++ b/src/config/tape_job.rs @@ -22,6 +22,7 @@ use crate::api2::types::{ MEDIA_POOL_NAME_SCHEMA, SINGLE_LINE_COMMENT_SCHEMA, SYNC_SCHEDULE_SCHEMA, + JobScheduleStatus, }; lazy_static! { @@ -81,6 +82,26 @@ pub struct TapeBackupJobConfig { pub schedule: Option, } +#[api( + properties: { + config: { + type: TapeBackupJobConfig, + }, + status: { + type: JobScheduleStatus, + }, + }, +)] +#[serde(rename_all="kebab-case")] +#[derive(Serialize,Deserialize)] +/// Status of Tape Backup Job +pub struct TapeBackupJobStatus { + #[serde(flatten)] + pub config: TapeBackupJobConfig, + #[serde(flatten)] + pub status: JobScheduleStatus, +} + fn init() -> SectionConfig { let obj_schema = match TapeBackupJobConfig::API_SCHEMA { Schema::Object(ref obj_schema) => obj_schema,