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:
Wolfgang Bumiller 2022-05-10 15:55:14 +02:00 committed by Thomas Lamprecht
parent 473063e9ec
commit 226a4e68da
2 changed files with 172 additions and 0 deletions

View File

@ -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"])

View 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(&param);
let repo = extract_repository_from_value(&param)?;
let backup_ns = optional_ns_param(&param)?;
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(&param)?;
let mut backup_ns = optional_ns_param(&param)?;
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(&param)?;
let backup_ns = optional_ns_param(&param)?;
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"]),
)
}