From: Hannes Laimer <h.laimer@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v9 07/26] api: admin: add (un)mount endpoint for removable datastores
Date: Tue, 23 Apr 2024 10:29:41 +0200 [thread overview]
Message-ID: <20240423083000.28002-8-h.laimer@proxmox.com> (raw)
In-Reply-To: <20240423083000.28002-1-h.laimer@proxmox.com>
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
pbs-api-types/src/maintenance.rs | 4 +
src/api2/admin/datastore.rs | 187 +++++++++++++++++++++++++++++--
2 files changed, 181 insertions(+), 10 deletions(-)
diff --git a/pbs-api-types/src/maintenance.rs b/pbs-api-types/src/maintenance.rs
index 4f653ec7..469dc25d 100644
--- a/pbs-api-types/src/maintenance.rs
+++ b/pbs-api-types/src/maintenance.rs
@@ -78,6 +78,10 @@ pub struct MaintenanceMode {
}
impl MaintenanceMode {
+ pub fn new(ty: MaintenanceType, message: Option<String>) -> Self {
+ Self { ty, message }
+ }
+
/// Used for deciding whether the datastore is cleared from the internal cache after the last
/// task finishes, so all open files are closed.
pub fn is_offline(&self) -> bool {
diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 35628c59..fd26f0db 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -26,20 +26,21 @@ use proxmox_sortable_macro::sortable;
use proxmox_sys::fs::{
file_read_firstline, file_read_optional_string, replace_file, CreateOptions,
};
-use proxmox_sys::{task_log, task_warn};
+use proxmox_sys::{task_log, task_warn, WorkerTaskContext};
use pxar::accessor::aio::Accessor;
use pxar::EntryKind;
use pbs_api_types::{
print_ns_and_snapshot, print_store_and_ns, Authid, BackupContent, BackupNamespace, BackupType,
- Counts, CryptMode, DataStoreListItem, DataStoreStatus, GarbageCollectionStatus, GroupListItem,
- KeepOptions, Operation, PruneJobOptions, RRDMode, RRDTimeFrame, SnapshotListItem,
- SnapshotVerifyState, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA,
- BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA,
- MAX_NAMESPACE_DEPTH, NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
- PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY,
- UPID_SCHEMA, VERIFICATION_OUTDATED_AFTER_SCHEMA,
+ Counts, CryptMode, DataStoreConfig, DataStoreListItem, DataStoreStatus,
+ GarbageCollectionStatus, GroupListItem, KeepOptions, MaintenanceMode, MaintenanceType,
+ Operation, PruneJobOptions, RRDMode, RRDTimeFrame, SnapshotListItem, SnapshotVerifyState,
+ BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA,
+ BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA, IGNORE_VERIFIED_BACKUPS_SCHEMA, MAX_NAMESPACE_DEPTH,
+ NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY,
+ PRIV_DATASTORE_PRUNE, PRIV_DATASTORE_READ, PRIV_DATASTORE_VERIFY, UPID_SCHEMA,
+ VERIFICATION_OUTDATED_AFTER_SCHEMA,
};
use pbs_client::pxar::{create_tar, create_zip};
use pbs_config::CachedUserInfo;
@@ -54,8 +55,8 @@ use pbs_datastore::index::IndexFile;
use pbs_datastore::manifest::{BackupManifest, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME};
use pbs_datastore::prune::compute_prune_info;
use pbs_datastore::{
- check_backup_owner, task_tracking, BackupDir, BackupGroup, DataStore, LocalChunkReader,
- StoreProgress, CATALOG_NAME,
+ check_backup_owner, is_datastore_available, task_tracking, BackupDir, BackupGroup, DataStore,
+ LocalChunkReader, StoreProgress, CATALOG_NAME,
};
use pbs_tools::json::required_string_param;
use proxmox_rest_server::{formatter, WorkerTask};
@@ -2278,6 +2279,170 @@ pub async fn set_backup_owner(
.await?
}
+pub fn do_mount_device(
+ datastore: DataStoreConfig,
+ worker: Option<&dyn WorkerTaskContext>,
+) -> Result<(), Error> {
+ if let (Some(uuid), Some(mount_point)) = (
+ datastore.backing_device.as_ref(),
+ datastore.get_mount_point(),
+ ) {
+ if pbs_datastore::is_datastore_available(&datastore) {
+ bail!("device '{uuid}' is already mounted");
+ }
+ let mount_point_path = std::path::Path::new(&mount_point);
+ if let Some(worker) = worker {
+ task_log!(
+ worker,
+ "mounting '{uuid}' for store {} to '{mount_point}'",
+ datastore.name,
+ );
+ }
+ crate::tools::disks::mount_by_uuid(uuid, mount_point_path)?;
+
+ Ok(())
+ } else {
+ Err(format_err!(
+ "Datastore '{}' cannot be mounted because it is not removable.",
+ datastore.name
+ ))
+ }
+}
+
+#[api(
+ protected: true,
+ input: {
+ properties: {
+ store: {
+ schema: DATASTORE_SCHEMA,
+ },
+ }
+ },
+ returns: {
+ schema: UPID_SCHEMA,
+ },
+ access: {
+ permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_AUDIT, false),
+ },
+)]
+/// Mount removable datastore.
+pub fn mount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
+ let (section_config, _digest) = pbs_config::datastore::config()?;
+ let datastore: DataStoreConfig = section_config.lookup("datastore", &store)?;
+
+ if datastore.backing_device.is_none() {
+ bail!("datastore '{store}' is not removable");
+ }
+
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+ let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
+
+ let upid = WorkerTask::new_thread(
+ "mount-device",
+ Some(store),
+ auth_id.to_string(),
+ to_stdout,
+ move |worker| do_mount_device(datastore, Some(&worker)),
+ )?;
+
+ Ok(json!(upid))
+}
+
+fn do_unmount_device(
+ datastore: DataStoreConfig,
+ worker: Option<&dyn WorkerTaskContext>,
+) -> Result<(), Error> {
+ let mut active_operations = task_tracking::get_active_operations(&datastore.name)?;
+ let mut old_status = String::new();
+ while active_operations.read + active_operations.write > 0 {
+ if let Some(worker) = worker {
+ if worker.abort_requested() {
+ bail!("aborted, due to user request");
+ }
+ let status = format!(
+ "cannot unmount yet, still {} read and {} write operations active",
+ active_operations.read, active_operations.write
+ );
+ if status != old_status {
+ task_log!(worker, "{status}");
+ old_status = status;
+ }
+ }
+ std::thread::sleep(std::time::Duration::from_millis(250));
+ active_operations = task_tracking::get_active_operations(&datastore.name)?;
+ }
+ if let Some(mount_point) = datastore.get_mount_point() {
+ crate::tools::disks::unmount_by_mountpoint(&mount_point)?;
+
+ let _lock = pbs_config::datastore::lock_config()?;
+ let (mut section_config, _digest) = pbs_config::datastore::config()?;
+ let mut store_config: DataStoreConfig =
+ section_config.lookup("datastore", &datastore.name)?;
+ store_config.maintenance_mode = None;
+ section_config.set_data(&datastore.name, "datastore", &store_config)?;
+ pbs_config::datastore::save_config(§ion_config)?;
+ }
+ Ok(())
+}
+
+#[api(
+ protected: true,
+ input: {
+ properties: {
+ store: { schema: DATASTORE_SCHEMA },
+ },
+ },
+ returns: {
+ schema: UPID_SCHEMA,
+ },
+ access: {
+ permission: &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY, true),
+ }
+)]
+/// Unmount a removable device that is associated with the datastore
+pub async fn unmount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
+ let _lock = pbs_config::datastore::lock_config()?;
+ let (mut section_config, _digest) = pbs_config::datastore::config()?;
+ let mut datastore: DataStoreConfig = section_config.lookup("datastore", &store)?;
+
+ if datastore.backing_device.is_none() {
+ bail!("datastore '{store}' is not removable");
+ }
+
+ if !is_datastore_available(&datastore) {
+ bail!("datastore '{store}' is not mounted");
+ }
+
+ datastore.set_maintenance_mode(Some(MaintenanceMode::new(MaintenanceType::Unmount, None)))?;
+ section_config.set_data(&store, "datastore", &datastore)?;
+ pbs_config::datastore::save_config(§ion_config)?;
+
+ drop(_lock);
+
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+ let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
+
+ if let Ok(proxy_pid) = proxmox_rest_server::read_pid(pbs_buildcfg::PROXMOX_BACKUP_PROXY_PID_FN)
+ {
+ let sock = proxmox_rest_server::ctrl_sock_from_pid(proxy_pid);
+ let _ = proxmox_rest_server::send_raw_command(
+ sock,
+ &format!("{{\"command\":\"update-datastore-cache\",\"args\":\"{store}\"}}\n"),
+ )
+ .await;
+ }
+
+ let upid = WorkerTask::new_thread(
+ "unmount-device",
+ Some(store),
+ auth_id.to_string(),
+ to_stdout,
+ move |worker| do_unmount_device(datastore, Some(&worker)),
+ )?;
+
+ Ok(json!(upid))
+}
+
#[sortable]
const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
(
@@ -2316,6 +2481,7 @@ const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
.get(&API_METHOD_LIST_GROUPS)
.delete(&API_METHOD_DELETE_GROUP),
),
+ ("mount", &Router::new().post(&API_METHOD_MOUNT)),
(
"namespace",
// FIXME: move into datastore:: sub-module?!
@@ -2350,6 +2516,7 @@ const DATASTORE_INFO_SUBDIRS: SubdirMap = &[
.delete(&API_METHOD_DELETE_SNAPSHOT),
),
("status", &Router::new().get(&API_METHOD_STATUS)),
+ ("unmount", &Router::new().post(&API_METHOD_UNMOUNT)),
(
"upload-backup-log",
&Router::new().upload(&API_METHOD_UPLOAD_BACKUP_LOG),
--
2.39.2
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
next prev parent reply other threads:[~2024-04-23 8:40 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-23 8:29 [pbs-devel] [PATCH proxmox-backup v9 00/26] add " Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 01/26] tools: add disks utility functions Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 02/26] config: factor out method to get the absolute datastore path Hannes Laimer
2024-04-24 13:26 ` Wolfgang Bumiller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 03/26] pbs-api-types: add backing-device to DataStoreConfig Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 04/26] maintenance: add 'Unmount' maintenance type Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 05/26] disks: add UUID to partition info Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 06/26] datastore: add helper for checking if a removable datastore is available Hannes Laimer
2024-04-24 11:16 ` Gabriel Goller
2024-04-24 13:30 ` Wolfgang Bumiller
2024-04-25 6:05 ` Hannes Laimer
2024-04-25 7:19 ` Wolfgang Bumiller
2024-04-23 8:29 ` Hannes Laimer [this message]
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 08/26] api: removable datastore creation Hannes Laimer
2024-04-24 13:04 ` Wolfgang Bumiller
2024-04-25 8:52 ` Wolfgang Bumiller
2024-04-25 8:58 ` Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 09/26] api: disks list: add exclude-used flag Hannes Laimer
2024-04-24 13:09 ` Wolfgang Bumiller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 10/26] pbs-api-types: add removable/is-available flag to DataStoreListItem Hannes Laimer
2024-04-24 13:13 ` Wolfgang Bumiller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 11/26] bin: manager: add (un)mount command Hannes Laimer
2024-04-24 11:25 ` Gabriel Goller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 12/26] add auto-mounting for removable datastores Hannes Laimer
2024-04-24 13:18 ` Wolfgang Bumiller
2024-04-25 5:32 ` Hannes Laimer
2024-04-25 5:34 ` Hannes Laimer
2024-04-24 13:35 ` Wolfgang Bumiller
2024-04-25 4:59 ` Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 13/26] datastore: handle deletion of removable datastore properly Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 14/26] docs: add removable datastores section Hannes Laimer
2024-04-24 11:53 ` Gabriel Goller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 15/26] ui: add partition selector form Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 16/26] ui: add removable datastore creation support Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 17/26] ui: add (un)mount button to summary Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 18/26] ui: tree: render unmounted datastores correctly Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 19/26] ui: utils: make parseMaintenanceMode more robust Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 20/26] ui: add datastore status mask for unmounted removable datastores Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 21/26] ui: maintenance: fix disable msg field if no type is selected Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 22/26] ui: render 'unmount' maintenance mode correctly Hannes Laimer
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 23/26] api: node: allow creation of removable datastore through directory endpoint Hannes Laimer
2024-04-24 11:56 ` Gabriel Goller
2024-04-24 13:21 ` Wolfgang Bumiller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 24/26] api: node: include removable datastores in directory list Hannes Laimer
2024-04-24 13:06 ` Wolfgang Bumiller
2024-04-23 8:29 ` [pbs-devel] [PATCH proxmox-backup v9 25/26] node: disks: replace BASE_MOUNT_DIR with DATASTORE_MOUNT_DIR Hannes Laimer
2024-04-23 8:30 ` [pbs-devel] [PATCH proxmox-backup v9 26/26] ui: support create removable datastore through directory creation Hannes Laimer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240423083000.28002-8-h.laimer@proxmox.com \
--to=h.laimer@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox