[pdm-devel] [RFC PATCH datacenter-manager 1/3] server: pve api: add new bulkstart api call

Dominik Csapak d.csapak at proxmox.com
Wed Jan 29 11:51:40 CET 2025


similar to the 'bulkstart' of pve itself, but implemented here, since we
can do it across the cluster, and are not bound to one specific node.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 server/src/api/pve/mod.rs | 98 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs
index 2cefbb4..7dc7a34 100644
--- a/server/src/api/pve/mod.rs
+++ b/server/src/api/pve/mod.rs
@@ -1,10 +1,12 @@
 //! Manage PVE instances.
 
+use std::collections::HashMap;
 use std::sync::Arc;
 
 use anyhow::{bail, format_err, Error};
 
 use proxmox_access_control::CachedUserInfo;
+use proxmox_rest_server::WorkerTask;
 use proxmox_router::{
     http_bail, http_err, list_subdirs_api_method, Permission, Router, RpcEnvironment, SubdirMap,
 };
@@ -17,7 +19,7 @@ use pdm_api_types::remotes::{NodeUrl, Remote, RemoteType, REMOTE_ID_SCHEMA};
 use pdm_api_types::resource::PveResource;
 use pdm_api_types::{
     Authid, RemoteUpid, HOST_OPTIONAL_PORT_FORMAT, PRIV_RESOURCE_AUDIT, PRIV_RESOURCE_DELETE,
-    PRIV_SYS_MODIFY,
+    PRIV_RESOURCE_MANAGE, PRIV_SYS_MODIFY, UPID, VMID_SCHEMA,
 };
 
 use pve_api_types::client::PveClient;
@@ -57,6 +59,7 @@ const MAIN_ROUTER: Router = Router::new()
 
 #[sortable]
 const REMOTE_SUBDIRS: SubdirMap = &sorted!([
+    ("bulk-start", &Router::new().post(&API_METHOD_BULK_START)),
     ("lxc", &lxc::ROUTER),
     ("nodes", &NODES_ROUTER),
     ("qemu", &qemu::ROUTER),
@@ -427,3 +430,96 @@ pub async fn list_realm_remote_pve(
 
     Ok(list)
 }
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+            "vmid-list": {
+                type: Array,
+                description: "A list of vmids to start",
+                items: {
+                    schema: VMID_SCHEMA,
+                },
+            },
+        },
+    },
+    returns: { type: UPID },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_MANAGE, false),
+    },
+)]
+/// Start a remote qemu vm.
+pub async fn bulk_start(
+    remote: String,
+    vmid_list: Vec<u32>,
+    rpcenv: &mut dyn RpcEnvironment,
+) -> Result<UPID, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+
+    let pve = connect_to_remote(&remotes, &remote)?;
+
+    let auth_id = rpcenv.get_auth_id().unwrap();
+
+    let upid = WorkerTask::spawn("qmbulkstart", None, auth_id, false, |_| async move {
+        let resources = pve.cluster_resources(Some(ClusterResourceKind::Vm)).await?;
+
+        let mut map = HashMap::new();
+
+        for res in resources {
+            match res.ty {
+                ClusterResourceType::Qemu => {
+                    map.insert(res.vmid.unwrap(), (res.node, res.ty));
+                }
+                ClusterResourceType::Lxc => {
+                    map.insert(res.vmid.unwrap(), (res.node, res.ty));
+                }
+                _ => {}
+            }
+        }
+
+        for vmid in vmid_list {
+            // TODO:
+            // * get boot order/delay?
+            // * wait for start task to finish?
+            // * how to handle errors?
+            // * check privileges for each vmid
+
+            let (node, vmtype) = if let Some((node, vmtype)) = map.get(&vmid) {
+                match node {
+                    Some(node) => (node, vmtype),
+                    None => bail!("vm without node"),
+                }
+            } else {
+                bail!("no such vmid");
+            };
+
+            log::info!("Start VM {vmid} on {node}");
+            let res = match vmtype {
+                ClusterResourceType::Qemu => {
+                    pve.start_qemu_async(node, vmid, Default::default()).await
+                }
+                ClusterResourceType::Lxc => {
+                    pve.start_lxc_async(node, vmid, Default::default()).await
+                }
+                _ => bail!("invalid vm type"),
+            };
+
+            match res {
+                Ok(upid) => {
+                    log::info!("Started Task: {upid}");
+
+                    // track the remote upids
+                    let _ = new_remote_upid(remote.clone(), upid);
+                }
+                Err(err) => {
+                    log::error!("Starting failed: {err}");
+                }
+            }
+        }
+
+        Ok(())
+    })?;
+
+    upid.parse()
+}
-- 
2.39.5





More information about the pdm-devel mailing list