From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 30DD31FF140 for ; Fri, 10 Apr 2026 17:43:50 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 1496E22190; Fri, 10 Apr 2026 17:44:35 +0200 (CEST) From: Thomas Lamprecht To: pbs-devel@lists.proxmox.com Subject: [PATCH v4 3/5] client: migrate commands to flattened repository args Date: Fri, 10 Apr 2026 16:09:04 +0200 Message-ID: <20260410154327.4133440-4-t.lamprecht@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260410154327.4133440-1-t.lamprecht@proxmox.com> References: <20260410154327.4133440-1-t.lamprecht@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1775835763746 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.002 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 SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: SZATWZ2JLYKJVIDDMSIRBBSAODDHLZ5D X-Message-ID-Hash: SZATWZ2JLYKJVIDDMSIRBBSAODDHLZ5D X-MailFrom: t.lamprecht@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Replace the individual repository and ns property definitions in all client command API schema macros with the flattened repository args struct. This makes --server, --port, --datastore, --auth-id, and --ns available on every command that previously only accepted --repository. Commands where the namespace has no semantic effect (login, logout, version, status, GC, benchmark, task) use BackupRepositoryArgs, which only exposes the connection parameters. All data-path commands use the full BackupTargetArgs that includes --ns. Also moves optional_ns_param() to pbs-client's tools module so that all three client binaries can share it instead of each carrying their own copy. Signed-off-by: Thomas Lamprecht --- changes v3 -> v4: - use BackupRepositoryArgs (no --ns) for login, logout, version, status, GC, benchmark, and task commands - use AllOfSchema for mount.rs raw ApiMethod definitions instead of manually listing all repository parameter schemas - moved optional_ns_param() to pbs-client tools as shared helper - fixed change_backup_owner: use remove_repository_from_value() to strip all repo fields before forwarding params to the server API. pbs-client/src/tools/mod.rs | 9 ++ proxmox-backup-client/src/benchmark.rs | 8 +- proxmox-backup-client/src/catalog.rs | 26 ++--- proxmox-backup-client/src/group.rs | 14 +-- proxmox-backup-client/src/main.rs | 104 ++++++++------------ proxmox-backup-client/src/mount.rs | 130 +++++++++++++------------ proxmox-backup-client/src/namespace.rs | 33 ++----- proxmox-backup-client/src/snapshot.rs | 84 +++++----------- proxmox-backup-client/src/task.rs | 20 ++-- proxmox-file-restore/src/main.rs | 30 ++---- src/bin/proxmox_backup_debug/diff.rs | 17 ++-- 11 files changed, 200 insertions(+), 275 deletions(-) diff --git a/pbs-client/src/tools/mod.rs b/pbs-client/src/tools/mod.rs index 436d9ddcd..fa708a8b5 100644 --- a/pbs-client/src/tools/mod.rs +++ b/pbs-client/src/tools/mod.rs @@ -339,6 +339,15 @@ pub fn extract_repository_from_map(param: &HashMap) -> Option Result { + Ok(match param.get("ns") { + Some(Value::String(ns)) => ns.parse()?, + Some(_) => bail!("invalid namespace parameter"), + None => BackupNamespace::root(), + }) +} + pub fn connect(repo: &BackupRepository) -> Result { let rate_limit = RateLimitConfig::default(); // unlimited connect_do(repo.host(), repo.port(), repo.auth_id(), rate_limit) diff --git a/proxmox-backup-client/src/benchmark.rs b/proxmox-backup-client/src/benchmark.rs index ad8c60ed9..c113e2ca2 100644 --- a/proxmox-backup-client/src/benchmark.rs +++ b/proxmox-backup-client/src/benchmark.rs @@ -22,7 +22,7 @@ use pbs_key_config::{load_and_decrypt_key, KeyDerivationConfig}; use pbs_tools::crypt_config::CryptConfig; use crate::{ - connect, extract_repository_from_value, record_repository, KEYFILE_SCHEMA, REPO_URL_SCHEMA, + connect, extract_repository_from_value, record_repository, BackupRepositoryArgs, KEYFILE_SCHEMA, }; #[api()] @@ -105,9 +105,9 @@ static BENCHMARK_RESULT_2020_TOP: BenchmarkResult = BenchmarkResult { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, keyfile: { schema: KEYFILE_SCHEMA, diff --git a/proxmox-backup-client/src/catalog.rs b/proxmox-backup-client/src/catalog.rs index b1b22ff24..5096378bb 100644 --- a/proxmox-backup-client/src/catalog.rs +++ b/proxmox-backup-client/src/catalog.rs @@ -7,7 +7,7 @@ use serde_json::Value; use proxmox_router::cli::*; use proxmox_schema::api; -use pbs_api_types::{BackupArchiveName, BackupNamespace, CATALOG_NAME}; +use pbs_api_types::{BackupArchiveName, CATALOG_NAME}; use pbs_client::pxar::tools::get_remote_pxar_reader; use pbs_client::tools::key_source::get_encryption_key_password; use pbs_client::{BackupReader, RemoteChunkReader}; @@ -20,20 +20,16 @@ use crate::{ complete_backup_snapshot, complete_group_or_snapshot, complete_namespace, complete_pxar_archive_name, complete_repository, connect, crypto_parameters, decrypt_key, dir_or_last_from_group, extract_repository_from_value, format_key_source, optional_ns_param, - record_repository, BackupDir, BufferedDynamicReader, CatalogReader, DynamicIndexReader, - IndexFile, Shell, KEYFD_SCHEMA, REPO_URL_SCHEMA, + record_repository, BackupDir, BackupTargetArgs, BufferedDynamicReader, CatalogReader, + DynamicIndexReader, IndexFile, Shell, KEYFD_SCHEMA, }; #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -159,10 +155,6 @@ async fn dump_catalog(param: Value) -> Result { #[api( input: { properties: { - ns: { - type: BackupNamespace, - optional: true, - }, "snapshot": { type: String, description: "Group/Snapshot path.", @@ -170,9 +162,9 @@ async fn dump_catalog(param: Value) -> Result { "archive-name": { type: BackupArchiveName, }, - "repository": { - optional: true, - schema: REPO_URL_SCHEMA, + repo: { + type: BackupTargetArgs, + flatten: true, }, "keyfile": { optional: true, diff --git a/proxmox-backup-client/src/group.rs b/proxmox-backup-client/src/group.rs index 2c12db2ee..42cb7ab7a 100644 --- a/proxmox-backup-client/src/group.rs +++ b/proxmox-backup-client/src/group.rs @@ -6,9 +6,9 @@ use proxmox_schema::api; use crate::{ complete_backup_group, complete_namespace, complete_repository, merge_group_into, - REPO_URL_SCHEMA, + BackupTargetArgs, }; -use pbs_api_types::{BackupGroup, BackupNamespace}; +use pbs_api_types::BackupGroup; use pbs_client::tools::{connect, remove_repository_from_value}; pub fn group_mgmt_cli() -> CliCommandMap { @@ -29,13 +29,9 @@ pub fn group_mgmt_cli() -> CliCommandMap { type: String, description: "Backup group", }, - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, } } diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs index 2ada87bdd..e8db3f814 100644 --- a/proxmox-backup-client/src/main.rs +++ b/proxmox-backup-client/src/main.rs @@ -27,8 +27,8 @@ use pbs_api_types::{ ArchiveType, Authid, BackupArchiveName, BackupDir, BackupGroup, BackupNamespace, BackupPart, BackupType, ClientRateLimitConfig, CryptMode, Fingerprint, GroupListItem, PathPattern, PruneJobOptions, PruneListItem, RateLimitConfig, SnapshotListItem, StorageStatus, - BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, - CATALOG_NAME, ENCRYPTED_KEY_BLOB_NAME, MANIFEST_BLOB_NAME, + BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, CATALOG_NAME, + ENCRYPTED_KEY_BLOB_NAME, MANIFEST_BLOB_NAME, }; use pbs_client::catalog_shell::Shell; use pbs_client::pxar::{ErrorHandler as PxarErrorHandler, MetadataArchiveReader, PxarPrevRef}; @@ -36,18 +36,19 @@ use pbs_client::tools::{ complete_archive_name, complete_auth_id, complete_backup_group, complete_backup_snapshot, complete_backup_source, complete_chunk_size, complete_group_or_snapshot, complete_img_archive_name, complete_namespace, complete_pxar_archive_name, complete_repository, - connect, connect_rate_limited, extract_repository_from_value, + connect, connect_rate_limited, extract_repository_from_value, remove_repository_from_value, key_source::{ crypto_parameters, format_key_source, get_encryption_key_password, KEYFD_SCHEMA, KEYFILE_SCHEMA, MASTER_PUBKEY_FD_SCHEMA, MASTER_PUBKEY_FILE_SCHEMA, }, - raise_nofile_limit, CHUNK_SIZE_SCHEMA, REPO_URL_SCHEMA, + raise_nofile_limit, CHUNK_SIZE_SCHEMA, }; use pbs_client::{ delete_ticket_info, parse_backup_specification, view_task_result, BackupDetectionMode, - BackupReader, BackupRepository, BackupSpecificationType, BackupStats, BackupWriter, - BackupWriterOptions, ChunkStream, FixedChunkStream, HttpClient, IndexType, InjectionData, - PxarBackupStream, RemoteChunkReader, UploadOptions, BACKUP_SOURCE_SCHEMA, + BackupReader, BackupRepository, BackupRepositoryArgs, BackupSpecificationType, BackupStats, + BackupTargetArgs, BackupWriter, BackupWriterOptions, ChunkStream, FixedChunkStream, HttpClient, + IndexType, InjectionData, PxarBackupStream, RemoteChunkReader, UploadOptions, + BACKUP_SOURCE_SCHEMA, }; use pbs_datastore::catalog::{BackupCatalogWriter, CatalogReader, CatalogWriter}; use pbs_datastore::chunk_store::verify_chunk_size; @@ -329,24 +330,15 @@ async fn backup_image>( Ok(stats) } -pub fn optional_ns_param(param: &Value) -> Result { - Ok(match param.get("ns") { - Some(Value::String(ns)) => ns.parse()?, - Some(_) => bail!("invalid namespace parameter"), - None => BackupNamespace::root(), - }) -} +// Re-export for use by submodules. +pub use pbs_client::tools::optional_ns_param; #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - "ns": { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, "output-format": { schema: OUTPUT_FORMAT, @@ -433,18 +425,14 @@ fn merge_group_into(to: &mut serde_json::Map, group: BackupGroup) #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, group: { type: String, description: "Backup group.", }, - "ns": { - type: BackupNamespace, - optional: true, - }, "new-owner": { type: Authid, }, @@ -453,13 +441,11 @@ fn merge_group_into(to: &mut serde_json::Map, group: BackupGroup) )] /// Change owner of a backup group async fn change_backup_owner(group: String, mut param: Value) -> Result<(), Error> { - let repo = extract_repository_from_value(¶m)?; + let repo = remove_repository_from_value(&mut param)?; let ns = optional_ns_param(¶m)?; let client = connect(&repo)?; - param.as_object_mut().unwrap().remove("repository"); - let group: BackupGroup = group.parse()?; merge_group_into(param.as_object_mut().unwrap(), group); @@ -478,9 +464,9 @@ async fn change_backup_owner(group: String, mut param: Value) -> Result<(), Erro #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, } } @@ -500,9 +486,9 @@ async fn api_login(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, } } @@ -519,9 +505,9 @@ fn api_logout(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, "output-format": { schema: OUTPUT_FORMAT, @@ -572,9 +558,9 @@ async fn api_version(param: Value) -> Result<(), Error> { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, "output-format": { schema: OUTPUT_FORMAT, @@ -662,9 +648,9 @@ fn spawn_catalog_upload( schema: BACKUP_SOURCE_SCHEMA, } }, - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, "include-dev": { description: @@ -708,10 +694,6 @@ fn spawn_catalog_upload( optional: true, default: false, }, - "ns": { - schema: BACKUP_NAMESPACE_SCHEMA, - optional: true, - }, "backup-type": { schema: BACKUP_TYPE_SCHEMA, optional: true, @@ -1439,13 +1421,9 @@ async fn dump_image( #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -1837,9 +1815,9 @@ async fn restore( default: false, description: "Minimal output - only show removals.", }, - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, }, }, @@ -1929,9 +1907,9 @@ async fn prune( #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, "output-format": { schema: OUTPUT_FORMAT, diff --git a/proxmox-backup-client/src/mount.rs b/proxmox-backup-client/src/mount.rs index e815c8a9c..0e6c09656 100644 --- a/proxmox-backup-client/src/mount.rs +++ b/proxmox-backup-client/src/mount.rs @@ -17,11 +17,11 @@ use proxmox_router::{cli::*, ApiHandler, ApiMethod, RpcEnvironment}; use proxmox_schema::*; use proxmox_sortable_macro::sortable; -use pbs_api_types::{ArchiveType, BackupArchiveName, BackupNamespace}; +use pbs_api_types::{ArchiveType, BackupArchiveName}; use pbs_client::tools::key_source::{ crypto_parameters, format_key_source, get_encryption_key_password, }; -use pbs_client::{BackupReader, RemoteChunkReader}; +use pbs_client::{BackupReader, BackupTargetArgs, RemoteChunkReader}; use pbs_datastore::cached_chunk_reader::CachedChunkReader; use pbs_datastore::index::IndexFile; use pbs_key_config::decrypt_key; @@ -32,73 +32,83 @@ use crate::helper; use crate::{ complete_group_or_snapshot, complete_img_archive_name, complete_namespace, complete_pxar_archive_name, complete_repository, connect, dir_or_last_from_group, - extract_repository_from_value, optional_ns_param, record_repository, REPO_URL_SCHEMA, + extract_repository_from_value, optional_ns_param, record_repository, }; #[sortable] -const API_METHOD_MOUNT: ApiMethod = ApiMethod::new( +const API_METHOD_MOUNT: ApiMethod = ApiMethod::new_full( &ApiHandler::Sync(&mount), - &ObjectSchema::new( + ParameterSchema::AllOf(&AllOfSchema::new( "Mount pxar archive.", - &sorted!([ - ("ns", true, &BackupNamespace::API_SCHEMA,), - ( - "snapshot", - false, - &StringSchema::new("Group/Snapshot path.").schema() - ), - ("archive-name", false, &BackupArchiveName::API_SCHEMA), - ( - "target", - false, - &StringSchema::new("Target directory path.").schema() - ), - ("repository", true, &REPO_URL_SCHEMA), - ( - "keyfile", - true, - &StringSchema::new("Path to encryption key.").schema() - ), - ( - "verbose", - true, - &BooleanSchema::new("Verbose output and stay in foreground.") - .default(false) - .schema() - ), - ]), - ), + &[ + &ObjectSchema::new( + "", + &sorted!([ + ( + "snapshot", + false, + &StringSchema::new("Group/Snapshot path.").schema() + ), + ("archive-name", false, &BackupArchiveName::API_SCHEMA), + ( + "target", + false, + &StringSchema::new("Target directory path.").schema() + ), + ( + "keyfile", + true, + &StringSchema::new("Path to encryption key.").schema() + ), + ( + "verbose", + true, + &BooleanSchema::new("Verbose output and stay in foreground.") + .default(false) + .schema() + ), + ]), + ) + .schema(), + &BackupTargetArgs::API_SCHEMA, + ], + )), ); #[sortable] -const API_METHOD_MAP: ApiMethod = ApiMethod::new( +const API_METHOD_MAP: ApiMethod = ApiMethod::new_full( &ApiHandler::Sync(&mount), - &ObjectSchema::new( - "Map a drive image from a VM backup to a local loopback device. Use 'unmap' to undo. -WARNING: Only do this with *trusted* backups!", - &sorted!([ - ("ns", true, &BackupNamespace::API_SCHEMA,), - ( - "snapshot", - false, - &StringSchema::new("Group/Snapshot path.").schema() - ), - ("archive-name", false, &BackupArchiveName::API_SCHEMA), - ("repository", true, &REPO_URL_SCHEMA), - ( - "keyfile", - true, - &StringSchema::new("Path to encryption key.").schema() - ), - ( - "verbose", - true, - &BooleanSchema::new("Verbose output and stay in foreground.") - .default(false) - .schema() - ), - ]), - ), + ParameterSchema::AllOf(&AllOfSchema::new( + "Map a drive image from a VM backup to a local loopback device. Use 'unmap' to undo.\n\ + WARNING: Only do this with *trusted* backups!", + &[ + &ObjectSchema::new( + "", + &sorted!([ + ( + "snapshot", + false, + &StringSchema::new("Group/Snapshot path.").schema() + ), + ("archive-name", false, &BackupArchiveName::API_SCHEMA), + ( + "keyfile", + true, + &StringSchema::new("Path to encryption key.").schema() + ), + ( + "verbose", + true, + &BooleanSchema::new("Verbose output and stay in foreground.") + .default(false) + .schema() + ), + ]), + ) + .schema(), + &BackupTargetArgs::API_SCHEMA, + ], + )), ); #[sortable] diff --git a/proxmox-backup-client/src/namespace.rs b/proxmox-backup-client/src/namespace.rs index 2929e394b..15ec085aa 100644 --- a/proxmox-backup-client/src/namespace.rs +++ b/proxmox-backup-client/src/namespace.rs @@ -1,8 +1,7 @@ use anyhow::{bail, Error}; use serde_json::{json, Value}; -use pbs_api_types::BackupNamespace; -use pbs_client::tools::REPO_URL_SCHEMA; +use pbs_client::BackupTargetArgs; use proxmox_router::cli::{ format_and_print_result, get_output_format, CliCommand, CliCommandMap, OUTPUT_FORMAT, @@ -17,13 +16,9 @@ use crate::{ #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, "max-depth": { description: "maximum recursion depth", @@ -84,13 +79,9 @@ async fn list_namespaces(param: Value, max_depth: Option) -> Result<(), E #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, } }, @@ -124,13 +115,9 @@ async fn create_namespace(param: Value) -> Result<(), Error> { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, "delete-groups": { description: "Destroys all groups in the hierarchy.", diff --git a/proxmox-backup-client/src/snapshot.rs b/proxmox-backup-client/src/snapshot.rs index 500fd2bb8..b8b208a1f 100644 --- a/proxmox-backup-client/src/snapshot.rs +++ b/proxmox-backup-client/src/snapshot.rs @@ -17,8 +17,8 @@ use pbs_tools::json::required_string_param; use crate::{ api_datastore_list_snapshots, complete_backup_group, complete_backup_snapshot, complete_namespace, complete_repository, connect, crypto_parameters, - extract_repository_from_value, optional_ns_param, record_repository, BackupDir, KEYFD_SCHEMA, - KEYFILE_SCHEMA, REPO_URL_SCHEMA, + extract_repository_from_value, optional_ns_param, record_repository, BackupDir, + BackupTargetArgs, KEYFD_SCHEMA, KEYFILE_SCHEMA, }; fn snapshot_args(ns: &BackupNamespace, snapshot: &BackupDir) -> Result { @@ -32,13 +32,9 @@ fn snapshot_args(ns: &BackupNamespace, snapshot: &BackupDir) -> Result Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -161,13 +153,9 @@ async fn list_snapshot_files(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -200,13 +188,9 @@ async fn forget_snapshots(param: Value) -> Result<(), Error> { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -281,13 +265,9 @@ async fn upload_log(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -338,13 +318,9 @@ async fn show_notes(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -380,13 +356,9 @@ async fn update_notes(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -437,13 +409,9 @@ async fn show_protection(param: Value) -> Result<(), Error> { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, diff --git a/proxmox-backup-client/src/task.rs b/proxmox-backup-client/src/task.rs index 472db0860..dba50cc85 100644 --- a/proxmox-backup-client/src/task.rs +++ b/proxmox-backup-client/src/task.rs @@ -10,14 +10,14 @@ use pbs_tools::json::required_string_param; use pbs_api_types::UPID; -use crate::{complete_repository, connect, extract_repository_from_value, REPO_URL_SCHEMA}; +use crate::{complete_repository, connect, extract_repository_from_value, BackupRepositoryArgs}; #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, limit: { description: "The maximal number of tasks to list.", @@ -87,9 +87,9 @@ async fn task_list(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, upid: { type: UPID, @@ -112,9 +112,9 @@ async fn task_log(param: Value) -> Result { #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, + repo: { + type: BackupRepositoryArgs, + flatten: true, }, upid: { type: UPID, diff --git a/proxmox-file-restore/src/main.rs b/proxmox-file-restore/src/main.rs index bf6cf9aed..4b5fd6c62 100644 --- a/proxmox-file-restore/src/main.rs +++ b/proxmox-file-restore/src/main.rs @@ -31,9 +31,9 @@ use pbs_client::tools::{ crypto_parameters_keep_fd, format_key_source, get_encryption_key_password, KEYFD_SCHEMA, KEYFILE_SCHEMA, }, - REPO_URL_SCHEMA, + optional_ns_param, }; -use pbs_client::{BackupReader, BackupRepository, RemoteChunkReader}; +use pbs_client::{BackupReader, BackupRepository, BackupTargetArgs, RemoteChunkReader}; use pbs_datastore::catalog::{ArchiveEntry, CatalogReader, DirEntryAttribute}; use pbs_datastore::dynamic_index::BufferedDynamicReader; use pbs_datastore::index::IndexFile; @@ -212,13 +212,9 @@ async fn list_files( #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -272,7 +268,6 @@ async fn list_files( )] /// List a directory from a backup snapshot. async fn list( - ns: Option, snapshot: String, path: String, base64: bool, @@ -280,7 +275,7 @@ async fn list( param: Value, ) -> Result<(), Error> { let repo = extract_repository_from_value(¶m)?; - let ns = ns.unwrap_or_default(); + let ns = optional_ns_param(¶m)?; let snapshot: BackupDir = snapshot.parse()?; let path = parse_path(path, base64)?; @@ -361,13 +356,9 @@ async fn list( #[api( input: { properties: { - repository: { - schema: REPO_URL_SCHEMA, - optional: true, - }, - ns: { - type: BackupNamespace, - optional: true, + repo: { + type: BackupTargetArgs, + flatten: true, }, snapshot: { type: String, @@ -426,7 +417,6 @@ async fn list( /// Restore files from a backup snapshot. #[allow(clippy::too_many_arguments)] async fn extract( - ns: Option, snapshot: String, path: String, base64: bool, @@ -436,7 +426,7 @@ async fn extract( param: Value, ) -> Result<(), Error> { let repo = extract_repository_from_value(¶m)?; - let namespace = ns.unwrap_or_default(); + let namespace = optional_ns_param(¶m)?; let snapshot: BackupDir = snapshot.parse()?; let orig_path = path; let path = parse_path(orig_path.clone(), base64)?; diff --git a/src/bin/proxmox_backup_debug/diff.rs b/src/bin/proxmox_backup_debug/diff.rs index 116216e51..20ac73125 100644 --- a/src/bin/proxmox_backup_debug/diff.rs +++ b/src/bin/proxmox_backup_debug/diff.rs @@ -19,9 +19,9 @@ use pbs_client::tools::key_source::{ }; use pbs_client::tools::{ complete_archive_name, complete_group_or_snapshot, connect, extract_repository_from_value, - REPO_URL_SCHEMA, + optional_ns_param, }; -use pbs_client::{BackupReader, BackupRepository, RemoteChunkReader}; +use pbs_client::{BackupReader, BackupRepository, BackupTargetArgs, RemoteChunkReader}; use pbs_datastore::dynamic_index::{BufferedDynamicReader, DynamicIndexReader, LocalDynamicReadAt}; use pbs_datastore::index::IndexFile; use pbs_key_config::decrypt_key; @@ -57,10 +57,6 @@ pub fn diff_commands() -> CommandLineInterface { #[api( input: { properties: { - "ns": { - type: BackupNamespace, - optional: true, - }, "prev-snapshot": { description: "Path for the first snapshot.", type: String, @@ -72,9 +68,9 @@ pub fn diff_commands() -> CommandLineInterface { "archive-name": { type: BackupArchiveName, }, - "repository": { - optional: true, - schema: REPO_URL_SCHEMA, + repo: { + type: BackupTargetArgs, + flatten: true, }, "keyfile": { optional: true, @@ -108,13 +104,12 @@ async fn diff_archive_cmd( archive_name: BackupArchiveName, compare_content: bool, color: Option, - ns: Option, param: Value, ) -> Result<(), Error> { let repo = extract_repository_from_value(¶m)?; let color = color.unwrap_or_default(); - let namespace = ns.unwrap_or_else(BackupNamespace::root); + let namespace = optional_ns_param(¶m)?; let crypto = crypto_parameters(¶m)?; -- 2.47.3