all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pbs-devel] [PATCH proxmox-backup v2 0/4] improve datastore removal/creation
@ 2021-06-02 11:27 Dominik Csapak
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal Dominik Csapak
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Dominik Csapak @ 2021-06-02 11:27 UTC (permalink / raw)
  To: pbs-devel

by fixing the leftover datastore references
changing the api call that creates the datastore to use a worker
and shows a removal button in the gui

changes from v1:
* renamed one 'refresh_datstores' to 'notify_datastore_removed'
  (and the relevant command in the socket)
* changed the create api call to always use a worker,
  this makes it necessary to factor the creation code out, so that
  we can reuse it in /api2/node/disks/*.rs
* move the remove button from the datastore list to the
  datastore option view

Dominik Csapak (4):
  proxmox-backup-proxy: fix leftover references on datastore removal
  api2/config/datastore: change create datastore api call to a worker
  backup/chunk_store: optionally log progress on creation
  ui: DataStoreList: add remove button

 src/api2/config/datastore.rs     | 56 ++++++++++++++++++++++----------
 src/api2/node/disks/directory.rs | 15 +++++++--
 src/api2/node/disks/zfs.rs       | 14 +++++++-
 src/backup/chunk_store.rs        | 11 ++++---
 src/backup/datastore.rs          | 16 +++++++++
 src/bin/proxmox-backup-proxy.rs  | 11 +++++++
 src/server.rs                    |  8 +++++
 www/Utils.js                     |  1 +
 www/datastore/OptionView.js      | 30 +++++++++++++++++
 www/window/DataStoreEdit.js      |  1 +
 10 files changed, 139 insertions(+), 24 deletions(-)

-- 
2.20.1





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

* [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal
  2021-06-02 11:27 [pbs-devel] [PATCH proxmox-backup v2 0/4] improve datastore removal/creation Dominik Csapak
@ 2021-06-02 11:27 ` Dominik Csapak
  2021-06-04  6:24   ` Dietmar Maurer
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 2/4] api2/config/datastore: change create datastore api call to a worker Dominik Csapak
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Dominik Csapak @ 2021-06-02 11:27 UTC (permalink / raw)
  To: pbs-devel

when we remove a datastore via api/cli, the proxy
has sometimes leftover references to that datastore in its
DATASTORE_MAP which includes an open filehandle on the
'.lock' file

this prevents unmounting/exporting the datastore even after removal,
only a reload/restart of the proxy did help

add a command to our command socket, which removes all non
configured datastores from the map, dropping the open filehandle

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/config/datastore.rs    |  4 +++-
 src/backup/datastore.rs         | 16 ++++++++++++++++
 src/bin/proxmox-backup-proxy.rs | 11 +++++++++++
 src/server.rs                   |  8 ++++++++
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
index 6ca98b53..7299c91d 100644
--- a/src/api2/config/datastore.rs
+++ b/src/api2/config/datastore.rs
@@ -403,7 +403,7 @@ pub fn update_datastore(
     },
 )]
 /// Remove a datastore configuration.
-pub fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Error> {
+pub async fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Error> {
 
     let _lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
 
@@ -425,6 +425,8 @@ pub fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Erro
     let _ = jobstate::remove_state_file("prune", &name);
     let _ = jobstate::remove_state_file("garbage_collection", &name);
 
+    crate::server::notify_datastore_removed().await?;
+
     Ok(())
 }
 
diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs
index 584b2020..6989313d 100644
--- a/src/backup/datastore.rs
+++ b/src/backup/datastore.rs
@@ -69,6 +69,22 @@ impl DataStore {
         Ok(datastore)
     }
 
+    /// removes all datastores that are not configured anymore
+    pub fn refresh_datastores() -> Result<(), Error>{
+        let (config, _digest) = datastore::config()?;
+        let mut stores = HashSet::new();
+        for (store, _) in config.sections {
+            stores.insert(store);
+        }
+
+        let mut map = DATASTORE_MAP.lock().unwrap();
+        // removes all elements that are not in the config
+        map.retain(|key, _| {
+            stores.contains(key)
+        });
+        Ok(())
+    }
+
     fn open_with_path(store_name: &str, path: &Path, config: DataStoreConfig) -> Result<Self, Error> {
         let chunk_store = ChunkStore::open(store_name, path)?;
 
diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs
index a53f554a..75d40e21 100644
--- a/src/bin/proxmox-backup-proxy.rs
+++ b/src/bin/proxmox-backup-proxy.rs
@@ -136,6 +136,17 @@ async fn run() -> Result<(), Error> {
         },
     )?;
 
+    // to remove references for not configured datastores
+    commando_sock.register_command(
+        "datastore-removed".to_string(),
+        |_value| {
+            if let Err(err) = proxmox_backup::backup::DataStore::refresh_datastores() {
+                log::error!("could not refresh datastores: {}", err);
+            }
+            Ok(Value::Null)
+        }
+    )?;
+
     let server = daemon::create_daemon(
         ([0,0,0,0,0,0,0,0], 8007).into(),
         move |listener, ready| {
diff --git a/src/server.rs b/src/server.rs
index ba25617d..c4a36967 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -100,3 +100,11 @@ pub(crate) async fn reload_proxy_certificate() -> Result<(), Error> {
         .await?;
     Ok(())
 }
+
+pub(crate) async fn notify_datastore_removed() -> Result<(), Error> {
+    let proxy_pid = crate::server::read_pid(buildcfg::PROXMOX_BACKUP_PROXY_PID_FN)?;
+    let sock = crate::server::ctrl_sock_from_pid(proxy_pid);
+    let _: Value = crate::server::send_raw_command(sock, "{\"command\":\"datastore-removed\"}\n")
+        .await?;
+    Ok(())
+}
-- 
2.20.1





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

* [pbs-devel] [PATCH proxmox-backup v2 2/4] api2/config/datastore: change create datastore api call to a worker
  2021-06-02 11:27 [pbs-devel] [PATCH proxmox-backup v2 0/4] improve datastore removal/creation Dominik Csapak
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal Dominik Csapak
@ 2021-06-02 11:27 ` Dominik Csapak
  2021-06-04  7:07   ` [pbs-devel] applied: " Dietmar Maurer
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 3/4] backup/chunk_store: optionally log progress on creation Dominik Csapak
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 4/4] ui: DataStoreList: add remove button Dominik Csapak
  3 siblings, 1 reply; 9+ messages in thread
From: Dominik Csapak @ 2021-06-02 11:27 UTC (permalink / raw)
  To: pbs-devel

so that longer running creates (e.g. a slow storage), does not
run in a timeout and we can follow its creation

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/config/datastore.rs     | 51 ++++++++++++++++++++++----------
 src/api2/node/disks/directory.rs | 15 ++++++++--
 src/api2/node/disks/zfs.rs       | 14 ++++++++-
 www/window/DataStoreEdit.js      |  1 +
 4 files changed, 62 insertions(+), 19 deletions(-)

diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
index 7299c91d..4fa76b40 100644
--- a/src/api2/config/datastore.rs
+++ b/src/api2/config/datastore.rs
@@ -5,6 +5,7 @@ use serde_json::Value;
 use ::serde::{Deserialize, Serialize};
 
 use proxmox::api::{api, Router, RpcEnvironment, Permission};
+use proxmox::api::section_config::SectionConfigData;
 use proxmox::api::schema::parse_property_string;
 use proxmox::tools::fs::open_file_locked;
 
@@ -13,7 +14,7 @@ use crate::backup::*;
 use crate::config::cached_user_info::CachedUserInfo;
 use crate::config::datastore::{self, DataStoreConfig, DIR_NAME_SCHEMA};
 use crate::config::acl::{PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY};
-use crate::server::jobstate;
+use crate::server::{jobstate, WorkerTask};
 
 #[api(
     input: {
@@ -50,6 +51,25 @@ pub fn list_datastores(
     Ok(list.into_iter().filter(filter_by_privs).collect())
 }
 
+pub(crate) fn create_datastore_impl(
+    _lock: std::fs::File,
+    mut config: SectionConfigData,
+    datastore: DataStoreConfig,
+) -> Result<(), Error> {
+    let path: PathBuf = datastore.path.clone().into();
+
+    let backup_user = crate::backup::backup_user()?;
+    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
+
+    config.set_data(&datastore.name, "datastore", &datastore)?;
+
+    datastore::save_config(&config)?;
+
+    jobstate::create_state_file("prune", &datastore.name)?;
+    jobstate::create_state_file("garbage_collection", &datastore.name)?;
+
+    Ok(())
+}
 
 // fixme: impl. const fn get_object_schema(datastore::DataStoreConfig::API_SCHEMA),
 // but this need support for match inside const fn
@@ -116,31 +136,30 @@ pub fn list_datastores(
     },
 )]
 /// Create new datastore config.
-pub fn create_datastore(param: Value) -> Result<(), Error> {
+pub fn create_datastore(
+    param: Value,
+    rpcenv: &mut dyn RpcEnvironment,
+) -> Result<String, Error> {
 
-    let _lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
+    let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
 
     let datastore: datastore::DataStoreConfig = serde_json::from_value(param)?;
 
-    let (mut config, _digest) = datastore::config()?;
+    let (config, _digest) = datastore::config()?;
 
     if config.sections.get(&datastore.name).is_some() {
         bail!("datastore '{}' already exists.", datastore.name);
     }
 
-    let path: PathBuf = datastore.path.clone().into();
-
-    let backup_user = crate::backup::backup_user()?;
-    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
-
-    config.set_data(&datastore.name, "datastore", &datastore)?;
-
-    datastore::save_config(&config)?;
-
-    jobstate::create_state_file("prune", &datastore.name)?;
-    jobstate::create_state_file("garbage_collection", &datastore.name)?;
+    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
 
-    Ok(())
+    WorkerTask::new_thread(
+        "create-datastore",
+        Some(datastore.name.to_string()),
+        auth_id,
+        false,
+        move |_worker| create_datastore_impl(lock, config, datastore),
+    )
 }
 
 #[api(
diff --git a/src/api2/node/disks/directory.rs b/src/api2/node/disks/directory.rs
index c968b333..006e9522 100644
--- a/src/api2/node/disks/directory.rs
+++ b/src/api2/node/disks/directory.rs
@@ -5,6 +5,7 @@ use ::serde::{Deserialize, Serialize};
 use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType};
 use proxmox::api::section_config::SectionConfigData;
 use proxmox::api::router::Router;
+use proxmox::tools::fs::open_file_locked;
 
 use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
 use crate::tools::disks::{
@@ -16,7 +17,7 @@ use crate::tools::systemd::{self, types::*};
 use crate::server::WorkerTask;
 
 use crate::api2::types::*;
-use crate::config::datastore::DataStoreConfig;
+use crate::config::datastore::{self, DataStoreConfig};
 
 #[api(
     properties: {
@@ -179,7 +180,17 @@ pub fn create_datastore_disk(
             systemd::start_unit(&mount_unit_name)?;
 
             if add_datastore {
-                crate::api2::config::datastore::create_datastore(json!({ "name": name, "path": mount_point }))?
+                let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
+                let datastore: DataStoreConfig =
+                    serde_json::from_value(json!({ "name": name, "path": mount_point }))?;
+
+                let (config, _digest) = datastore::config()?;
+
+                if config.sections.get(&datastore.name).is_some() {
+                    bail!("datastore '{}' already exists.", datastore.name);
+                }
+
+                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
             }
 
             Ok(())
diff --git a/src/api2/node/disks/zfs.rs b/src/api2/node/disks/zfs.rs
index 0f93f110..ee8037e2 100644
--- a/src/api2/node/disks/zfs.rs
+++ b/src/api2/node/disks/zfs.rs
@@ -14,12 +14,14 @@ use proxmox::api::{
     },
 };
 use proxmox::api::router::Router;
+use proxmox::tools::fs::open_file_locked;
 
 use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
 use crate::tools::disks::{
     zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree,
     DiskUsageType,
 };
+use crate::config::datastore::{self, DataStoreConfig};
 
 use crate::server::WorkerTask;
 
@@ -372,7 +374,17 @@ pub fn create_zpool(
             }
 
             if add_datastore {
-                crate::api2::config::datastore::create_datastore(json!({ "name": name, "path": mount_point }))?
+                let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
+                let datastore: DataStoreConfig =
+                    serde_json::from_value(json!({ "name": name, "path": mount_point }))?;
+
+                let (config, _digest) = datastore::config()?;
+
+                if config.sections.get(&datastore.name).is_some() {
+                    bail!("datastore '{}' already exists.", datastore.name);
+                }
+
+                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
             }
 
             Ok(())
diff --git a/www/window/DataStoreEdit.js b/www/window/DataStoreEdit.js
index c2b2809f..2f67db76 100644
--- a/www/window/DataStoreEdit.js
+++ b/www/window/DataStoreEdit.js
@@ -75,6 +75,7 @@ Ext.define('PBS.DataStoreEdit', {
     isAdd: true,
 
     bodyPadding: 0,
+    showProgress: true,
 
     cbindData: function(initialConfig) {
 	var me = this;
-- 
2.20.1





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

* [pbs-devel] [PATCH proxmox-backup v2 3/4] backup/chunk_store: optionally log progress on creation
  2021-06-02 11:27 [pbs-devel] [PATCH proxmox-backup v2 0/4] improve datastore removal/creation Dominik Csapak
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal Dominik Csapak
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 2/4] api2/config/datastore: change create datastore api call to a worker Dominik Csapak
@ 2021-06-02 11:27 ` Dominik Csapak
  2021-06-04  7:40   ` [pbs-devel] applied: " Dietmar Maurer
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 4/4] ui: DataStoreList: add remove button Dominik Csapak
  3 siblings, 1 reply; 9+ messages in thread
From: Dominik Csapak @ 2021-06-02 11:27 UTC (permalink / raw)
  To: pbs-devel

and enable it for the worker variants

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/config/datastore.rs     |  5 +++--
 src/api2/node/disks/directory.rs |  2 +-
 src/api2/node/disks/zfs.rs       |  2 +-
 src/backup/chunk_store.rs        | 11 +++++++----
 4 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
index 4fa76b40..4e079cd5 100644
--- a/src/api2/config/datastore.rs
+++ b/src/api2/config/datastore.rs
@@ -55,11 +55,12 @@ pub(crate) fn create_datastore_impl(
     _lock: std::fs::File,
     mut config: SectionConfigData,
     datastore: DataStoreConfig,
+    worker: Option<&dyn crate::task::TaskState>,
 ) -> Result<(), Error> {
     let path: PathBuf = datastore.path.clone().into();
 
     let backup_user = crate::backup::backup_user()?;
-    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
+    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid, worker)?;
 
     config.set_data(&datastore.name, "datastore", &datastore)?;
 
@@ -158,7 +159,7 @@ pub fn create_datastore(
         Some(datastore.name.to_string()),
         auth_id,
         false,
-        move |_worker| create_datastore_impl(lock, config, datastore),
+        move |worker| create_datastore_impl(lock, config, datastore, Some(&worker)),
     )
 }
 
diff --git a/src/api2/node/disks/directory.rs b/src/api2/node/disks/directory.rs
index 006e9522..4eadf867 100644
--- a/src/api2/node/disks/directory.rs
+++ b/src/api2/node/disks/directory.rs
@@ -190,7 +190,7 @@ pub fn create_datastore_disk(
                     bail!("datastore '{}' already exists.", datastore.name);
                 }
 
-                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
+                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore, Some(&worker))?;
             }
 
             Ok(())
diff --git a/src/api2/node/disks/zfs.rs b/src/api2/node/disks/zfs.rs
index ee8037e2..ebdc3688 100644
--- a/src/api2/node/disks/zfs.rs
+++ b/src/api2/node/disks/zfs.rs
@@ -384,7 +384,7 @@ pub fn create_zpool(
                     bail!("datastore '{}' already exists.", datastore.name);
                 }
 
-                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
+                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore, Some(&worker))?;
             }
 
             Ok(())
diff --git a/src/backup/chunk_store.rs b/src/backup/chunk_store.rs
index 31e8307c..e9cc3897 100644
--- a/src/backup/chunk_store.rs
+++ b/src/backup/chunk_store.rs
@@ -7,6 +7,7 @@ use std::os::unix::io::AsRawFd;
 
 use proxmox::tools::fs::{CreateOptions, create_path, create_dir};
 
+use crate::task_log;
 use crate::tools;
 use crate::api2::types::GarbageCollectionStatus;
 
@@ -61,7 +62,7 @@ impl ChunkStore {
         chunk_dir
     }
 
-    pub fn create<P>(name: &str, path: P, uid: nix::unistd::Uid, gid: nix::unistd::Gid) -> Result<Self, Error>
+    pub fn create<P>(name: &str, path: P, uid: nix::unistd::Uid, gid: nix::unistd::Gid, worker: Option<&dyn TaskState>) -> Result<Self, Error>
     where
         P: Into<PathBuf>,
     {
@@ -104,7 +105,9 @@ impl ChunkStore {
             }
             let percentage = (i*100)/(64*1024);
             if percentage != last_percentage {
-                // eprintln!("ChunkStore::create {}%", percentage);
+                if let Some(worker) = worker {
+                    task_log!(worker, "Chunkstore create: {}%", percentage)
+                }
                 last_percentage = percentage;
             }
         }
@@ -461,7 +464,7 @@ fn test_chunk_store1() {
     assert!(chunk_store.is_err());
 
     let user = nix::unistd::User::from_uid(nix::unistd::Uid::current()).unwrap().unwrap();
-    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid).unwrap();
+    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid, None).unwrap();
 
     let (chunk, digest) = super::DataChunkBuilder::new(&[0u8, 1u8]).build().unwrap();
 
@@ -472,7 +475,7 @@ fn test_chunk_store1() {
     assert!(exists);
 
 
-    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid);
+    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid, None);
     assert!(chunk_store.is_err());
 
     if let Err(_e) = std::fs::remove_dir_all(".testdir") { /* ignore */ }
