From: Thomas Lamprecht <t.lamprecht@proxmox.com>
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 [thread overview]
Message-ID: <20260410154327.4133440-4-t.lamprecht@proxmox.com> (raw)
In-Reply-To: <20260410154327.4133440-1-t.lamprecht@proxmox.com>
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 <t.lamprecht@proxmox.com>
---
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<String, String>) -> Option<Ba
resolve_repository(cli).ok()
}
+/// Extract a [`BackupNamespace`] from CLI parameters.
+pub fn optional_ns_param(param: &Value) -> Result<BackupNamespace, Error> {
+ 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<HttpClient, Error> {
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<Value, Error> {
#[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<Value, Error> {
"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<P: AsRef<Path>>(
Ok(stats)
}
-pub fn optional_ns_param(param: &Value) -> Result<BackupNamespace, Error> {
- 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<String, Value>, 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<String, Value>, 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<Value, Error> {
#[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<Value, Error> {
#[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<W: Write>(
#[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(
+ "<mount parameters>",
+ &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(
+ "<map parameters>",
+ &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<usize>) -> 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<Value, Error> {
@@ -32,13 +32,9 @@ fn snapshot_args(ns: &BackupNamespace, snapshot: &BackupDir) -> Result<Value, Er
#[api(
input: {
properties: {
- repository: {
- schema: REPO_URL_SCHEMA,
- optional: true,
- },
- ns: {
- type: BackupNamespace,
- optional: true,
+ repo: {
+ type: BackupTargetArgs,
+ flatten: true,
},
group: {
type: String,
@@ -108,13 +104,9 @@ async fn list_snapshots(param: Value) -> Result<Value, Error> {
#[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<Value, Error> {
#[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<Value, Error> {
#[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<Value, Error> {
#[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<Value, Error> {
#[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<Value, Error> {
#[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<Value, Error> {
#[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<BackupNamespace>,
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<BackupNamespace>,
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<ColorMode>,
- ns: Option<BackupNamespace>,
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
next prev parent reply other threads:[~2026-04-10 15:43 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-10 14:09 [PATCH v4 0/5] client: repository: add individual component parameters Thomas Lamprecht
2026-04-10 14:09 ` [PATCH v4 1/5] client: repository: add tests for BackupRepository parsing Thomas Lamprecht
2026-04-10 14:09 ` [PATCH v4 2/5] client: repository: add individual component parameters Thomas Lamprecht
2026-04-10 14:09 ` Thomas Lamprecht [this message]
2026-04-10 14:09 ` [PATCH v4 4/5] docs: document repository component options and env vars Thomas Lamprecht
2026-04-10 14:09 ` [PATCH v4 5/5] fix #5340: client: repository: add PBS_NAMESPACE environment variable Thomas Lamprecht
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=20260410154327.4133440-4-t.lamprecht@proxmox.com \
--to=t.lamprecht@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.