[pve-devel] [PATCH proxmox-perl-rs 1/2] pve-rs: add resource scheduling module

Fiona Ebner f.ebner at proxmox.com
Thu Nov 10 15:37:43 CET 2022


backed by the proxmox-resource-scheduling crate.

Initially to be used by the HA manager to allow it basing its decision
where to start a new or recovered service on static usage information
rather than just counting.

Signed-off-by: Fiona Ebner <f.ebner at proxmox.com>
---
 Makefile                                 |   1 +
 pve-rs/Cargo.toml                        |   1 +
 pve-rs/src/lib.rs                        |   1 +
 pve-rs/src/resource_scheduling/mod.rs    |   1 +
 pve-rs/src/resource_scheduling/static.rs | 116 +++++++++++++++++++++++
 5 files changed, 120 insertions(+)
 create mode 100644 pve-rs/src/resource_scheduling/mod.rs
 create mode 100644 pve-rs/src/resource_scheduling/static.rs

diff --git a/Makefile b/Makefile
index 0836c9d..3ddafd0 100644
--- a/Makefile
+++ b/Makefile
@@ -56,6 +56,7 @@ gen:
 	perl ./scripts/genpackage.pl PVE \
 	  PVE::RS::APT::Repositories \
 	  PVE::RS::OpenId \
+	  PVE::RS::ResourceScheduling::Static \
 	  PVE::RS::TFA
 	perl ./scripts/genpackage.pl PMG \
 	  PMG::RS::APT::Repositories \
diff --git a/pve-rs/Cargo.toml b/pve-rs/Cargo.toml
index 855c72d..daa6bff 100644
--- a/pve-rs/Cargo.toml
+++ b/pve-rs/Cargo.toml
@@ -33,6 +33,7 @@ perlmod = { version = "0.13", features = [ "exporter" ] }
 proxmox-apt = "0.9"
 proxmox-http = { version = "0.7", features = ["client-sync", "client-trait"] }
 proxmox-openid = "0.9.5"
+proxmox-resource-scheduling = "0.1"
 proxmox-subscription = "0.3"
 proxmox-sys = "0.4"
 proxmox-tfa = { version = "2.1", features = ["api"] }
diff --git a/pve-rs/src/lib.rs b/pve-rs/src/lib.rs
index 26b998b..562a4d4 100644
--- a/pve-rs/src/lib.rs
+++ b/pve-rs/src/lib.rs
@@ -5,4 +5,5 @@ pub mod common;
 
 pub mod apt;
 pub mod openid;
+pub mod resource_scheduling;
 pub mod tfa;
diff --git a/pve-rs/src/resource_scheduling/mod.rs b/pve-rs/src/resource_scheduling/mod.rs
new file mode 100644
index 0000000..a28f1c9
--- /dev/null
+++ b/pve-rs/src/resource_scheduling/mod.rs
@@ -0,0 +1 @@
+pub mod r#static;
diff --git a/pve-rs/src/resource_scheduling/static.rs b/pve-rs/src/resource_scheduling/static.rs
new file mode 100644
index 0000000..c47dcd3
--- /dev/null
+++ b/pve-rs/src/resource_scheduling/static.rs
@@ -0,0 +1,116 @@
+#[perlmod::package(name = "PVE::RS::ResourceScheduling::Static", lib = "pve_rs")]
+mod export {
+    use std::collections::HashMap;
+    use std::sync::Mutex;
+
+    use anyhow::{bail, Error};
+
+    use perlmod::Value;
+    use proxmox_resource_scheduling::pve_static::{StaticNodeUsage, StaticServiceUsage};
+
+    perlmod::declare_magic!(Box<Scheduler> : &Scheduler as "PVE::RS::ResourceScheduling::Static");
+
+    struct Usage {
+        nodes: HashMap<String, StaticNodeUsage>,
+    }
+
+    pub struct Scheduler {
+        inner: Mutex<Usage>,
+    }
+
+    #[export(raw_return)]
+    fn new(#[raw] class: Value) -> Result<Value, Error> {
+        let inner = Usage {
+            nodes: HashMap::new(),
+        };
+
+        Ok(perlmod::instantiate_magic!(
+            &class, MAGIC => Box::new(Scheduler { inner: Mutex::new(inner) })
+        ))
+    }
+
+    #[export]
+    fn add_node(
+        #[try_from_ref] this: &Scheduler,
+        nodename: String,
+        maxcpu: usize,
+        maxmem: usize,
+    ) -> Result<(), Error> {
+        let mut usage = this.inner.lock().unwrap();
+
+        if usage.nodes.contains_key(&nodename) {
+            bail!("node {} already added", nodename);
+        }
+
+        let node = StaticNodeUsage {
+            name: nodename.clone(),
+            cpu: 0.0,
+            maxcpu,
+            mem: 0,
+            maxmem,
+        };
+
+        usage.nodes.insert(nodename, node);
+        Ok(())
+    }
+
+    #[export]
+    fn remove_node(#[try_from_ref] this: &Scheduler, nodename: &str) {
+        let mut usage = this.inner.lock().unwrap();
+
+        usage.nodes.remove(nodename);
+    }
+
+    #[export]
+    fn list_nodes(#[try_from_ref] this: &Scheduler) -> Vec<String> {
+        let usage = this.inner.lock().unwrap();
+
+        usage
+            .nodes
+            .keys()
+            .map(|nodename| nodename.to_string())
+            .collect()
+    }
+
+    #[export]
+    fn contains_node(#[try_from_ref] this: &Scheduler, nodename: &str) -> bool {
+        let usage = this.inner.lock().unwrap();
+
+        usage.nodes.contains_key(nodename)
+    }
+
+    /// Add usage of `service` to the node's usage.
+    #[export]
+    fn add_service_usage_to_node(
+        #[try_from_ref] this: &Scheduler,
+        nodename: &str,
+        service: StaticServiceUsage,
+    ) -> Result<(), Error> {
+        let mut usage = this.inner.lock().unwrap();
+
+        match usage.nodes.get_mut(nodename) {
+            Some(node) => {
+                node.add_service_usage(&service);
+                Ok(())
+            }
+            None => bail!("node '{}' not present in usage hashmap", nodename),
+        }
+    }
+
+    /// Scores all previously added nodes for starting a `service` on. Scoring is done according to
+    /// the static memory and CPU usages of the nodes as if the service would already be running on
+    /// each.
+    ///
+    /// Returns a vector of (nodename, score) pairs. Scores are between 0.0 and 1.0 and a higher
+    /// score is better.
+    #[export]
+    fn score_nodes_to_start_service(
+        #[try_from_ref] this: &Scheduler,
+        service: StaticServiceUsage,
+    ) -> Result<Vec<(String, f64)>, Error> {
+        let usage = this.inner.lock().unwrap();
+        let nodes = usage.nodes.values().collect::<Vec<&StaticNodeUsage>>();
+
+        proxmox_resource_scheduling::pve_static::score_nodes_to_start_service(&nodes, &service)
+    }
+}
-- 
2.30.2






More information about the pve-devel mailing list