snapshot: add helper function to retrieve verify_state

Add helper functions to retrieve the verify_state from the manifest of a
snapshot. Replaced all the manual "verify_state" parsing with the helper
function.

Suggested-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
This commit is contained in:
Gabriel Goller 2024-11-22 13:16:14 +01:00 committed by Fabian Grünbichler
parent 3dc9d2de69
commit b5be65cf8a
5 changed files with 43 additions and 21 deletions

View File

@ -8,8 +8,8 @@ use anyhow::{bail, format_err, Error};
use proxmox_sys::fs::{lock_dir_noblock, replace_file, CreateOptions}; use proxmox_sys::fs::{lock_dir_noblock, replace_file, CreateOptions};
use pbs_api_types::{ use pbs_api_types::{
Authid, BackupGroupDeleteStats, BackupNamespace, BackupType, GroupFilter, BACKUP_DATE_REGEX, Authid, BackupGroupDeleteStats, BackupNamespace, BackupType, GroupFilter, VerifyState,
BACKUP_FILE_REGEX, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME, BACKUP_DATE_REGEX, BACKUP_FILE_REGEX, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME,
}; };
use pbs_config::{open_backup_lockfile, BackupLockGuard}; use pbs_config::{open_backup_lockfile, BackupLockGuard};
@ -553,6 +553,11 @@ impl BackupDir {
Ok(()) Ok(())
} }
/// Load the verify state from the manifest.
pub fn verify_state(&self) -> Result<Option<VerifyState>, anyhow::Error> {
Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state))
}
} }
impl AsRef<pbs_api_types::BackupNamespace> for BackupDir { impl AsRef<pbs_api_types::BackupNamespace> for BackupDir {

View File

@ -3,7 +3,7 @@ use anyhow::{bail, format_err, Error};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{json, Value}; 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; use pbs_tools::crypt_config::CryptConfig;
pub const MANIFEST_LOCK_NAME: &str = ".index.json.lck"; pub const MANIFEST_LOCK_NAME: &str = ".index.json.lck";
@ -224,6 +224,18 @@ impl BackupManifest {
let manifest: BackupManifest = serde_json::from_value(json)?; let manifest: BackupManifest = serde_json::from_value(json)?;
Ok(manifest) 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<Option<SnapshotVerifyState>, anyhow::Error> {
let verify = self.unprotected["verify_state"].clone();
if verify.is_null() {
return Ok(None);
}
Ok(Some(serde_json::from_value::<SnapshotVerifyState>(verify)?))
}
} }
impl TryFrom<super::DataBlob> for BackupManifest { impl TryFrom<super::DataBlob> for BackupManifest {

View File

@ -539,15 +539,13 @@ unsafe fn list_snapshots_blocking(
} }
}; };
let verification = manifest.unprotected["verify_state"].clone(); let verification: Option<SnapshotVerifyState> = match manifest.verify_state() {
let verification: Option<SnapshotVerifyState> = Ok(verify) => verify,
match serde_json::from_value(verification) { Err(err) => {
Ok(verify) => verify, eprintln!("error parsing verification state : '{}'", err);
Err(err) => { None
eprintln!("error parsing verification state : '{}'", err); }
None };
}
};
let size = Some(files.iter().map(|x| x.size.unwrap_or(0)).sum()); let size = Some(files.iter().map(|x| x.size.unwrap_or(0)).sum());

View File

@ -8,6 +8,7 @@ use hyper::http::request::Parts;
use hyper::{Body, Request, Response, StatusCode}; use hyper::{Body, Request, Response, StatusCode};
use serde::Deserialize; use serde::Deserialize;
use serde_json::{json, Value}; use serde_json::{json, Value};
use tracing::warn;
use proxmox_rest_server::{H2Service, WorkerTask}; use proxmox_rest_server::{H2Service, WorkerTask};
use proxmox_router::{http_err, list_subdirs_api_method}; 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); let info = backup_group.last_backup(true).unwrap_or(None);
if let Some(info) = info { if let Some(info) = info {
let (manifest, _) = info.backup_dir.load_manifest()?; let (manifest, _) = info.backup_dir.load_manifest()?;
let verify = manifest.unprotected["verify_state"].clone(); match manifest.verify_state() {
match serde_json::from_value::<SnapshotVerifyState>(verify) { Ok(Some(verify)) => match verify.state {
Ok(verify) => match verify.state {
VerifyState::Ok => Some(info), VerifyState::Ok => Some(info),
VerifyState::Failed => None, VerifyState::Failed => None,
}, },
Err(_) => { Ok(None) => {
// no verify state found, treat as valid // no verify state found, treat as valid
Some(info) Some(info)
},
Err(err) => {
warn!("error parsing the snapshot manifest: {err:#}");
Some(info)
} }
} }
} else { } else {

View File

@ -5,7 +5,7 @@ use std::time::Instant;
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use nix::dir::Dir; use nix::dir::Dir;
use tracing::{error, info}; use tracing::{error, info, warn};
use proxmox_sys::fs::lock_dir_noblock_shared; use proxmox_sys::fs::lock_dir_noblock_shared;
use proxmox_worker_task::WorkerTaskContext; use proxmox_worker_task::WorkerTaskContext;
@ -554,10 +554,13 @@ pub fn verify_filter(
return true; return true;
} }
let raw_verify_state = manifest.unprotected["verify_state"].clone(); match manifest.verify_state() {
match serde_json::from_value::<SnapshotVerifyState>(raw_verify_state) { Err(err) => {
Err(_) => true, // no last verification, always include warn!("error reading manifest: {err:#}");
Ok(last_verify) => { true
}
Ok(None) => true, // no last verification, always include
Ok(Some(last_verify)) => {
match outdated_after { match outdated_after {
None => false, // never re-verify if ignored and no max age None => false, // never re-verify if ignored and no max age
Some(max_age) => { Some(max_age) => {