[pbs-devel] [PATCH proxmox-backup v2 2/4] api: datastore admin: add 'snapshot-information' api call
Dominik Csapak
d.csapak at proxmox.com
Tue Dec 5 11:53:43 CET 2023
get information about a snapshot. This is intended to contain all
relevant information about a snapshot, so that we don't fill the
'list_snapshots' api call with further info
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
pbs-api-types/src/datastore.rs | 24 +++++++
src/api2/admin/datastore.rs | 117 +++++++++++++++++++++++++++++++--
2 files changed, 135 insertions(+), 6 deletions(-)
diff --git a/pbs-api-types/src/datastore.rs b/pbs-api-types/src/datastore.rs
index 52f83f48..76d1811f 100644
--- a/pbs-api-types/src/datastore.rs
+++ b/pbs-api-types/src/datastore.rs
@@ -421,6 +421,30 @@ pub struct SnapshotVerifyState {
pub state: VerifyState,
}
+#[api(
+ properties: {
+ info : {
+ type: SnapshotListItem,
+ },
+ "upload-statistics": {
+ type: UploadStatistic,
+ optional: true,
+ },
+ },
+)]
+#[derive(Serialize, Deserialize, Clone, PartialEq)]
+#[serde(rename_all = "kebab-case")]
+/// Information about a Snapshot
+pub struct SnapshotInformation {
+ #[serde(flatten)]
+ pub info: SnapshotListItem,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub upload_statistics: Option<UploadStatistic>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ /// "notes" for the whole backup group
+ pub group_comment: Option<String>,
+}
+
#[api()]
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index a95031e7..f6fcb8ff 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -34,12 +34,12 @@ use pxar::EntryKind;
use pbs_api_types::{
print_ns_and_snapshot, print_store_and_ns, Authid, BackupContent, BackupNamespace, BackupType,
Counts, CryptMode, DataStoreListItem, DataStoreStatus, GarbageCollectionStatus, GroupListItem,
- KeepOptions, Operation, PruneJobOptions, RRDMode, RRDTimeFrame, SnapshotListItem,
- SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA,
- BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA,
- MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
- PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY,
- UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA,
+ KeepOptions, Operation, PruneJobOptions, RRDMode, RRDTimeFrame, SnapshotInformation,
+ SnapshotListItem, SnapshotVerifyState, UploadStatistic, BACKUP_ARCHIVE_NAME_SCHEMA,
+ BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA,
+ DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA, MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA,
+ PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE,
+ PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA,
};
use pbs_client::pxar::{create_tar, create_zip};
use pbs_config::CachedUserInfo;
@@ -2239,6 +2239,107 @@ pub async fn set_backup_owner(
.await?
}
+#[api(
+ input: {
+ properties: {
+ store: { schema: DATASTORE_SCHEMA },
+ ns: {
+ type: BackupNamespace,
+ optional: true,
+ },
+ backup_dir: {
+ type: pbs_api_types::BackupDir,
+ flatten: true,
+ },
+ },
+ },
+ access: {
+ permission: &Permission::Anybody,
+ description: "Requires on /datastore/{store}[/{namespace}] either DATASTORE_AUDIT for any \
+ or DATASTORE_BACKUP and being the owner of the group",
+ },
+)]
+/// Get Information about a snapshot
+pub fn get_snapshot_info(
+ store: String,
+ ns: Option<BackupNamespace>,
+ backup_dir: pbs_api_types::BackupDir,
+ rpcenv: &mut dyn RpcEnvironment,
+) -> Result<SnapshotInformation, Error> {
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+ let ns = ns.unwrap_or_default();
+
+ let datastore = check_privs_and_load_store(
+ &store,
+ &ns,
+ &auth_id,
+ PRIV_DATASTORE_AUDIT,
+ PRIV_DATASTORE_BACKUP,
+ Some(Operation::Read),
+ &backup_dir.group,
+ )?;
+
+ let group = datastore.backup_group(ns.clone(), backup_dir.group.clone());
+ let owner = group.get_owner()?;
+ let backup = datastore.backup_dir(ns.clone(), backup_dir.clone())?;
+
+ let protected = backup.is_protected();
+ let backup_info = BackupInfo::new(backup)?;
+
+ let (manifest, files) = get_all_snapshot_files(&backup_info)?;
+ let comment: Option<String> = manifest.unprotected["notes"].as_str().map(String::from);
+
+ let fingerprint = match manifest.fingerprint() {
+ Ok(fp) => fp,
+ Err(err) => {
+ eprintln!("error parsing fingerprint: '{}'", err);
+ None
+ }
+ };
+
+ let verification = manifest.unprotected["verify_state"].clone();
+ let verification: Option<SnapshotVerifyState> = match serde_json::from_value(verification) {
+ 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());
+
+ let group = backup_dir.group.clone();
+
+ let info = SnapshotListItem {
+ backup: backup_dir,
+ comment,
+ verification,
+ fingerprint,
+ files,
+ size,
+ owner: Some(owner),
+ protected,
+ };
+
+ let upload_statistics =
+ match Option::<UploadStatistic>::deserialize(&manifest.unprotected["chunk_upload_stats"]) {
+ Ok(stats) => stats,
+ Err(err) => {
+ log::warn!("error parsing chunk_upload_stats: {err}");
+ None
+ }
+ };
+
+ let note_path = get_group_note_path(&datastore, &ns, &group);
+ let group_comment = file_read_optional_string(note_path)?;
+
+ Ok(SnapshotInformation {
+ info,
+ upload_statistics,
+ group_comment,
+ })
+}
+
#[sortable]
const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
(
@@ -2304,6 +2405,10 @@ const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
&Router::new().download(&API_METHOD_PXAR_FILE_DOWNLOAD),
),
("rrd", &Router::new().get(&API_METHOD_GET_RRD_STATS)),
+ (
+ "snapshot-information",
+ &Router::new().get(&API_METHOD_GET_SNAPSHOT_INFO),
+ ),
(
"snapshots",
&Router::new()
--
2.30.2
More information about the pbs-devel
mailing list