all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content
@ 2021-07-16  8:53 Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 01/11] api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types Dominik Csapak
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

similar to the 'verify all' button, it makes sense that a user can
prune all groups (which he has access to) on demand with custom setings.

this adds a new api call, since pruning all groups could take a while,
depending on the number of groups snapshots, and it does not make sense
to have that in a synchronous api call (that we already have per group),
so modifying the existing api call to have the group optional was not
really sensible IMHO.

patches 1-6 are simply refactoring, to make it more easy to use
 the PruneOptions, 'prune_datastore', etc. later
7,8 add new parameter/functionality to the 'prune_datastore' method
9 really adds the api call
10 is the button in the gui
11 is just a ui improvement for the other prune window
 (could be applied seperately)

Dominik Csapak (11):
  api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types
  pbs-datastore/prune: make PruneOptions an api type
  client: simplify prune api method
  api: admin/datastore: simplify prune api call
  backup/datastore: refactor check_backup_owner there
  server/prune_job: factor out 'prune_datastore'
  server/prune_job: add 'keep_all' logic to 'prune_datastore'
  server/prune_job: add proper permission checks to 'prune_datastore'
  api: admin/datastore: add new 'prune-datastore' api call
  ui: datastore/Content: add 'Prune All' button
  ui: datastore/Prune: improve title of group prune window

 pbs-api-types/src/lib.rs         |  30 +++++
 pbs-datastore/src/prune.rs       |  50 +++++++-
 src/api2/admin/datastore.rs      | 208 ++++++++++++++++---------------
 src/api2/types/mod.rs            |  30 -----
 src/backup/datastore.rs          |  20 +++
 src/bin/proxmox-backup-client.rs |  95 +++++++-------
 src/server/prune_job.rs          | 139 +++++++++++++--------
 www/datastore/Content.js         |  34 +++++
 www/datastore/Prune.js           |   2 +-
 www/window/DataStoreEdit.js      |  15 +++
 10 files changed, 390 insertions(+), 233 deletions(-)

-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 01/11] api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 02/11] pbs-datastore/prune: make PruneOptions an api type Dominik Csapak
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 pbs-api-types/src/lib.rs | 30 ++++++++++++++++++++++++++++++
 src/api2/types/mod.rs    | 30 ------------------------------
 2 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs
index f9fe5cfb..c07699d1 100644
--- a/pbs-api-types/src/lib.rs
+++ b/pbs-api-types/src/lib.rs
@@ -146,6 +146,36 @@ pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema =
         .format(&FINGERPRINT_SHA256_FORMAT)
         .schema();
 
+pub const PRUNE_SCHEMA_KEEP_DAILY: Schema = IntegerSchema::new(
+    "Number of daily backups to keep.")
+    .minimum(1)
+    .schema();
+
+pub const PRUNE_SCHEMA_KEEP_HOURLY: Schema = IntegerSchema::new(
+    "Number of hourly backups to keep.")
+    .minimum(1)
+    .schema();
+
+pub const PRUNE_SCHEMA_KEEP_LAST: Schema = IntegerSchema::new(
+    "Number of backups to keep.")
+    .minimum(1)
+    .schema();
+
+pub const PRUNE_SCHEMA_KEEP_MONTHLY: Schema = IntegerSchema::new(
+    "Number of monthly backups to keep.")
+    .minimum(1)
+    .schema();
+
+pub const PRUNE_SCHEMA_KEEP_WEEKLY: Schema = IntegerSchema::new(
+    "Number of weekly backups to keep.")
+    .minimum(1)
+    .schema();
+
+pub const PRUNE_SCHEMA_KEEP_YEARLY: Schema = IntegerSchema::new(
+    "Number of yearly backups to keep.")
+    .minimum(1)
+    .schema();
+
 pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat =
     ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
 
diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs
index d3c16b96..b8b42a5e 100644
--- a/src/api2/types/mod.rs
+++ b/src/api2/types/mod.rs
@@ -357,36 +357,6 @@ pub const REALM_ID_SCHEMA: Schema = StringSchema::new("Realm name.")
 
 // Complex type definitions
 
-pub const PRUNE_SCHEMA_KEEP_DAILY: Schema = IntegerSchema::new(
-    "Number of daily backups to keep.")
-    .minimum(1)
-    .schema();
-
-pub const PRUNE_SCHEMA_KEEP_HOURLY: Schema = IntegerSchema::new(
-    "Number of hourly backups to keep.")
-    .minimum(1)
-    .schema();
-
-pub const PRUNE_SCHEMA_KEEP_LAST: Schema = IntegerSchema::new(
-    "Number of backups to keep.")
-    .minimum(1)
-    .schema();
-
-pub const PRUNE_SCHEMA_KEEP_MONTHLY: Schema = IntegerSchema::new(
-    "Number of monthly backups to keep.")
-    .minimum(1)
-    .schema();
-
-pub const PRUNE_SCHEMA_KEEP_WEEKLY: Schema = IntegerSchema::new(
-    "Number of weekly backups to keep.")
-    .minimum(1)
-    .schema();
-
-pub const PRUNE_SCHEMA_KEEP_YEARLY: Schema = IntegerSchema::new(
-    "Number of yearly backups to keep.")
-    .minimum(1)
-    .schema();
-
 #[api()]
 #[derive(Default, Serialize, Deserialize)]
 /// Storage space usage information.
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 02/11] pbs-datastore/prune: make PruneOptions an api type
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 01/11] api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 03/11] client: simplify prune api method Dominik Csapak
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

so that we can reuse it from here

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 pbs-datastore/src/prune.rs | 50 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/pbs-datastore/src/prune.rs b/pbs-datastore/src/prune.rs
index d0d8ca16..4605e26f 100644
--- a/pbs-datastore/src/prune.rs
+++ b/pbs-datastore/src/prune.rs
@@ -2,6 +2,18 @@ use std::collections::{HashMap, HashSet};
 use std::path::PathBuf;
 
 use anyhow::{Error};
+use serde::{Deserialize, Serialize};
+
+use proxmox::api::api;
+
+use pbs_api_types::{
+    PRUNE_SCHEMA_KEEP_LAST,
+    PRUNE_SCHEMA_KEEP_HOURLY,
+    PRUNE_SCHEMA_KEEP_DAILY,
+    PRUNE_SCHEMA_KEEP_WEEKLY,
+    PRUNE_SCHEMA_KEEP_MONTHLY,
+    PRUNE_SCHEMA_KEEP_YEARLY,
+};
 
 use super::BackupInfo;
 
@@ -68,13 +80,49 @@ fn remove_incomplete_snapshots(
     }
 }
 
-#[derive(Default)]
+#[api(
+    properties: {
+        "keep-last": {
+            schema: PRUNE_SCHEMA_KEEP_LAST,
+            optional: true,
+        },
+        "keep-hourly": {
+            schema: PRUNE_SCHEMA_KEEP_HOURLY,
+            optional: true,
+        },
+        "keep-daily": {
+            schema: PRUNE_SCHEMA_KEEP_DAILY,
+            optional: true,
+        },
+        "keep-weekly": {
+            schema: PRUNE_SCHEMA_KEEP_WEEKLY,
+            optional: true,
+        },
+        "keep-monthly": {
+            schema: PRUNE_SCHEMA_KEEP_MONTHLY,
+            optional: true,
+        },
+        "keep-yearly": {
+            schema: PRUNE_SCHEMA_KEEP_YEARLY,
+            optional: true,
+        },
+    }
+)]
+#[derive(Serialize, Deserialize, Default)]
+#[serde(rename_all = "kebab-case")]
+/// Common pruning options
 pub struct PruneOptions {
+    #[serde(skip_serializing_if="Option::is_none")]
     pub keep_last: Option<u64>,
+    #[serde(skip_serializing_if="Option::is_none")]
     pub keep_hourly: Option<u64>,
+    #[serde(skip_serializing_if="Option::is_none")]
     pub keep_daily: Option<u64>,
+    #[serde(skip_serializing_if="Option::is_none")]
     pub keep_weekly: Option<u64>,
+    #[serde(skip_serializing_if="Option::is_none")]
     pub keep_monthly: Option<u64>,
+    #[serde(skip_serializing_if="Option::is_none")]
     pub keep_yearly: Option<u64>,
 }
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 03/11] client: simplify prune api method
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 01/11] api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 02/11] pbs-datastore/prune: make PruneOptions an api type Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 04/11] api: admin/datastore: simplify prune api call Dominik Csapak
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

by using the api macro on the async method and reusing the PruneOptions
from pbs-datastore with 'flatten: true'

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/bin/proxmox-backup-client.rs | 95 ++++++++++++++++----------------
 1 file changed, 49 insertions(+), 46 deletions(-)

diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-client.rs
index b110763e..a5810538 100644
--- a/src/bin/proxmox-backup-client.rs
+++ b/src/bin/proxmox-backup-client.rs
@@ -6,7 +6,6 @@ use std::sync::{Arc, Mutex};
 use std::task::Context;
 
 use anyhow::{bail, format_err, Error};
-use futures::future::FutureExt;
 use futures::stream::{StreamExt, TryStreamExt};
 use serde_json::{json, Value};
 use tokio::sync::mpsc;
@@ -21,10 +20,8 @@ use proxmox::{
     },
     api::{
         api,
-        ApiHandler,
         ApiMethod,
         RpcEnvironment,
-        schema::*,
         cli::*,
     },
 };
@@ -65,6 +62,7 @@ use proxmox_backup::backup::{
     IndexFile,
     MANIFEST_BLOB_NAME,
     Shell,
+    PruneOptions,
 };
 
 mod proxmox_backup_client;
@@ -1225,60 +1223,65 @@ async fn restore(param: Value) -> Result<Value, Error> {
     Ok(Value::Null)
 }
 
-const API_METHOD_PRUNE: ApiMethod = ApiMethod::new(
-    &ApiHandler::Async(&prune),
-    &ObjectSchema::new(
-        "Prune a backup repository.",
-        &proxmox_backup::add_common_prune_prameters!([
-            ("dry-run", true, &BooleanSchema::new(
-                "Just show what prune would do, but do not delete anything.")
-             .schema()),
-            ("group", false, &StringSchema::new("Backup group.").schema()),
-        ], [
-            ("output-format", true, &OUTPUT_FORMAT),
-            (
-                "quiet",
-                true,
-                &BooleanSchema::new("Minimal output - only show removals.")
-                    .schema()
-            ),
-            ("repository", true, &REPO_URL_SCHEMA),
-        ])
-    )
-);
-
-fn prune<'a>(
-    param: Value,
-    _info: &ApiMethod,
-    _rpcenv: &'a mut dyn RpcEnvironment,
-) -> proxmox::api::ApiFuture<'a> {
-    async move {
-        prune_async(param).await
-    }.boxed()
-}
-
-async fn prune_async(mut param: Value) -> Result<Value, Error> {
+#[api(
+    input: {
+        properties: {
+            "dry-run": {
+                type: bool,
+                optional: true,
+                description: "Just show what prune would do, but do not delete anything.",
+            },
+            group: {
+                type: String,
+                description: "Backup group",
+            },
+            "prune-options": {
+                type: PruneOptions,
+                flatten: true,
+            },
+            "output-format": {
+                schema: OUTPUT_FORMAT,
+                optional: true,
+            },
+            quiet: {
+                type: bool,
+                optional: true,
+                default: false,
+                description: "Minimal output - only show removals.",
+            },
+            repository: {
+                schema: REPO_URL_SCHEMA,
+                optional: true,
+            },
+        },
+    },
+)]
+/// Prune a backup repository.
+async fn prune(
+    dry_run: Option<bool>,
+    group: String,
+    prune_options: PruneOptions,
+    quiet: bool,
+    mut param: Value
+) -> Result<Value, Error> {
     let repo = extract_repository_from_value(&param)?;
 
     let mut client = connect(&repo)?;
 
     let path = format!("api2/json/admin/datastore/{}/prune", repo.store());
 
-    let group = tools::required_string_param(&param, "group")?;
     let group: BackupGroup = group.parse()?;
 
     let output_format = extract_output_format(&mut param);
 
-    let quiet = param["quiet"].as_bool().unwrap_or(false);
-
-    param.as_object_mut().unwrap().remove("repository");
-    param.as_object_mut().unwrap().remove("group");
-    param.as_object_mut().unwrap().remove("quiet");
-
-    param["backup-type"] = group.backup_type().into();
-    param["backup-id"] = group.backup_id().into();
+    let mut api_param = serde_json::to_value(prune_options)?;
+    if let Some(dry_run) = dry_run {
+        api_param["dry-run"] = dry_run.into();
+    }
+    api_param["backup-type"] = group.backup_type().into();
+    api_param["backup-id"] = group.backup_id().into();
 
-    let mut result = client.post(&path, Some(param)).await?;
+    let mut result = client.post(&path, Some(api_param)).await?;
 
     record_repository(&repo);
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 04/11] api: admin/datastore: simplify prune api call
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (2 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 03/11] client: simplify prune api method Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 05/11] backup/datastore: refactor check_backup_owner there Dominik Csapak
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

by using the api macro and reusing the PruneOptions from pbs-datastore

this means we can now drop the 'add_common_prune_prameters' macro

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/admin/datastore.rs | 135 ++++++++++++------------------------
 1 file changed, 45 insertions(+), 90 deletions(-)

diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 184def5a..0bf6a86b 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -16,7 +16,7 @@ use proxmox::api::{
     api, ApiResponseFuture, ApiHandler, ApiMethod, Router,
     RpcEnvironment, RpcEnvironmentType, Permission
 };
