From: Hannes Laimer <h.laimer@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v3 2/4] api: datastore: auto-unmount after mount-triggered sync
Date: Wed, 12 Nov 2025 13:05:13 +0100 [thread overview]
Message-ID: <20251112120515.145480-4-h.laimer@proxmox.com> (raw)
In-Reply-To: <20251112120515.145480-1-h.laimer@proxmox.com>
When a datastore mount triggers sync jobs, unmount the datastore afterwards
if any such job has unmount_on_done=true. This applies only to mount-triggered
runs. Manual and scheduled syncs run in the proxy and cannot perform the
privileged unmount.
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
src/api2/admin/datastore.rs | 96 ++++++++++++++++++++++---------------
1 file changed, 57 insertions(+), 39 deletions(-)
diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index 6e269ef9..911378d7 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -2454,6 +2454,7 @@ async fn do_sync_jobs(
}
}
}
+
Ok(())
}
@@ -2515,30 +2516,44 @@ pub fn mount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Er
warn!("unable to parse sync job config, won't run any sync jobs");
return Ok(());
};
- let mut jobs_to_run: Vec<SyncJobConfig> = list
- .into_iter()
- .filter(|job: &SyncJobConfig| {
- // add job iff (running on mount is enabled and) any of these apply
- // - the jobs is local and we are source or target
- // - we are the source of a push to a remote
- // - we are the target of a pull from a remote
- //
- // `job.store == datastore.name` iff we are the target for pull from remote or we
- // are the source for push to remote, therefore we don't have to check for the
- // direction of the job.
- job.run_on_mount.unwrap_or(false)
- && (job.remote.is_none() && job.remote_store == name || job.store == name)
- })
- .collect();
+ let (unmount_on_done, mut jobs_to_run): (bool, Vec<SyncJobConfig>) =
+ list.into_iter().fold(
+ (false, Vec::new()),
+ |(mut unmount, mut jobs), job: SyncJobConfig| {
+ // add job iff (running on mount is enabled and) any of these apply
+ // - the jobs is local and we are source or target
+ // - we are the source of a push to a remote
+ // - we are the target of a pull from a remote
+ //
+ // `job.store == datastore.name` iff we are the target for pull from remote or we
+ // are the source for push to remote, therefore we don't have to check for the
+ // direction of the job.
+ let should_run = job.run_on_mount.unwrap_or(false)
+ && (job.remote.is_none() && job.remote_store == name
+ || job.store == name);
+ if should_run {
+ unmount |= job.unmount_on_done.unwrap_or_default();
+ jobs.push(job);
+ };
+ (unmount, jobs)
+ },
+ );
jobs_to_run.sort_by(|j1, j2| j1.id.cmp(&j2.id));
if !jobs_to_run.is_empty() {
info!("starting {} sync jobs", jobs_to_run.len());
let _ = WorkerTask::spawn(
"mount-sync-jobs",
- Some(store),
+ Some(store.clone()),
auth_id.to_string(),
false,
- move |worker| async move { do_sync_jobs(jobs_to_run, worker).await },
+ move |worker| async move {
+ let res = do_sync_jobs(jobs_to_run, worker).await;
+ if unmount_on_done {
+ info!("start unmounting...");
+ do_unmount(store, auth_id, false).await?;
+ }
+ res
+ },
);
}
Ok(())
@@ -2624,25 +2639,7 @@ fn do_unmount_device(
Ok(())
}
-#[api(
- protected: true,
- input: {
- properties: {
- store: { schema: DATASTORE_SCHEMA },
- },
- },
- returns: {
- schema: UPID_SCHEMA,
- },
- access: {
- permission: &Permission::And(&[
- &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY, true),
- &Permission::Privilege(&["system", "disks"], PRIV_SYS_MODIFY, false)
- ]),
- }
-)]
-/// Unmount a removable device that is associated with the datastore
-pub async fn unmount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
+async fn do_unmount(store: String, auth_id: Authid, to_stdout: bool) -> 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)?;
@@ -2662,9 +2659,6 @@ pub async fn unmount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<V
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_daemon::command_socket::path_from_pid(proxy_pid);
@@ -2689,6 +2683,30 @@ pub async fn unmount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<V
Ok(json!(upid))
}
+#[api(
+ protected: true,
+ input: {
+ properties: {
+ store: { schema: DATASTORE_SCHEMA },
+ },
+ },
+ returns: {
+ schema: UPID_SCHEMA,
+ },
+ access: {
+ permission: &Permission::And(&[
+ &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_MODIFY, true),
+ &Permission::Privilege(&["system", "disks"], PRIV_SYS_MODIFY, false)
+ ]),
+ }
+)]
+/// Unmount a removable device that is associated with the datastore
+pub async fn unmount(store: String, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Error> {
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+ let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
+ do_unmount(store, auth_id, to_stdout).await
+}
+
#[api(
protected: true,
input: {
--
2.47.3
_______________________________________________
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:[~2025-11-12 12:04 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-12 12:05 [pbs-devel] [PATCH proxmox{, -backup} v3 0/5] unmount datastores after sync job Hannes Laimer
2025-11-12 12:05 ` [pbs-devel] [PATCH proxmox v3 1/1] pbs-api-types: add 'unmount-on-done' field to sync job config Hannes Laimer
2025-11-14 21:36 ` [pbs-devel] applied: " Thomas Lamprecht
2025-11-12 12:05 ` [pbs-devel] [PATCH proxmox-backup v3 1/4] api: syncjob: correctly update/delete 'unmount-on-done' field Hannes Laimer
2025-11-12 12:05 ` Hannes Laimer [this message]
2025-11-12 12:05 ` [pbs-devel] [PATCH proxmox-backup v3 3/4] ui: add 'unmount-on-done' field to SyncJobEdit window Hannes Laimer
2025-11-12 12:05 ` [pbs-devel] [PATCH proxmox-backup v3 4/4] docs: add section about `unmount-on-done` Hannes Laimer
2025-11-14 22:15 ` [pbs-devel] [PATCH proxmox{, -backup} v3 0/5] unmount datastores after sync job Thomas Lamprecht
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=20251112120515.145480-4-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 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.