-- 
2.20.1





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

* [pbs-devel] [PATCH proxmox-backup v2 4/4] ui: DataStoreList: add remove button
  2021-06-02 11:27 [pbs-devel] [PATCH proxmox-backup v2 0/4] improve datastore removal/creation Dominik Csapak
                   ` (2 preceding siblings ...)
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 3/4] backup/chunk_store: optionally log progress on creation Dominik Csapak
@ 2021-06-02 11:27 ` Dominik Csapak
  2021-06-04  7:52   ` [pbs-devel] applied: " Dietmar Maurer
  3 siblings, 1 reply; 9+ messages in thread
From: Dominik Csapak @ 2021-06-02 11:27 UTC (permalink / raw)
  To: pbs-devel

so that a user can remove a datastore from the gui,
though no data is deleted, this has to be done elsewhere (for now)

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/Utils.js                |  1 +
 www/datastore/OptionView.js | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/www/Utils.js b/www/Utils.js
index f614d77e..6b378355 100644
--- a/www/Utils.js
+++ b/www/Utils.js
@@ -380,6 +380,7 @@ Ext.define('PBS.Utils', {
 	    backup: (type, id) => PBS.Utils.render_datastore_worker_id(id, gettext('Backup')),
 	    'barcode-label-media': [gettext('Drive'), gettext('Barcode-Label Media')],
 	    'catalog-media': [gettext('Drive'), gettext('Catalog Media')],
+	    'delete-datastore': [gettext('Datastore'), gettext('Remove Datastore')],
 	    dircreate: [gettext('Directory Storage'), gettext('Create')],
 	    dirremove: [gettext('Directory'), gettext('Remove')],
 	    'eject-media': [gettext('Drive'), gettext('Eject Media')],
diff --git a/www/datastore/OptionView.js b/www/datastore/OptionView.js
index 723730fd..98152dce 100644
--- a/www/datastore/OptionView.js
+++ b/www/datastore/OptionView.js
@@ -21,6 +21,28 @@ Ext.define('PBS.Datastore.Options', {
 	edit: function() {
 	    this.getView().run_editor();
 	},
+
+	removeDatastore: function() {
+	    let me = this;
+	    let datastore = me.getView().datastore;
+	    Ext.create('Proxmox.window.SafeDestroy', {
+		url: `/config/datastore/${datastore}`,
+		item: {
+		    id: datastore,
+		},
+		note: gettext('Configuration change only, no data will be deleted.'),
+		autoShow: true,
+		taskName: 'delete-datastore',
+		listeners: {
+		    destroy: () => {
+			let navtree = Ext.ComponentQuery.query('navigationtree')[0];
+			navtree.rstore.load();
+			let mainview = me.getView().up('mainview');
+			mainview.getController().redirectTo('pbsDataStores');
+		    },
+		},
+	    });
+	},
     },
 
     tbar: [
@@ -30,6 +52,14 @@ Ext.define('PBS.Datastore.Options', {
 	    disabled: true,
 	    handler: 'edit',
 	},
+	'->',
+	{
+	    xtype: 'proxmoxButton',
+	    selModel: null,
+	    iconCls: 'fa fa-trash-o',
+	    text: gettext('Remove Datastore'),
+	    handler: 'removeDatastore',
+	},
     ],
 
     listeners: {
-- 
2.20.1





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

* Re: [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal Dominik Csapak
@ 2021-06-04  6:24   ` Dietmar Maurer
  0 siblings, 0 replies; 9+ messages in thread
From: Dietmar Maurer @ 2021-06-04  6:24 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Dominik Csapak

applied with small modifications

- simplify refresh_datastores (as suggested by Thomas)

- rename  refresh_datastores to remove_unused_datastores

On 6/2/21 1:27 PM, Dominik Csapak wrote:
> when we remove a datastore via api/cli, the proxy
> has sometimes leftover references to that datastore in its
> DATASTORE_MAP which includes an open filehandle on the
> '.lock' file
>
> this prevents unmounting/exporting the datastore even after removal,
> only a reload/restart of the proxy did help
>
> add a command to our command socket, which removes all non
> configured datastores from the map, dropping the open filehandle
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
>   src/api2/config/datastore.rs    |  4 +++-
>   src/backup/datastore.rs         | 16 ++++++++++++++++
>   src/bin/proxmox-backup-proxy.rs | 11 +++++++++++
>   src/server.rs                   |  8 ++++++++
>   4 files changed, 38 insertions(+), 1 deletion(-)
>
> diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
> index 6ca98b53..7299c91d 100644
> --- a/src/api2/config/datastore.rs
> +++ b/src/api2/config/datastore.rs
> @@ -403,7 +403,7 @@ pub fn update_datastore(
>       },
>   )]
>   /// Remove a datastore configuration.
> -pub fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Error> {
> +pub async fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Error> {
>   
>       let _lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
>   
> @@ -425,6 +425,8 @@ pub fn delete_datastore(name: String, digest: Option<String>) -> Result<(), Erro
>       let _ = jobstate::remove_state_file("prune", &name);
>       let _ = jobstate::remove_state_file("garbage_collection", &name);
>   
> +    crate::server::notify_datastore_removed().await?;
> +
>       Ok(())
>   }
>   
> diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs
> index 584b2020..6989313d 100644
> --- a/src/backup/datastore.rs
> +++ b/src/backup/datastore.rs
> @@ -69,6 +69,22 @@ impl DataStore {
>           Ok(datastore)
>       }
>   
> +    /// removes all datastores that are not configured anymore
> +    pub fn refresh_datastores() -> Result<(), Error>{
> +        let (config, _digest) = datastore::config()?;
> +        let mut stores = HashSet::new();
> +        for (store, _) in config.sections {
> +            stores.insert(store);
> +        }
> +
> +        let mut map = DATASTORE_MAP.lock().unwrap();
> +        // removes all elements that are not in the config
> +        map.retain(|key, _| {
> +            stores.contains(key)
> +        });
> +        Ok(())
> +    }
> +
>       fn open_with_path(store_name: &str, path: &Path, config: DataStoreConfig) -> Result<Self, Error> {
>           let chunk_store = ChunkStore::open(store_name, path)?;
>   
> diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs
> index a53f554a..75d40e21 100644
> --- a/src/bin/proxmox-backup-proxy.rs
> +++ b/src/bin/proxmox-backup-proxy.rs
> @@ -136,6 +136,17 @@ async fn run() -> Result<(), Error> {
>           },
>       )?;
>   
> +    // to remove references for not configured datastores
> +    commando_sock.register_command(
> +        "datastore-removed".to_string(),
> +        |_value| {
> +            if let Err(err) = proxmox_backup::backup::DataStore::refresh_datastores() {
> +                log::error!("could not refresh datastores: {}", err);
> +            }
> +            Ok(Value::Null)
> +        }
> +    )?;
> +
>       let server = daemon::create_daemon(
>           ([0,0,0,0,0,0,0,0], 8007).into(),
>           move |listener, ready| {
> diff --git a/src/server.rs b/src/server.rs
> index ba25617d..c4a36967 100644
> --- a/src/server.rs
> +++ b/src/server.rs
> @@ -100,3 +100,11 @@ pub(crate) async fn reload_proxy_certificate() -> Result<(), Error> {
>           .await?;
>       Ok(())
>   }
> +
> +pub(crate) async fn notify_datastore_removed() -> Result<(), Error> {
> +    let proxy_pid = crate::server::read_pid(buildcfg::PROXMOX_BACKUP_PROXY_PID_FN)?;
> +    let sock = crate::server::ctrl_sock_from_pid(proxy_pid);
> +    let _: Value = crate::server::send_raw_command(sock, "{\"command\":\"datastore-removed\"}\n")
> +        .await?;
> +    Ok(())
> +}




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

* [pbs-devel] applied: [PATCH proxmox-backup v2 2/4] api2/config/datastore: change create datastore api call to a worker
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 2/4] api2/config/datastore: change create datastore api call to a worker Dominik Csapak
@ 2021-06-04  7:07   ` Dietmar Maurer
  0 siblings, 0 replies; 9+ messages in thread
From: Dietmar Maurer @ 2021-06-04  7:07 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Dominik Csapak

applied with additional cleanups:

- rename create_datastore_impl to do_create_datastore

- factor out the datastore config lock function

On 6/2/21 1:27 PM, Dominik Csapak wrote:
> so that longer running creates (e.g. a slow storage), does not
> run in a timeout and we can follow its creation
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
>   src/api2/config/datastore.rs     | 51 ++++++++++++++++++++++----------
>   src/api2/node/disks/directory.rs | 15 ++++++++--
>   src/api2/node/disks/zfs.rs       | 14 ++++++++-
>   www/window/DataStoreEdit.js      |  1 +
>   4 files changed, 62 insertions(+), 19 deletions(-)
>
> diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
> index 7299c91d..4fa76b40 100644
> --- a/src/api2/config/datastore.rs
> +++ b/src/api2/config/datastore.rs
> @@ -5,6 +5,7 @@ use serde_json::Value;
>   use ::serde::{Deserialize, Serialize};
>   
>   use proxmox::api::{api, Router, RpcEnvironment, Permission};
> +use proxmox::api::section_config::SectionConfigData;
>   use proxmox::api::schema::parse_property_string;
>   use proxmox::tools::fs::open_file_locked;
>   
> @@ -13,7 +14,7 @@ use crate::backup::*;
>   use crate::config::cached_user_info::CachedUserInfo;
>   use crate::config::datastore::{self, DataStoreConfig, DIR_NAME_SCHEMA};
>   use crate::config::acl::{PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY};
> -use crate::server::jobstate;
> +use crate::server::{jobstate, WorkerTask};
>   
>   #[api(
>       input: {
> @@ -50,6 +51,25 @@ pub fn list_datastores(
>       Ok(list.into_iter().filter(filter_by_privs).collect())
>   }
>   
> +pub(crate) fn create_datastore_impl(
> +    _lock: std::fs::File,
> +    mut config: SectionConfigData,
> +    datastore: DataStoreConfig,
> +) -> Result<(), Error> {
> +    let path: PathBuf = datastore.path.clone().into();
> +
> +    let backup_user = crate::backup::backup_user()?;
> +    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
> +
> +    config.set_data(&datastore.name, "datastore", &datastore)?;
> +
> +    datastore::save_config(&config)?;
> +
> +    jobstate::create_state_file("prune", &datastore.name)?;
> +    jobstate::create_state_file("garbage_collection", &datastore.name)?;
> +
> +    Ok(())
> +}
>   
>   // fixme: impl. const fn get_object_schema(datastore::DataStoreConfig::API_SCHEMA),
>   // but this need support for match inside const fn
> @@ -116,31 +136,30 @@ pub fn list_datastores(
>       },
>   )]
>   /// Create new datastore config.
> -pub fn create_datastore(param: Value) -> Result<(), Error> {
> +pub fn create_datastore(
> +    param: Value,
> +    rpcenv: &mut dyn RpcEnvironment,
> +) -> Result<String, Error> {
>   
> -    let _lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
> +    let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
>   
>       let datastore: datastore::DataStoreConfig = serde_json::from_value(param)?;
>   
> -    let (mut config, _digest) = datastore::config()?;
> +    let (config, _digest) = datastore::config()?;
>   
>       if config.sections.get(&datastore.name).is_some() {
>           bail!("datastore '{}' already exists.", datastore.name);
>       }
>   
> -    let path: PathBuf = datastore.path.clone().into();
> -
> -    let backup_user = crate::backup::backup_user()?;
> -    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
> -
> -    config.set_data(&datastore.name, "datastore", &datastore)?;
> -
> -    datastore::save_config(&config)?;
> -
> -    jobstate::create_state_file("prune", &datastore.name)?;
> -    jobstate::create_state_file("garbage_collection", &datastore.name)?;
> +    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
>   
> -    Ok(())
> +    WorkerTask::new_thread(
> +        "create-datastore",
> +        Some(datastore.name.to_string()),
> +        auth_id,
> +        false,
> +        move |_worker| create_datastore_impl(lock, config, datastore),
> +    )
>   }
>   
>   #[api(
> diff --git a/src/api2/node/disks/directory.rs b/src/api2/node/disks/directory.rs
> index c968b333..006e9522 100644
> --- a/src/api2/node/disks/directory.rs
> +++ b/src/api2/node/disks/directory.rs
> @@ -5,6 +5,7 @@ use ::serde::{Deserialize, Serialize};
>   use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType};
>   use proxmox::api::section_config::SectionConfigData;
>   use proxmox::api::router::Router;
> +use proxmox::tools::fs::open_file_locked;
>   
>   use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
>   use crate::tools::disks::{
> @@ -16,7 +17,7 @@ use crate::tools::systemd::{self, types::*};
>   use crate::server::WorkerTask;
>   
>   use crate::api2::types::*;
> -use crate::config::datastore::DataStoreConfig;
> +use crate::config::datastore::{self, DataStoreConfig};
>   
>   #[api(
>       properties: {
> @@ -179,7 +180,17 @@ pub fn create_datastore_disk(
>               systemd::start_unit(&mount_unit_name)?;
>   
>               if add_datastore {
> -                crate::api2::config::datastore::create_datastore(json!({ "name": name, "path": mount_point }))?
> +                let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
> +                let datastore: DataStoreConfig =
> +                    serde_json::from_value(json!({ "name": name, "path": mount_point }))?;
> +
> +                let (config, _digest) = datastore::config()?;
> +
> +                if config.sections.get(&datastore.name).is_some() {
> +                    bail!("datastore '{}' already exists.", datastore.name);
> +                }
> +
> +                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
>               }
>   
>               Ok(())
> diff --git a/src/api2/node/disks/zfs.rs b/src/api2/node/disks/zfs.rs
> index 0f93f110..ee8037e2 100644
> --- a/src/api2/node/disks/zfs.rs
> +++ b/src/api2/node/disks/zfs.rs
> @@ -14,12 +14,14 @@ use proxmox::api::{
>       },
>   };
>   use proxmox::api::router::Router;
> +use proxmox::tools::fs::open_file_locked;
>   
>   use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
>   use crate::tools::disks::{
>       zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree,
>       DiskUsageType,
>   };
> +use crate::config::datastore::{self, DataStoreConfig};
>   
>   use crate::server::WorkerTask;
>   
> @@ -372,7 +374,17 @@ pub fn create_zpool(
>               }
>   
>               if add_datastore {
> -                crate::api2::config::datastore::create_datastore(json!({ "name": name, "path": mount_point }))?
> +                let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?;
> +                let datastore: DataStoreConfig =
> +                    serde_json::from_value(json!({ "name": name, "path": mount_point }))?;
> +
> +                let (config, _digest) = datastore::config()?;
> +
> +                if config.sections.get(&datastore.name).is_some() {
> +                    bail!("datastore '{}' already exists.", datastore.name);
> +                }
> +
> +                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
>               }
>   
>               Ok(())
> diff --git a/www/window/DataStoreEdit.js b/www/window/DataStoreEdit.js
> index c2b2809f..2f67db76 100644
> --- a/www/window/DataStoreEdit.js
> +++ b/www/window/DataStoreEdit.js
> @@ -75,6 +75,7 @@ Ext.define('PBS.DataStoreEdit', {
>       isAdd: true,
>   
>       bodyPadding: 0,
> +    showProgress: true,
>   
>       cbindData: function(initialConfig) {
>   	var me = this;




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

* [pbs-devel] applied: [PATCH proxmox-backup v2 3/4] backup/chunk_store: optionally log progress on creation
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 3/4] backup/chunk_store: optionally log progress on creation Dominik Csapak
@ 2021-06-04  7:40   ` Dietmar Maurer
  0 siblings, 0 replies; 9+ messages in thread
From: Dietmar Maurer @ 2021-06-04  7:40 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Dominik Csapak

applied

On 6/2/21 1:27 PM, Dominik Csapak wrote:
> and enable it for the worker variants
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
>   src/api2/config/datastore.rs     |  5 +++--
>   src/api2/node/disks/directory.rs |  2 +-
>   src/api2/node/disks/zfs.rs       |  2 +-
>   src/backup/chunk_store.rs        | 11 +++++++----
>   4 files changed, 12 insertions(+), 8 deletions(-)
>
> diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs
> index 4fa76b40..4e079cd5 100644
> --- a/src/api2/config/datastore.rs
> +++ b/src/api2/config/datastore.rs
> @@ -55,11 +55,12 @@ pub(crate) fn create_datastore_impl(
>       _lock: std::fs::File,
>       mut config: SectionConfigData,
>       datastore: DataStoreConfig,
> +    worker: Option<&dyn crate::task::TaskState>,
>   ) -> Result<(), Error> {
>       let path: PathBuf = datastore.path.clone().into();
>   
>       let backup_user = crate::backup::backup_user()?;
> -    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
> +    let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid, worker)?;
>   
>       config.set_data(&datastore.name, "datastore", &datastore)?;
>   
> @@ -158,7 +159,7 @@ pub fn create_datastore(
>           Some(datastore.name.to_string()),
>           auth_id,
>           false,
> -        move |_worker| create_datastore_impl(lock, config, datastore),
> +        move |worker| create_datastore_impl(lock, config, datastore, Some(&worker)),
>       )
>   }
>   
> diff --git a/src/api2/node/disks/directory.rs b/src/api2/node/disks/directory.rs
> index 006e9522..4eadf867 100644
> --- a/src/api2/node/disks/directory.rs
> +++ b/src/api2/node/disks/directory.rs
> @@ -190,7 +190,7 @@ pub fn create_datastore_disk(
>                       bail!("datastore '{}' already exists.", datastore.name);
>                   }
>   
> -                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
> +                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore, Some(&worker))?;
>               }
>   
>               Ok(())
> diff --git a/src/api2/node/disks/zfs.rs b/src/api2/node/disks/zfs.rs
> index ee8037e2..ebdc3688 100644
> --- a/src/api2/node/disks/zfs.rs
> +++ b/src/api2/node/disks/zfs.rs
> @@ -384,7 +384,7 @@ pub fn create_zpool(
>                       bail!("datastore '{}' already exists.", datastore.name);
>                   }
>   
> -                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?;
> +                crate::api2::config::datastore::create_datastore_impl(lock, config, datastore, Some(&worker))?;
>               }
>   
>               Ok(())
> diff --git a/src/backup/chunk_store.rs b/src/backup/chunk_store.rs
> index 31e8307c..e9cc3897 100644
> --- a/src/backup/chunk_store.rs
> +++ b/src/backup/chunk_store.rs
> @@ -7,6 +7,7 @@ use std::os::unix::io::AsRawFd;
>   
>   use proxmox::tools::fs::{CreateOptions, create_path, create_dir};
>   
> +use crate::task_log;
>   use crate::tools;
>   use crate::api2::types::GarbageCollectionStatus;
>   
> @@ -61,7 +62,7 @@ impl ChunkStore {
>           chunk_dir
>       }
>   
> -    pub fn create<P>(name: &str, path: P, uid: nix::unistd::Uid, gid: nix::unistd::Gid) -> Result<Self, Error>
> +    pub fn create<P>(name: &str, path: P, uid: nix::unistd::Uid, gid: nix::unistd::Gid, worker: Option<&dyn TaskState>) -> Result<Self, Error>
>       where
>           P: Into<PathBuf>,
>       {
> @@ -104,7 +105,9 @@ impl ChunkStore {
>               }
>               let percentage = (i*100)/(64*1024);
>               if percentage != last_percentage {
> -                // eprintln!("ChunkStore::create {}%", percentage);
> +                if let Some(worker) = worker {
> +                    task_log!(worker, "Chunkstore create: {}%", percentage)
> +                }
>                   last_percentage = percentage;
>               }
>           }
> @@ -461,7 +464,7 @@ fn test_chunk_store1() {
>       assert!(chunk_store.is_err());
>   
>       let user = nix::unistd::User::from_uid(nix::unistd::Uid::current()).unwrap().unwrap();
> -    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid).unwrap();
> +    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid, None).unwrap();
>   
>       let (chunk, digest) = super::DataChunkBuilder::new(&[0u8, 1u8]).build().unwrap();
>   
> @@ -472,7 +475,7 @@ fn test_chunk_store1() {
>       assert!(exists);
>   
>   
> -    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid);
> +    let chunk_store = ChunkStore::create("test", &path, user.uid, user.gid, None);
>       assert!(chunk_store.is_err());
>   
>       if let Err(_e) = std::fs::remove_dir_all(".testdir") { /* ignore */ }




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

* [pbs-devel] applied: [PATCH proxmox-backup v2 4/4] ui: DataStoreList: add remove button
  2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 4/4] ui: DataStoreList: add remove button Dominik Csapak
@ 2021-06-04  7:52   ` Dietmar Maurer
  0 siblings, 0 replies; 9+ messages in thread
From: Dietmar Maurer @ 2021-06-04  7:52 UTC (permalink / raw)
  To: Proxmox Backup Server development discussion, Dominik Csapak

applied

On 6/2/21 1:27 PM, Dominik Csapak wrote:
> so that a user can remove a datastore from the gui,
> though no data is deleted, this has to be done elsewhere (for now)
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
>   www/Utils.js                |  1 +
>   www/datastore/OptionView.js | 30 ++++++++++++++++++++++++++++++
>   2 files changed, 31 insertions(+)
>
> diff --git a/www/Utils.js b/www/Utils.js
> index f614d77e..6b378355 100644
> --- a/www/Utils.js
> +++ b/www/Utils.js
> @@ -380,6 +380,7 @@ Ext.define('PBS.Utils', {
>   	    backup: (type, id) => PBS.Utils.render_datastore_worker_id(id, gettext('Backup')),
>   	    'barcode-label-media': [gettext('Drive'), gettext('Barcode-Label Media')],
>   	    'catalog-media': [gettext('Drive'), gettext('Catalog Media')],
> +	    'delete-datastore': [gettext('Datastore'), gettext('Remove Datastore')],
>   	    dircreate: [gettext('Directory Storage'), gettext('Create')],
>   	    dirremove: [gettext('Directory'), gettext('Remove')],
>   	    'eject-media': [gettext('Drive'), gettext('Eject Media')],
> diff --git a/www/datastore/OptionView.js b/www/datastore/OptionView.js
> index 723730fd..98152dce 100644
> --- a/www/datastore/OptionView.js
> +++ b/www/datastore/OptionView.js
> @@ -21,6 +21,28 @@ Ext.define('PBS.Datastore.Options', {
>   	edit: function() {
>   	    this.getView().run_editor();
>   	},
> +
> +	removeDatastore: function() {
> +	    let me = this;
> +	    let datastore = me.getView().datastore;
> +	    Ext.create('Proxmox.window.SafeDestroy', {
> +		url: `/config/datastore/${datastore}`,
> +		item: {
> +		    id: datastore,
> +		},
> +		note: gettext('Configuration change only, no data will be deleted.'),
> +		autoShow: true,
> +		taskName: 'delete-datastore',
> +		listeners: {
> +		    destroy: () => {
> +			let navtree = Ext.ComponentQuery.query('navigationtree')[0];
> +			navtree.rstore.load();
> +			let mainview = me.getView().up('mainview');
> +			mainview.getController().redirectTo('pbsDataStores');
> +		    },
> +		},
> +	    });
> +	},
>       },
>   
>       tbar: [
> @@ -30,6 +52,14 @@ Ext.define('PBS.Datastore.Options', {
>   	    disabled: true,
>   	    handler: 'edit',
>   	},
> +	'->',
> +	{
> +	    xtype: 'proxmoxButton',
> +	    selModel: null,
> +	    iconCls: 'fa fa-trash-o',
> +	    text: gettext('Remove Datastore'),
> +	    handler: 'removeDatastore',
> +	},
>       ],
>   
>       listeners: {




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

end of thread, other threads:[~2021-06-04  7:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-02 11:27 [pbs-devel] [PATCH proxmox-backup v2 0/4] improve datastore removal/creation Dominik Csapak
2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 1/4] proxmox-backup-proxy: fix leftover references on datastore removal Dominik Csapak
2021-06-04  6:24   ` Dietmar Maurer
2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 2/4] api2/config/datastore: change create datastore api call to a worker Dominik Csapak
2021-06-04  7:07   ` [pbs-devel] applied: " Dietmar Maurer
2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 3/4] backup/chunk_store: optionally log progress on creation Dominik Csapak
2021-06-04  7:40   ` [pbs-devel] applied: " Dietmar Maurer
2021-06-02 11:27 ` [pbs-devel] [PATCH proxmox-backup v2 4/4] ui: DataStoreList: add remove button Dominik Csapak
2021-06-04  7:52   ` [pbs-devel] applied: " 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