[pdm-devel] [PATCH datacenter-manager v3 3/4] api: add /remotes/tasks/refresh

Lukas Wagner l.wagner at proxmox.com
Mon Dec 29 16:30:03 CET 2025


This one allows us to trigger task fetching for a single or all remotes.

Signed-off-by: Lukas Wagner <l.wagner at proxmox.com>
Reviewed-by: Shannon Sterz <s.sterz at proxmox.com>
---

Notes:
    Changes since v2:
      - Support to refresh multiple remotes at once
      - Rename paramter from 'remote' to 'remotes', since it's now an
        optional list of remotes
      - Improved documentation for the API handler

 server/src/api/remote_tasks.rs | 100 ++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 3 deletions(-)

diff --git a/server/src/api/remote_tasks.rs b/server/src/api/remote_tasks.rs
index c7359166..eb1448dd 100644
--- a/server/src/api/remote_tasks.rs
+++ b/server/src/api/remote_tasks.rs
@@ -3,11 +3,14 @@ use std::collections::HashMap;
 use anyhow::Error;
 
 use pdm_api_types::{
-    remotes::REMOTE_ID_SCHEMA, RemoteUpid, TaskCount, TaskFilters, TaskListItem, TaskStateType,
-    TaskStatistics, PRIV_RESOURCE_AUDIT, VIEW_ID_SCHEMA,
+    remotes::REMOTE_ID_SCHEMA, Authid, RemoteUpid, TaskCount, TaskFilters, TaskListItem,
+    TaskStateType, TaskStatistics, PRIV_RESOURCE_AUDIT, PRIV_RESOURCE_MODIFY, UPID, VIEW_ID_SCHEMA,
 };
 use proxmox_access_control::CachedUserInfo;
-use proxmox_router::{list_subdirs_api_method, Permission, Router, RpcEnvironment, SubdirMap};
+use proxmox_rest_server::WorkerTask;
+use proxmox_router::{
+    http_bail, http_err, list_subdirs_api_method, Permission, Router, RpcEnvironment, SubdirMap,
+};
 use proxmox_schema::api;
 use proxmox_sortable_macro::sortable;
 
@@ -24,6 +27,10 @@ const SUBDIRS: SubdirMap = &sorted!([
         "statistics",
         &Router::new().get(&API_METHOD_TASK_STATISTICS)
     ),
+    (
+        "refresh",
+        &Router::new().post(&API_METHOD_REFRESH_REMOTE_TASKS)
+    )
 ]);
 
 #[api(
@@ -168,3 +175,90 @@ async fn task_statistics(
 
     Ok(TaskStatistics { by_type, by_remote })
 }
+
+#[api(
+    input: {
+        properties: {
+            remotes: {
+                description: "Optional list of tasks to fetch tasks from.",
+                optional: true,
+                type: Array,
+                items: {
+                    schema: REMOTE_ID_SCHEMA,
+                },
+            },
+        },
+    },
+    access: {
+        permission: &Permission::Anybody,
+        description: "Resource.Modify privileges are needed on /resource/{remote}",
+    },
+    returns: { type: UPID }
+)]
+/// Refresh remote tasks cache.
+///
+/// If `remotes` is provided, tasks will only be fetched from the provided remotes.
+/// `Resource.Modify` permissions on `/resource/{remote}` are needed for every remote provided this way.
+///
+/// If `remotes` is not provided, then all remotes for which the user has appropriate permissions are considered.
+pub fn refresh_remote_tasks(
+    remotes: Option<Vec<String>>,
+    rpcenv: &mut dyn RpcEnvironment,
+) -> Result<UPID, Error> {
+    let (config, _digest) = pdm_config::remotes::config()?;
+
+    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+    let user_info = CachedUserInfo::new()?;
+
+    let remotes = if let Some(remotes) = remotes {
+        let mut configs = Vec::new();
+
+        for remote in &remotes {
+            if user_info
+                .check_privs(&auth_id, &["resource", remote], PRIV_RESOURCE_MODIFY, false)
+                .is_err()
+            {
+                http_bail!(FORBIDDEN, "user has no access to this remote");
+            }
+            let remote = config
+                .get(remote)
+                .ok_or_else(|| http_err!(NOT_FOUND, "remote does not exist"))?;
+
+            configs.push(remote.clone());
+        }
+
+        configs
+    } else {
+        if !user_info.any_privs_below(&auth_id, &["resource"], PRIV_RESOURCE_MODIFY)? {
+            http_bail!(FORBIDDEN, "user has no access to resources");
+        }
+
+        config
+            .into_iter()
+            .filter_map(|(remote_name, remote)| {
+                user_info
+                    .check_privs(
+                        &auth_id,
+                        &["resource", &remote_name],
+                        PRIV_RESOURCE_MODIFY,
+                        false,
+                    )
+                    .is_ok()
+                    .then_some(remote)
+            })
+            .collect()
+    };
+
+    let upid_str = WorkerTask::spawn(
+        "refresh-remote-tasks",
+        None,
+        auth_id.to_string(),
+        true,
+        |_worker| async {
+            remote_tasks::refresh_task::refresh_taskcache(remotes).await?;
+            Ok(())
+        },
+    )?;
+
+    upid_str.parse()
+}
-- 
2.47.3





More information about the pdm-devel mailing list