]> git.proxmox.com Git - proxmox-backup.git/commitdiff
client: add basic namespace commands
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Tue, 10 May 2022 13:55:14 +0000 (15:55 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 12 May 2022 07:33:50 +0000 (09:33 +0200)
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
proxmox-backup-client/src/main.rs
proxmox-backup-client/src/namespace.rs [new file with mode: 0644]

index 179a03d3a4f27a8df63a6500a4ff64fdcc167559..a186da6041674c7ca65ba7a02b0289ce7bda02e7 100644 (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"])
diff --git a/proxmox-backup-client/src/namespace.rs b/proxmox-backup-client/src/namespace.rs
new file mode 100644 (file)
index 0000000..aa34b5c
--- /dev/null
@@ -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"]),
+        )
+}