-use proxmox::api::router::{ReturnType, SubdirMap};
+use proxmox::api::router::SubdirMap;
 use proxmox::api::schema::*;
 use proxmox::tools::fs::{
     file_read_firstline, file_read_optional_string, replace_file, CreateOptions,
@@ -797,106 +797,61 @@ pub fn verify(
     Ok(json!(upid_str))
 }
 
-#[macro_export]
-macro_rules! add_common_prune_prameters {
-    ( [ $( $list1:tt )* ] ) => {
-        add_common_prune_prameters!([$( $list1 )* ] ,  [])
-    };
-    ( [ $( $list1:tt )* ] ,  [ $( $list2:tt )* ] ) => {
-        [
-            $( $list1 )*
-            (
-                "keep-daily",
-                true,
-                &PRUNE_SCHEMA_KEEP_DAILY,
-            ),
-            (
-                "keep-hourly",
-                true,
-                &PRUNE_SCHEMA_KEEP_HOURLY,
-            ),
-            (
-                "keep-last",
-                true,
-                &PRUNE_SCHEMA_KEEP_LAST,
-            ),
-            (
-                "keep-monthly",
-                true,
-                &PRUNE_SCHEMA_KEEP_MONTHLY,
-            ),
-            (
-                "keep-weekly",
-                true,
-                &PRUNE_SCHEMA_KEEP_WEEKLY,
-            ),
-            (
-                "keep-yearly",
-                true,
-                &PRUNE_SCHEMA_KEEP_YEARLY,
-            ),
-            $( $list2 )*
-        ]
-    }
-}
-
-pub const API_RETURN_SCHEMA_PRUNE: Schema = ArraySchema::new(
-    "Returns the list of snapshots and a flag indicating if there are kept or removed.",
-    &PruneListItem::API_SCHEMA
-).schema();
-
-pub const API_METHOD_PRUNE: ApiMethod = ApiMethod::new(
-    &ApiHandler::Sync(&prune),
-    &ObjectSchema::new(
-        "Prune the datastore.",
-        &add_common_prune_prameters!([
-            ("backup-id", false, &BACKUP_ID_SCHEMA),
-            ("backup-type", false, &BACKUP_TYPE_SCHEMA),
-            ("dry-run", true, &BooleanSchema::new(
-                "Just show what prune would do, but do not delete anything.")
-             .schema()
-            ),
-        ],[
-            ("store", false, &DATASTORE_SCHEMA),
-        ])
-    ))
-    .returns(ReturnType::new(false, &API_RETURN_SCHEMA_PRUNE))
-    .access(None, &Permission::Privilege(
-    &["datastore", "{store}"],
-    PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE,
-    true)
-);
-
+#[api(
+    input: {
+        properties: {
+            "backup-id": {
+                schema: BACKUP_ID_SCHEMA,
+            },
+            "backup-type": {
+                schema: BACKUP_TYPE_SCHEMA,
+            },
+            "dry-run": {
+                optional: true,
+                type: bool,
+                default: false,
+                description: "Just show what prune would do, but do not delete anything.",
+            },
+            "prune-options": {
+                type: PruneOptions,
+                flatten: true,
+            },
+            store: {
+                schema: DATASTORE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        type: Array,
+        description: "Returns the list of snapshots and a flag indicating if there are kept or removed.",
+        items: {
+            type: PruneListItem,
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE, true),
+    },
+)]
+/// Prune the datastore
 pub fn prune(
-    param: Value,
-    _info: &ApiMethod,
+    backup_id: String,
+    backup_type: String,
+    dry_run: bool,
+    prune_options: PruneOptions,
+    store: String,
+    _param: Value,
     rpcenv: &mut dyn RpcEnvironment,
 ) -> Result<Value, Error> {
 
-    let store = tools::required_string_param(&param, "store")?;
-    let backup_type = tools::required_string_param(&param, "backup-type")?;
-    let backup_id = tools::required_string_param(&param, "backup-id")?;
-
     let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
 
-    let dry_run = param["dry-run"].as_bool().unwrap_or(false);
-
-    let group = BackupGroup::new(backup_type, backup_id);
+    let group = BackupGroup::new(&backup_type, &backup_id);
 
     let datastore = DataStore::lookup_datastore(&store)?;
 
     check_priv_or_backup_owner(&datastore, &group, &auth_id, PRIV_DATASTORE_MODIFY)?;
 
-    let prune_options = PruneOptions {
-        keep_last: param["keep-last"].as_u64(),
-        keep_hourly: param["keep-hourly"].as_u64(),
-        keep_daily: param["keep-daily"].as_u64(),
-        keep_weekly: param["keep-weekly"].as_u64(),
-        keep_monthly: param["keep-monthly"].as_u64(),
-        keep_yearly: param["keep-yearly"].as_u64(),
-    };
-
-    let worker_id = format!("{}:{}/{}", store, backup_type, backup_id);
+    let worker_id = format!("{}:{}/{}", store, &backup_type, &backup_id);
 
     let mut prune_result = Vec::new();
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 05/11] backup/datastore: refactor check_backup_owner there
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (3 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 04/11] api: admin/datastore: simplify prune api call Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 06/11] server/prune_job: factor out 'prune_datastore' Dominik Csapak
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

and add a 'owns_backup' convenience function

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/admin/datastore.rs | 12 ------------
 src/backup/datastore.rs     | 20 ++++++++++++++++++++
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 0bf6a86b..79ab97e7 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -74,18 +74,6 @@ fn check_priv_or_backup_owner(
     Ok(())
 }
 
-fn check_backup_owner(
-    owner: &Authid,
-    auth_id: &Authid,
-) -> Result<(), Error> {
-    let correct_owner = owner == auth_id
-        || (owner.is_token() && &Authid::from(owner.user().clone()) == auth_id);
-    if !correct_owner {
-        bail!("backup owner check failed ({} != {})", auth_id, owner);
-    }
-    Ok(())
-}
-
 fn read_backup_index(
     store: &DataStore,
     backup_dir: &BackupDir,
diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs
index d47c412b..29700846 100644
--- a/src/backup/datastore.rs
+++ b/src/backup/datastore.rs
@@ -37,6 +37,20 @@ lazy_static! {
     static ref DATASTORE_MAP: Mutex<HashMap<String, Arc<DataStore>>> = Mutex::new(HashMap::new());
 }
 
+/// checks if auth_id is owner, or, if owner is a token, if
+/// auth_id is the user of the token
+pub fn check_backup_owner(
+    owner: &Authid,
+    auth_id: &Authid,
+) -> Result<(), Error> {
+    let correct_owner = owner == auth_id
+        || (owner.is_token() && &Authid::from(owner.user().clone()) == auth_id);
+    if !correct_owner {
+        bail!("backup owner check failed ({} != {})", auth_id, owner);
+    }
+    Ok(())
+}
+
 /// Datastore Management
 ///
 /// A Datastore can store severals backups, and provides the
@@ -338,6 +352,12 @@ impl DataStore {
         Ok(owner.trim_end().parse()?) // remove trailing newline
     }
 
+    pub fn owns_backup(&self, backup_group: &BackupGroup, auth_id: &Authid) -> Result<bool, Error> {
+        let owner = self.get_owner(backup_group)?;
+
+        Ok(check_backup_owner(owner, auth_id).is_ok())
+    }
+
     /// Set the backup owner.
     pub fn set_owner(
         &self,
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 06/11] server/prune_job: factor out 'prune_datastore'
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (4 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 05/11] backup/datastore: refactor check_backup_owner there Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 07/11] server/prune_job: add 'keep_all' logic to 'prune_datastore' Dominik Csapak
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

