From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 2/5] api: datastore admin: add 'snapshot-information' api call
Date: Tue, 28 Nov 2023 10:43:59 +0100 [thread overview]
Message-ID: <20231128094402.38115-3-d.csapak@proxmox.com> (raw)
In-Reply-To: <20231128094402.38115-1-d.csapak@proxmox.com>
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@proxmox.com>
---
not sure about the naming honestly...
pbs-api-types/src/datastore.rs | 20 ++++++
src/api2/admin/datastore.rs | 117 +++++++++++++++++++++++++++++++--
2 files changed, 131 insertions(+), 6 deletions(-)
diff --git a/pbs-api-types/src/datastore.rs b/pbs-api-types/src/datastore.rs
index 14dc1cc1..54251897 100644
--- a/pbs-api-types/src/datastore.rs
+++ b/pbs-api-types/src/datastore.rs
@@ -421,6 +421,26 @@ pub struct SnapshotVerifyState {
pub state: VerifyState,
}
+#[api(
+ properties: {
+ info : {
+ type: SnapshotListItem,
+ },
+ },
+)]
+#[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 a backup group
+ pub group_notes: 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..759dca81 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_notes = file_read_optional_string(note_path)?;
+
+ Ok(SnapshotInformation {
+ info,
+ upload_statistics,
+ group_notes,
+ })
+}
+
#[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.39.2
next prev parent reply other threads:[~2023-11-28 9:44 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-28 9:43 [pbs-devel] [PATCH proxmox-backup 0/5] add context menu to datastore content Dominik Csapak
2023-11-28 9:43 ` [pbs-devel] [PATCH proxmox-backup 1/5] api-types: add an UploadStatistic api type Dominik Csapak
2023-11-28 9:43 ` Dominik Csapak [this message]
2023-11-28 9:44 ` [pbs-devel] [PATCH proxmox-backup 3/5] ui: datastore content: add context menu to groups and snapshots Dominik Csapak
2023-11-28 15:27 ` [pbs-devel] applied: " Thomas Lamprecht
2023-11-29 7:35 ` Dominik Csapak
2023-11-29 7:47 ` Thomas Lamprecht
2023-11-28 9:44 ` [pbs-devel] [PATCH proxmox-backup 4/5] ui: datastore content: add snapshot information to context menu Dominik Csapak
2023-11-28 9:44 ` [pbs-devel] [PATCH proxmox-backup 5/5] ui: datastore content: add 'more actions' menu to actions Dominik Csapak
2023-11-28 11:32 ` [pbs-devel] [PATCH proxmox-backup 0/5] add context menu to datastore content Fabian Grünbichler
2023-11-28 12:48 ` Philipp Hufnagl
2023-11-28 13:41 ` Max Carrara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231128094402.38115-3-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.