diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs index 4c17692d..be262773 100644 --- a/pbs-datastore/src/backup_info.rs +++ b/pbs-datastore/src/backup_info.rs @@ -8,8 +8,8 @@ use anyhow::{bail, format_err, Error}; use proxmox_sys::fs::{lock_dir_noblock, replace_file, CreateOptions}; use pbs_api_types::{ - Authid, BackupGroupDeleteStats, BackupNamespace, BackupType, GroupFilter, BACKUP_DATE_REGEX, - BACKUP_FILE_REGEX, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME, + Authid, BackupGroupDeleteStats, BackupNamespace, BackupType, GroupFilter, VerifyState, + BACKUP_DATE_REGEX, BACKUP_FILE_REGEX, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME, }; use pbs_config::{open_backup_lockfile, BackupLockGuard}; @@ -553,6 +553,11 @@ impl BackupDir { Ok(()) } + + /// Load the verify state from the manifest. + pub fn verify_state(&self) -> Result, anyhow::Error> { + Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state)) + } } impl AsRef for BackupDir { diff --git a/pbs-datastore/src/manifest.rs b/pbs-datastore/src/manifest.rs index 51ec117e..fb734a67 100644 --- a/pbs-datastore/src/manifest.rs +++ b/pbs-datastore/src/manifest.rs @@ -3,7 +3,7 @@ use anyhow::{bail, format_err, Error}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -use pbs_api_types::{BackupArchiveName, BackupType, CryptMode, Fingerprint}; +use pbs_api_types::{BackupArchiveName, BackupType, CryptMode, Fingerprint, SnapshotVerifyState}; use pbs_tools::crypt_config::CryptConfig; pub const MANIFEST_LOCK_NAME: &str = ".index.json.lck"; @@ -224,6 +224,18 @@ impl BackupManifest { let manifest: BackupManifest = serde_json::from_value(json)?; Ok(manifest) } + + /// Get the verify state of the snapshot + /// + /// Note: New snapshots, which have not been verified yet, do not have a status and this + /// function will return `Ok(None)`. + pub fn verify_state(&self) -> Result, anyhow::Error> { + let verify = self.unprotected["verify_state"].clone(); + if verify.is_null() { + return Ok(None); + } + Ok(Some(serde_json::from_value::(verify)?)) + } } impl TryFrom for BackupManifest { diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 3b863c06..9fdda8b7 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -539,15 +539,13 @@ unsafe fn list_snapshots_blocking( } }; - let verification = manifest.unprotected["verify_state"].clone(); - let verification: Option = - match serde_json::from_value(verification) { - Ok(verify) => verify, - Err(err) => { - eprintln!("error parsing verification state : '{}'", err); - None - } - }; + let verification: Option = match manifest.verify_state() { + Ok(verify) => verify, + Err(err) => { + eprintln!("error parsing verification state : '{}'", err); + None + } + }; let size = Some(files.iter().map(|x| x.size.unwrap_or(0)).sum()); diff --git a/src/api2/backup/mod.rs b/src/api2/backup/mod.rs index fbbe76bd..31334b59 100644 --- a/src/api2/backup/mod.rs +++ b/src/api2/backup/mod.rs @@ -8,6 +8,7 @@ use hyper::http::request::Parts; use hyper::{Body, Request, Response, StatusCode}; use serde::Deserialize; use serde_json::{json, Value}; +use tracing::warn; use proxmox_rest_server::{H2Service, WorkerTask}; use proxmox_router::{http_err, list_subdirs_api_method}; @@ -158,15 +159,18 @@ fn upgrade_to_backup_protocol( let info = backup_group.last_backup(true).unwrap_or(None); if let Some(info) = info { let (manifest, _) = info.backup_dir.load_manifest()?; - let verify = manifest.unprotected["verify_state"].clone(); - match serde_json::from_value::(verify) { - Ok(verify) => match verify.state { + match manifest.verify_state() { + Ok(Some(verify)) => match verify.state { VerifyState::Ok => Some(info), VerifyState::Failed => None, }, - Err(_) => { + Ok(None) => { // no verify state found, treat as valid Some(info) + }, + Err(err) => { + warn!("error parsing the snapshot manifest: {err:#}"); + Some(info) } } } else { diff --git a/src/backup/verify.rs b/src/backup/verify.rs index fee6ecf5..840a3785 100644 --- a/src/backup/verify.rs +++ b/src/backup/verify.rs @@ -5,7 +5,7 @@ use std::time::Instant; use anyhow::{bail, format_err, Error}; use nix::dir::Dir; -use tracing::{error, info}; +use tracing::{error, info, warn}; use proxmox_sys::fs::lock_dir_noblock_shared; use proxmox_worker_task::WorkerTaskContext; @@ -554,10 +554,13 @@ pub fn verify_filter( return true; } - let raw_verify_state = manifest.unprotected["verify_state"].clone(); - match serde_json::from_value::(raw_verify_state) { - Err(_) => true, // no last verification, always include - Ok(last_verify) => { + match manifest.verify_state() { + Err(err) => { + warn!("error reading manifest: {err:#}"); + true + } + Ok(None) => true, // no last verification, always include + Ok(Some(last_verify)) => { match outdated_after { None => false, // never re-verify if ignored and no max age Some(max_age) => {