diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index e6a29522..156ebf83 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -361,7 +361,7 @@ pub fn list_snapshots ( let mut size = None; - let (comment, files) = match get_all_snapshot_files(&datastore, &info) { + let (comment, verification, files) = match get_all_snapshot_files(&datastore, &info) { Ok((manifest, files)) => { size = Some(files.iter().map(|x| x.size.unwrap_or(0)).sum()); // extract the first line from notes @@ -370,11 +370,21 @@ pub fn list_snapshots ( .and_then(|notes| notes.lines().next()) .map(String::from); - (comment, files) + let verify = manifest.unprotected["verify_state"].clone(); + let verify: Option = match serde_json::from_value(verify) { + Ok(verify) => verify, + Err(err) => { + eprintln!("error parsing verification state : '{}'", err); + None + } + }; + + (comment, verify, files) }, Err(err) => { eprintln!("error during snapshot file listing: '{}'", err); ( + None, None, info .files @@ -394,6 +404,7 @@ pub fn list_snapshots ( backup_id: group.backup_id().to_string(), backup_time: info.backup_dir.backup_time().timestamp(), comment, + verification, files, size, owner: Some(owner), diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs index d3f20020..6854fdf0 100644 --- a/src/api2/types/mod.rs +++ b/src/api2/types/mod.rs @@ -6,6 +6,7 @@ use proxmox::const_regex; use proxmox::{IPRE, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32}; use crate::backup::CryptMode; +use crate::server::UPID; #[macro_use] mod macros; @@ -379,6 +380,25 @@ pub struct GroupListItem { pub owner: Option, } +#[api( + properties: { + upid: { + schema: UPID_SCHEMA + }, + state: { + type: String + }, + }, +)] +#[derive(Serialize, Deserialize)] +/// Task properties. +pub struct SnapshotVerifyState { + /// UPID of the verify task + pub upid: UPID, + /// State of the verification. "failed" or "ok" + pub state: String, +} + #[api( properties: { "backup-type": { @@ -394,6 +414,10 @@ pub struct GroupListItem { schema: SINGLE_LINE_COMMENT_SCHEMA, optional: true, }, + verification: { + type: SnapshotVerifyState, + optional: true, + }, files: { items: { schema: BACKUP_ARCHIVE_NAME_SCHEMA @@ -415,6 +439,9 @@ pub struct SnapshotListItem { /// The first line from manifest "notes" #[serde(skip_serializing_if="Option::is_none")] pub comment: Option, + /// The result of the last run verify task + #[serde(skip_serializing_if="Option::is_none")] + pub verification: Option, /// List of contained archive files. pub files: Vec, /// Overall snapshot size (sum of all archive sizes). diff --git a/src/backup/verify.rs b/src/backup/verify.rs index f9437ff0..dc8be22c 100644 --- a/src/backup/verify.rs +++ b/src/backup/verify.rs @@ -1,8 +1,9 @@ use std::collections::HashSet; -use anyhow::{bail, Error}; +use anyhow::{bail, format_err, Error}; use crate::server::WorkerTask; +use crate::api2::types::*; use super::{ DataStore, BackupGroup, BackupDir, BackupInfo, IndexFile, @@ -178,7 +179,7 @@ pub fn verify_backup_dir( worker: &WorkerTask ) -> Result { - let manifest = match datastore.load_manifest(&backup_dir) { + let mut manifest = match datastore.load_manifest(&backup_dir) { Ok((manifest, _)) => manifest, Err(err) => { worker.log(format!("verify {}:{} - manifest load error: {}", datastore.name(), backup_dir, err)); @@ -190,6 +191,7 @@ pub fn verify_backup_dir( let mut error_count = 0; + let mut verify_result = "ok"; for info in manifest.files() { let result = proxmox::try_block!({ worker.log(format!(" check {}", info.filename)); @@ -221,9 +223,20 @@ pub fn verify_backup_dir( if let Err(err) = result { worker.log(format!("verify {}:{}/{} failed: {}", datastore.name(), backup_dir, info.filename, err)); error_count += 1; + verify_result = "failed"; } + } + let verify_state = SnapshotVerifyState { + state: verify_result.to_string(), + upid: worker.upid().clone(), + }; + manifest.unprotected["verify_state"] = serde_json::to_value(verify_state)?; + datastore.store_manifest(&backup_dir, serde_json::to_value(manifest)?) + .map_err(|err| format_err!("unable to store manifest blob - {}", err))?; + + Ok(error_count == 0) }