we want to use that outside of a prune job

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/server/prune_job.rs | 114 +++++++++++++++++++++-------------------
 1 file changed, 61 insertions(+), 53 deletions(-)

diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs
index 248068ea..7ea42fcb 100644
--- a/src/server/prune_job.rs
+++ b/src/server/prune_job.rs
@@ -1,6 +1,6 @@
-use anyhow::Error;
+use std::sync::Arc;
 
-use proxmox::try_block;
+use anyhow::Error;
 
 use pbs_datastore::{task_log, task_warn};
 
@@ -11,6 +11,61 @@ use crate::{
     server::WorkerTask,
 };
 
+pub fn prune_datastore(
+    worker: Arc<WorkerTask>,
+    prune_options: PruneOptions,
+    store: &str,
+    datastore: Arc<DataStore>,
+) -> Result<(), Error> {
+    task_log!(worker, "Starting datastore prune on store \"{}\"", store);
+
+    task_log!(
+        worker,
+        "retention options: {}",
+        prune_options.cli_options_string()
+    );
+
+    let base_path = datastore.base_path();
+
+    let groups = BackupInfo::list_backup_groups(&base_path)?;
+    for group in groups {
+        let list = group.list_backups(&base_path)?;
+        let mut prune_info = compute_prune_info(list, &prune_options)?;
+        prune_info.reverse(); // delete older snapshots first
+
+        task_log!(
+            worker,
+            "Starting prune on store \"{}\" group \"{}/{}\"",
+            store,
+            group.backup_type(),
+            group.backup_id()
+        );
+
+        for (info, keep) in prune_info {
+            task_log!(
+                worker,
+                "{} {}/{}/{}",
+                if keep { "keep" } else { "remove" },
+                group.backup_type(),
+                group.backup_id(),
+                info.backup_dir.backup_time_string()
+            );
+            if !keep {
+                if let Err(err) = datastore.remove_backup_dir(&info.backup_dir, false) {
+                    task_warn!(
+                        worker,
+                        "failed to remove dir {:?}: {}",
+                        info.backup_dir.relative_path(),
+                        err,
+                    );
+                }
+            }
+        }
+    }
+
+    Ok(())
+}
+
 pub fn do_prune_job(
     mut job: Job,
     prune_options: PruneOptions,
@@ -29,58 +84,11 @@ pub fn do_prune_job(
         move |worker| {
             job.start(&worker.upid().to_string())?;
 
-            let result = try_block!({
-                task_log!(worker, "Starting datastore prune on store \"{}\"", store);
-
-                if let Some(event_str) = schedule {
-                    task_log!(worker, "task triggered by schedule '{}'", event_str);
-                }
-
-                task_log!(
-                    worker,
-                    "retention options: {}",
-                    prune_options.cli_options_string()
-                );
-
-                let base_path = datastore.base_path();
-
-                let groups = BackupInfo::list_backup_groups(&base_path)?;
-                for group in groups {
-                    let list = group.list_backups(&base_path)?;
-                    let mut prune_info = compute_prune_info(list, &prune_options)?;
-                    prune_info.reverse(); // delete older snapshots first
-
-                    task_log!(
-                        worker,
-                        "Starting prune on store \"{}\" group \"{}/{}\"",
-                        store,
-                        group.backup_type(),
-                        group.backup_id()
-                    );
+            if let Some(event_str) = schedule {
+                task_log!(worker, "task triggered by schedule '{}'", event_str);
+            }
 
-                    for (info, keep) in prune_info {
-                        task_log!(
-                            worker,
-                            "{} {}/{}/{}",
-                            if keep { "keep" } else { "remove" },
-                            group.backup_type(),
-                            group.backup_id(),
-                            info.backup_dir.backup_time_string()
-                        );
-                        if !keep {
-                            if let Err(err) = datastore.remove_backup_dir(&info.backup_dir, false) {
-                                task_warn!(
-                                    worker,
-                                    "failed to remove dir {:?}: {}",
-                                    info.backup_dir.relative_path(),
-                                    err,
-                                );
-                            }
-                        }
-                    }
-                }
-                Ok(())
-            });
+            let result = prune_datastore(worker.clone(), prune_options, &store, datastore);
 
             let status = worker.create_state(&result);
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 07/11] server/prune_job: add 'keep_all' logic to 'prune_datastore'
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (5 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 06/11] server/prune_job: factor out 'prune_datastore' Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 08/11] server/prune_job: add proper permission checks " Dominik Csapak
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

it is the same as when pruning single groups.
for prune_jobs, we never start the worker if there is no prune option set.
but if we want to call 'prune_datastore' from somewhere else, we
have to check it here again

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/server/prune_job.rs | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs
index 7ea42fcb..40ed555f 100644
--- a/src/server/prune_job.rs
+++ b/src/server/prune_job.rs
@@ -19,11 +19,17 @@ pub fn prune_datastore(
 ) -> Result<(), Error> {
     task_log!(worker, "Starting datastore prune on store \"{}\"", store);
 
-    task_log!(
-        worker,
-        "retention options: {}",
-        prune_options.cli_options_string()
-    );
+    let keep_all = !prune_options.keeps_something();
+
+    if keep_all {
+        task_log!(worker, "No prune selection - keeping all files.");
+    } else {
+        task_log!(
+            worker,
+            "retention options: {}",
+            prune_options.cli_options_string()
+        );
+    }
 
     let base_path = datastore.base_path();
 
@@ -41,7 +47,8 @@ pub fn prune_datastore(
             group.backup_id()
         );
 
-        for (info, keep) in prune_info {
+        for (info, mut keep) in prune_info {
+            if keep_all { keep = true; }
             task_log!(
                 worker,
                 "{} {}/{}/{}",
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 08/11] server/prune_job: add proper permission checks to 'prune_datastore'
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (6 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 07/11] server/prune_job: add 'keep_all' logic to 'prune_datastore' Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 09/11] api: admin/datastore: add new 'prune-datastore' api call Dominik Csapak
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

checks for PRIV_DATASTORE_MODIFY, or else if the auth_id is the backup
owner, and skips the group if not.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/backup/datastore.rs |  2 +-
 src/server/prune_job.rs | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs
index 29700846..0a5a52d1 100644
--- a/src/backup/datastore.rs
+++ b/src/backup/datastore.rs
@@ -355,7 +355,7 @@ impl DataStore {
     pub fn owns_backup(&self, backup_group: &BackupGroup, auth_id: &Authid) -> Result<bool, Error> {
         let owner = self.get_owner(backup_group)?;
 
-        Ok(check_backup_owner(owner, auth_id).is_ok())
+        Ok(check_backup_owner(&owner, auth_id).is_ok())
     }
 
     /// Set the backup owner.
diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs
index 40ed555f..bbf53ade 100644
--- a/src/server/prune_job.rs
+++ b/src/server/prune_job.rs
@@ -6,6 +6,8 @@ use pbs_datastore::{task_log, task_warn};
 
 use crate::{
     api2::types::*,
+    config::acl::PRIV_DATASTORE_MODIFY,
+    config::cached_user_info::CachedUserInfo,
     backup::{compute_prune_info, BackupInfo, DataStore, PruneOptions},
     server::jobstate::Job,
     server::WorkerTask,
@@ -13,6 +15,7 @@ use crate::{
 
 pub fn prune_datastore(
     worker: Arc<WorkerTask>,
+    auth_id: Authid,
     prune_options: PruneOptions,
     store: &str,
     datastore: Arc<DataStore>,
@@ -31,11 +34,20 @@ pub fn prune_datastore(
         );
     }
 
+    let user_info = CachedUserInfo::new()?;
+    let privs = user_info.lookup_privs(&auth_id, &["datastore", store]);
+    let has_privs = privs & PRIV_DATASTORE_MODIFY != 0;
+
     let base_path = datastore.base_path();
 
     let groups = BackupInfo::list_backup_groups(&base_path)?;
     for group in groups {
         let list = group.list_backups(&base_path)?;
+
+        if !has_privs && !datastore.owns_backup(&group, &auth_id)? {
+            continue;
+        }
+
         let mut prune_info = compute_prune_info(list, &prune_options)?;
         prune_info.reverse(); // delete older snapshots first
 
@@ -83,6 +95,7 @@ pub fn do_prune_job(
     let datastore = DataStore::lookup_datastore(&store)?;
 
     let worker_type = job.jobtype().to_string();
+    let auth_id = auth_id.clone();
     let upid_str = WorkerTask::new_thread(
         &worker_type,
         Some(job.jobname().to_string()),
@@ -95,7 +108,7 @@ pub fn do_prune_job(
                 task_log!(worker, "task triggered by schedule '{}'", event_str);
             }
 
-            let result = prune_datastore(worker.clone(), prune_options, &store, datastore);
+            let result = prune_datastore(worker.clone(), auth_id, prune_options, &store, datastore);
 
             let status = worker.create_state(&result);
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 09/11] api: admin/datastore: add new 'prune-datastore' api call
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (7 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 08/11] server/prune_job: add proper permission checks " Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 10/11] ui: datastore/Content: add 'Prune All' button Dominik Csapak
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

to prune the whole datastore at once, with the given parameters.
We need a new api call since this can take a while and we need to start
a worker for this. The exisiting api call returns a list of removed/kept
snapshots and is synchronous.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/admin/datastore.rs | 63 ++++++++++++++++++++++++++++++++++++-
 src/server/prune_job.rs     |  9 ++++--
 2 files changed, 69 insertions(+), 3 deletions(-)

diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 79ab97e7..60941501 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -820,7 +820,7 @@ pub fn verify(
         permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE, true),
     },
 )]
-/// Prune the datastore
+/// Prune a group on the datastore
 pub fn prune(
     backup_id: String,
     backup_type: String,
@@ -922,6 +922,62 @@ pub fn prune(
     Ok(json!(prune_result))
 }
 
+#[api(
+    input: {
+        properties: {
+            "dry-run": {
+                optional: true,
+                type: bool,
+                default: false,
+                description: "Just show what prune would do, but do not delete anything.",
+            },
+            "prune-options": {
+                type: PruneOptions,
+                flatten: true,
+            },
+            store: {
+                schema: DATASTORE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        schema: UPID_SCHEMA,
+    },
+    access: {
+        permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_PRUNE, true),
+    },
+)]
+/// Prune the datastore
+pub fn prune_datastore(
+    dry_run: bool,
+    prune_options: PruneOptions,
+    store: String,
+    _param: Value,
+    rpcenv: &mut dyn RpcEnvironment,
+) -> Result<String, Error> {
+
+    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+
+    let datastore = DataStore::lookup_datastore(&store)?;
+
+    let upid_str = WorkerTask::new_thread(
+        "prune",
+        Some(store.clone()),
+        auth_id.clone(),
+        false,
+        move |worker| crate::server::prune_datastore(
+            worker.clone(),
+            auth_id,
+            prune_options,
+            &store,
+            datastore,
+            dry_run
+        ),
+    )?;
+
+    Ok(upid_str)
+}
+
 #[api(
     input: {
         properties: {
@@ -1844,6 +1900,11 @@ const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
         &Router::new()
             .post(&API_METHOD_PRUNE)
     ),
+    (
+        "prune-datastore",
+        &Router::new()
+            .post(&API_METHOD_PRUNE_DATASTORE)
+    ),
     (
         "pxar-file-download",
         &Router::new()
diff --git a/src/server/prune_job.rs b/src/server/prune_job.rs
index bbf53ade..255e21ce 100644
--- a/src/server/prune_job.rs
+++ b/src/server/prune_job.rs
@@ -19,9 +19,14 @@ pub fn prune_datastore(
     prune_options: PruneOptions,
     store: &str,
     datastore: Arc<DataStore>,
+    dry_run: bool,
 ) -> Result<(), Error> {
     task_log!(worker, "Starting datastore prune on store \"{}\"", store);
 
+    if dry_run {
+        task_log!(worker, "(dry test run)");
+    }
+
     let keep_all = !prune_options.keeps_something();
 
     if keep_all {
@@ -69,7 +74,7 @@ pub fn prune_datastore(
                 group.backup_id(),
                 info.backup_dir.backup_time_string()
             );
-            if !keep {
+            if !keep && !dry_run {
                 if let Err(err) = datastore.remove_backup_dir(&info.backup_dir, false) {
                     task_warn!(
                         worker,
@@ -108,7 +113,7 @@ pub fn do_prune_job(
                 task_log!(worker, "task triggered by schedule '{}'", event_str);
             }
 
-            let result = prune_datastore(worker.clone(), auth_id, prune_options, &store, datastore);
+            let result = prune_datastore(worker.clone(), auth_id, prune_options, &store, datastore, false);
 
             let status = worker.create_state(&result);
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 10/11] ui: datastore/Content: add 'Prune All' button
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (8 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 09/11] api: admin/datastore: add new 'prune-datastore' api call Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 11/11] ui: datastore/Prune: improve title of group prune window Dominik Csapak
  2021-07-16  9:48 ` [pbs-devel] applied: [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dietmar Maurer
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

since the api call always starts a real worker, we cannot have a
preview. It would also be very hard to show that for all groups in a
non-confusing way. We reuse the pbsPruneInputPanel and add the dry-run
field there conditionally.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/datastore/Content.js    | 34 ++++++++++++++++++++++++++++++++++
 www/window/DataStoreEdit.js | 15 +++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/www/datastore/Content.js b/www/datastore/Content.js
index ac8ae1cc..57693785 100644
--- a/www/datastore/Content.js
+++ b/www/datastore/Content.js
@@ -340,6 +340,35 @@ Ext.define('PBS.DataStoreContent', {
 	    });
 	},
 
+	pruneAll: function() {
+	    let me = this;
+	    let view = me.getView();
+
+	    if (!view.datastore) return;
+
+	    Ext.create('Proxmox.window.Edit', {
+		title: `Prune Datastore '${view.datastore}'`,
+		onlineHelp: 'maintenance_pruning',
+
+		method: 'POST',
+		submitText: "Prune",
+		autoShow: true,
+		isCreate: true,
+		showTaskViewer: true,
+
+		taskDone: () => me.reload(),
+
+		url: `/api2/extjs/admin/datastore/${view.datastore}/prune-datastore`,
+
+		items: [
+		    {
+			xtype: 'pbsPruneInputPanel',
+			dryrun: true,
+		    },
+		],
+	    });
+	},
+
 	onVerify: function(view, rI, cI, item, e, rec) {
 	    let me = this;
 	    view = me.getView();
@@ -865,6 +894,11 @@ Ext.define('PBS.DataStoreContent', {
 	    confirmMsg: gettext('Do you want to verify all snapshots now?'),
 	    handler: 'verifyAll',
 	},
+	{
+	    xtype: 'proxmoxButton',
+	    text: gettext('Prune All'),
+	    handler: 'pruneAll',
+	},
 	'->',
 	{
 	    xtype: 'tbtext',
diff --git a/www/window/DataStoreEdit.js b/www/window/DataStoreEdit.js
index fbf0da5b..ed23ad11 100644
--- a/www/window/DataStoreEdit.js
+++ b/www/window/DataStoreEdit.js
@@ -6,6 +6,9 @@ Ext.define('PBS.panel.PruneInputPanel', {
 
     onlineHelp: 'maintenance_pruning',
 
+    // show/hide dry-run field
+    dryrun: false,
+
     cbindData: function() {
 	let me = this;
 	me.isCreate = !!me.isCreate;
@@ -65,6 +68,18 @@ Ext.define('PBS.panel.PruneInputPanel', {
 	},
     ],
 
+    columnB: [
+	{
+	    xtype: 'proxmoxcheckbox',
+	    name: 'dry-run',
+	    fieldLabel: gettext('Dry Run'),
+	    cbind: {
+		hidden: '{!dryrun}',
+		disabled: '{!dryrun}',
+	    },
+	},
+    ],
+
 });
 Ext.define('PBS.DataStoreEdit', {
     extend: 'Proxmox.window.Edit',
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] [PATCH proxmox-backup 11/11] ui: datastore/Prune: improve title of group prune window
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (9 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 10/11] ui: datastore/Content: add 'Prune All' button Dominik Csapak
@ 2021-07-16  8:53 ` Dominik Csapak
  2021-07-16  9:48 ` [pbs-devel] applied: [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dietmar Maurer
  11 siblings, 0 replies; 13+ messages in thread
From: Dominik Csapak @ 2021-07-16  8:53 UTC (permalink / raw)
  To: pbs-devel

we are not actually pruning the whole datastore, but only the single
group, so set that as a title

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/datastore/Prune.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www/datastore/Prune.js b/www/datastore/Prune.js
index 10191679..3e74269f 100644
--- a/www/datastore/Prune.js
+++ b/www/datastore/Prune.js
@@ -251,7 +251,7 @@ Ext.define('PBS.DataStorePrune', {
 
 	Ext.apply(me, {
 	    url: '/api2/extjs/admin/datastore/' + me.datastore + "/prune",
-	    title: "Prune Datastore '" + me.datastore + "'",
+	    title: `Prune Group '${me.datastore}:${me.backup_type}/${me.backup_id}'`,
 	    items: [{
 		xtype: 'pbsDataStorePruneInputPanel',
 		url: '/api2/extjs/admin/datastore/' + me.datastore + "/prune",
-- 
2.30.2





^ permalink raw reply	[flat|nested] 13+ messages in thread

* [pbs-devel] applied: [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content
  2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
                   ` (10 preceding siblings ...)
  2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 11/11] ui: datastore/Prune: improve title of group prune window Dominik Csapak
@ 2021-07-16  9:48 ` Dietmar Maurer
  11 siblings, 0 replies; 13+ messages in thread
From: Dietmar Maurer @ 2021-07-16  9:48 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Dominik Csapak

applied

On 7/16/21 10:53 AM, Dominik Csapak wrote:
> similar to the 'verify all' button, it makes sense that a user can
> prune all groups (which he has access to) on demand with custom setings.
>
> this adds a new api call, since pruning all groups could take a while,
> depending on the number of groups snapshots, and it does not make sense
> to have that in a synchronous api call (that we already have per group),
> so modifying the existing api call to have the group optional was not
> really sensible IMHO.
>
> patches 1-6 are simply refactoring, to make it more easy to use
>   the PruneOptions, 'prune_datastore', etc. later
> 7,8 add new parameter/functionality to the 'prune_datastore' method
> 9 really adds the api call
> 10 is the button in the gui
> 11 is just a ui improvement for the other prune window
>   (could be applied seperately)
>
> Dominik Csapak (11):
>    api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types
>    pbs-datastore/prune: make PruneOptions an api type
>    client: simplify prune api method
>    api: admin/datastore: simplify prune api call
>    backup/datastore: refactor check_backup_owner there
>    server/prune_job: factor out 'prune_datastore'
>    server/prune_job: add 'keep_all' logic to 'prune_datastore'
>    server/prune_job: add proper permission checks to 'prune_datastore'
>    api: admin/datastore: add new 'prune-datastore' api call
>    ui: datastore/Content: add 'Prune All' button
>    ui: datastore/Prune: improve title of group prune window
>
>   pbs-api-types/src/lib.rs         |  30 +++++
>   pbs-datastore/src/prune.rs       |  50 +++++++-
>   src/api2/admin/datastore.rs      | 208 ++++++++++++++++---------------
>   src/api2/types/mod.rs            |  30 -----
>   src/backup/datastore.rs          |  20 +++
>   src/bin/proxmox-backup-client.rs |  95 +++++++-------
>   src/server/prune_job.rs          | 139 +++++++++++++--------
>   www/datastore/Content.js         |  34 +++++
>   www/datastore/Prune.js           |   2 +-
>   www/window/DataStoreEdit.js      |  15 +++
>   10 files changed, 390 insertions(+), 233 deletions(-)
>




^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-07-16  9:48 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-16  8:53 [pbs-devel] [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 01/11] api-types: move PRUNE_SCHEMA_KEEP_* to pbs-api-types Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 02/11] pbs-datastore/prune: make PruneOptions an api type Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 03/11] client: simplify prune api method Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 04/11] api: admin/datastore: simplify prune api call Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 05/11] backup/datastore: refactor check_backup_owner there Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 06/11] server/prune_job: factor out 'prune_datastore' Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 07/11] server/prune_job: add 'keep_all' logic to 'prune_datastore' Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 08/11] server/prune_job: add proper permission checks " Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 09/11] api: admin/datastore: add new 'prune-datastore' api call Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 10/11] ui: datastore/Content: add 'Prune All' button Dominik Csapak
2021-07-16  8:53 ` [pbs-devel] [PATCH proxmox-backup 11/11] ui: datastore/Prune: improve title of group prune window Dominik Csapak
2021-07-16  9:48 ` [pbs-devel] applied: [PATCH proxmox-backup 00/11] add 'prune all' button to datastore content Dietmar Maurer

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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal