From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id EEF3DB86BC for ; Tue, 5 Dec 2023 11:53:47 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id C1340192DC for ; Tue, 5 Dec 2023 11:53:47 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 5 Dec 2023 11:53:47 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id B6DD544C0B for ; Tue, 5 Dec 2023 11:53:46 +0100 (CET) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Tue, 5 Dec 2023 11:53:43 +0100 Message-Id: <20231205105345.1656325-3-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231205105345.1656325-1-d.csapak@proxmox.com> References: <20231205105345.1656325-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.132 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record T_SCC_BODY_TEXT_LINE -0.01 - URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [datastore.rs] Subject: [pbs-devel] [PATCH proxmox-backup v2 2/4] api: datastore admin: add 'snapshot-information' api call X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Dec 2023 10:53:48 -0000 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 --- 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, + #[serde(skip_serializing_if = "Option::is_none")] + /// "notes" for the whole backup group + pub group_comment: Option, +} + #[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, + backup_dir: pbs_api_types::BackupDir, + rpcenv: &mut dyn RpcEnvironment, +) -> Result { + 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 = 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 = 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::::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