client: add basic namespace commands
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
473063e9ec
commit
226a4e68da
@ -71,6 +71,7 @@ pub use catalog::*;
|
||||
mod snapshot;
|
||||
pub use snapshot::*;
|
||||
pub mod key;
|
||||
pub mod namespace;
|
||||
|
||||
fn record_repository(repo: &BackupRepository) {
|
||||
let base = match BaseDirectories::with_prefix("proxmox-backup") {
|
||||
@ -1685,6 +1686,7 @@ fn main() {
|
||||
.insert("version", version_cmd_def)
|
||||
.insert("benchmark", benchmark_cmd_def)
|
||||
.insert("change-owner", change_owner_cmd_def)
|
||||
.insert("namespace", namespace::cli_map())
|
||||
.alias(&["files"], &["snapshot", "files"])
|
||||
.alias(&["forget"], &["snapshot", "forget"])
|
||||
.alias(&["upload-log"], &["snapshot", "upload-log"])
|
||||
|
170
proxmox-backup-client/src/namespace.rs
Normal file
170
proxmox-backup-client/src/namespace.rs
Normal file
@ -0,0 +1,170 @@
|
||||
use anyhow::{bail, Error};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use pbs_api_types::BackupNamespace;
|
||||
use pbs_client::tools::REPO_URL_SCHEMA;
|
||||
|
||||
use proxmox_router::cli::{
|
||||
format_and_print_result, get_output_format, CliCommand, CliCommandMap, OUTPUT_FORMAT,
|
||||
};
|
||||
use proxmox_schema::api;
|
||||
|
||||
use crate::{connect, extract_repository_from_value, optional_ns_param, record_repository};
|
||||
|
||||
#[api(
|
||||
input: {
|
||||
properties: {
|
||||
repository: {
|
||||
schema: REPO_URL_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
ns: {
|
||||
type: BackupNamespace,
|
||||
optional: true,
|
||||
},
|
||||
"max-depth": {
|
||||
description: "maximum recursion depth",
|
||||
optional: true,
|
||||
},
|
||||
"output-format": {
|
||||
schema: OUTPUT_FORMAT,
|
||||
optional: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
)]
|
||||
/// List namespaces in a repository.
|
||||
async fn list_namespaces(param: Value, max_depth: Option<usize>) -> Result<(), Error> {
|
||||
let output_format = get_output_format(¶m);
|
||||
let repo = extract_repository_from_value(¶m)?;
|
||||
let backup_ns = optional_ns_param(¶m)?;
|
||||
|
||||
let path = format!("api2/json/admin/datastore/{}/namespace", repo.store());
|
||||
|
||||
let mut param = json!({});
|
||||
|
||||
if let Some(max_depth) = max_depth {
|
||||
param["max-depth"] = max_depth.into();
|
||||
}
|
||||
|
||||
if !backup_ns.is_root() {
|
||||
param["parent"] = serde_json::to_value(backup_ns)?;
|
||||
}
|
||||
|
||||
let client = connect(&repo)?;
|
||||
|
||||
let mut result = client.get(&path, Some(param)).await?;
|
||||
|
||||
record_repository(&repo);
|
||||
|
||||
if output_format == "text" {
|
||||
let data: Vec<pbs_api_types::NamespaceListItem> =
|
||||
serde_json::from_value(result["data"].take())?;
|
||||
for entry in data {
|
||||
if entry.ns.is_root() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(comment) = entry.comment {
|
||||
println!("{} ({comment})", entry.ns);
|
||||
} else {
|
||||
println!("{}", entry.ns);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
format_and_print_result(&result, &output_format);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[api(
|
||||
input: {
|
||||
properties: {
|
||||
repository: {
|
||||
schema: REPO_URL_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
ns: {
|
||||
type: BackupNamespace,
|
||||
optional: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
)]
|
||||
/// Create a new namespace.
|
||||
async fn create_namespace(param: Value) -> Result<(), Error> {
|
||||
let repo = extract_repository_from_value(¶m)?;
|
||||
let mut backup_ns = optional_ns_param(¶m)?;
|
||||
|
||||
let path = format!("api2/json/admin/datastore/{}/namespace", repo.store());
|
||||
|
||||
let name = match backup_ns.pop() {
|
||||
Some(name) => name,
|
||||
None => bail!("root namespace is always present"),
|
||||
};
|
||||
|
||||
let param = json!({
|
||||
"parent": backup_ns,
|
||||
"name": name,
|
||||
});
|
||||
|
||||
let client = connect(&repo)?;
|
||||
|
||||
let _result = client.post(&path, Some(param)).await?;
|
||||
|
||||
record_repository(&repo);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[api(
|
||||
input: {
|
||||
properties: {
|
||||
repository: {
|
||||
schema: REPO_URL_SCHEMA,
|
||||
optional: true,
|
||||
},
|
||||
ns: {
|
||||
type: BackupNamespace,
|
||||
optional: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
)]
|
||||
/// Delete an existing namespace.
|
||||
async fn delete_namespace(param: Value) -> Result<(), Error> {
|
||||
let repo = extract_repository_from_value(¶m)?;
|
||||
let backup_ns = optional_ns_param(¶m)?;
|
||||
|
||||
if backup_ns.is_root() {
|
||||
bail!("root namespace cannot be deleted");
|
||||
}
|
||||
|
||||
let path = format!("api2/json/admin/datastore/{}/namespace", repo.store());
|
||||
let param = json!({ "ns": backup_ns });
|
||||
|
||||
let client = connect(&repo)?;
|
||||
|
||||
let _result = client.delete(&path, Some(param)).await?;
|
||||
|
||||
record_repository(&repo);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cli_map() -> CliCommandMap {
|
||||
CliCommandMap::new()
|
||||
.insert(
|
||||
"list",
|
||||
CliCommand::new(&API_METHOD_LIST_NAMESPACES).arg_param(&["ns"]),
|
||||
)
|
||||
.insert(
|
||||
"create",
|
||||
CliCommand::new(&API_METHOD_CREATE_NAMESPACE).arg_param(&["ns"]),
|
||||
)
|
||||
.insert(
|
||||
"delete",
|
||||
CliCommand::new(&API_METHOD_DELETE_NAMESPACE).arg_param(&["ns"]),
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user