public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager
@ 2025-11-06 12:43 Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH proxmox 1/1] node-status: add node status crate Shannon Sterz
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

this series adds a node status panel as a widget for a view to proxmox
datacenter manager. it allows for getting a rough overview of system
load as well as accessing the node's fingerprint and rebooting and
powering off the node.

the fist patch moves the api endpoints from proxmox-backup server to
their own proxmox-rs crate. the next two commits extend yew-comp to
allow implementing a node status panel of the newly extracted api
endpoints return types.

the next three commits first add the new api endpoints to proxmox
datacenter manager, add the ui panel as a widget type and remove a
suproflous macro.

Changelog
---------

changes since v1:

- move the node status panel to its own widget type in pdm
- properly import api feature (thanks @ Dominik Csapak)
- smaller clean ups (thanks @ Dominik Csapak)

proxmox:

Shannon Sterz (1):
  node-status: add node status crate

 Cargo.toml                               |   1 +
 proxmox-node-status/Cargo.toml           |  37 +++++
 proxmox-node-status/debian/changelog     |   5 +
 proxmox-node-status/debian/control       |  65 ++++++++
 proxmox-node-status/debian/copyright     |  18 +++
 proxmox-node-status/debian/debcargo.toml |   7 +
 proxmox-node-status/src/api.rs           | 184 +++++++++++++++++++++++
 proxmox-node-status/src/lib.rs           |  11 ++
 proxmox-node-status/src/types.rs         | 184 +++++++++++++++++++++++
 9 files changed, 512 insertions(+)
 create mode 100644 proxmox-node-status/Cargo.toml
 create mode 100644 proxmox-node-status/debian/changelog
 create mode 100644 proxmox-node-status/debian/control
 create mode 100644 proxmox-node-status/debian/copyright
 create mode 100644 proxmox-node-status/debian/debcargo.toml
 create mode 100644 proxmox-node-status/src/api.rs
 create mode 100644 proxmox-node-status/src/lib.rs
 create mode 100644 proxmox-node-status/src/types.rs


proxmox-yew-comp:

Shannon Sterz (2):
  node info: extend NodeStatus enum to include NodeStatus from
    proxmox-rs
  node status panel: add a panel that show the current status of a node

 Cargo.toml               |   1 +
 src/lib.rs               |   3 +
 src/node_info.rs         |  38 ++++++
 src/node_status_panel.rs | 246 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 288 insertions(+)
 create mode 100644 src/node_status_panel.rs


proxmox-datacenter-manager:

Shannon Sterz (3):
  api-types/api: add endpoints for querying the node's status
  ui: add NodeStatusPanel to the administration menu
  nodes: remove unnecessary rustfmt::skip macro

 Cargo.toml                                    |  2 ++
 lib/pdm-api-types/src/acl.rs                  |  2 ++
 server/Cargo.toml                             |  1 +
 server/src/api/nodes/mod.rs                   |  3 ++-
 server/src/api/nodes/status.rs                | 18 ++++++++++++++++++
 server/src/bin/proxmox-datacenter-api/main.rs |  2 ++
 ui/src/administration/mod.rs                  |  4 +++-
 ui/src/dashboard/types.rs                     |  1 +
 ui/src/dashboard/view.rs                      | 15 ++++++++++++++-
 9 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 server/src/api/nodes/status.rs


Summary over all repositories:
  22 files changed, 845 insertions(+), 3 deletions(-)

--
Generated by git-murpp 0.8.1


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH proxmox 1/1] node-status: add node status crate
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
@ 2025-11-06 12:43 ` Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH yew-comp 1/2] node info: extend NodeStatus enum to include NodeStatus from proxmox-rs Shannon Sterz
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

this includes api endpoints for querying api endpoints. the original
implementation was factored out from proxmox-backup.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Dominik Csapak <d.csapak@proxmox.com>
---
 Cargo.toml                               |   1 +
 proxmox-node-status/Cargo.toml           |  37 +++++
 proxmox-node-status/debian/changelog     |   5 +
 proxmox-node-status/debian/control       |  65 ++++++++
 proxmox-node-status/debian/copyright     |  18 +++
 proxmox-node-status/debian/debcargo.toml |   7 +
 proxmox-node-status/src/api.rs           | 184 +++++++++++++++++++++++
 proxmox-node-status/src/lib.rs           |  11 ++
 proxmox-node-status/src/types.rs         | 184 +++++++++++++++++++++++
 9 files changed, 512 insertions(+)
 create mode 100644 proxmox-node-status/Cargo.toml
 create mode 100644 proxmox-node-status/debian/changelog
 create mode 100644 proxmox-node-status/debian/control
 create mode 100644 proxmox-node-status/debian/copyright
 create mode 100644 proxmox-node-status/debian/debcargo.toml
 create mode 100644 proxmox-node-status/src/api.rs
 create mode 100644 proxmox-node-status/src/lib.rs
 create mode 100644 proxmox-node-status/src/types.rs

diff --git a/Cargo.toml b/Cargo.toml
index 1330fe97..37e8696c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,6 +26,7 @@ members = [
     "proxmox-metrics",
     "proxmox-network-api",
     "proxmox-network-types",
+    "proxmox-node-status",
     "proxmox-notify",
     "proxmox-openid",
     "proxmox-product-config",
diff --git a/proxmox-node-status/Cargo.toml b/proxmox-node-status/Cargo.toml
new file mode 100644
index 00000000..2976d6a0
--- /dev/null
+++ b/proxmox-node-status/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+name = "proxmox-node-status"
+description = "API implementation and types for querying a nodes status."
+version = "1.0.0"
+
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+homepage.workspace = true
+exclude.workspace = true
+rust-version.workspace = true
+
+[dependencies]
+anyhow = { workspace = true, optional = true }
+hex = { workspace = true, optional = true }
+nix = { workspace = true, optional = true }
+openssl = { workspace = true, optional = true }
+serde = { workspace = true, features = [ "derive" ] }
+serde_json.workspace = true
+tokio = { workspace = true, optional = true }
+
+proxmox-router = { workspace = true, optional = true }
+proxmox-schema = { workspace = true, features = [ "api-macro", "api-types" ] }
+proxmox-sys = { workspace = true, optional = true }
+
+[features]
+default = []
+api = [
+    "dep:anyhow",
+    "dep:hex",
+    "dep:nix",
+    "dep:openssl",
+    "dep:proxmox-router",
+    "dep:proxmox-sys",
+    "dep:tokio"
+]
diff --git a/proxmox-node-status/debian/changelog b/proxmox-node-status/debian/changelog
new file mode 100644
index 00000000..a7050f31
--- /dev/null
+++ b/proxmox-node-status/debian/changelog
@@ -0,0 +1,5 @@
+rust-proxmox-node-status (1.0.0-1) trixie; urgency=medium
+
+  * Initial packaging
+
+ -- Proxmox Support Team <support@proxmox.com>  Wed, 22 Oct 2025 14:44:26 +0200
diff --git a/proxmox-node-status/debian/control b/proxmox-node-status/debian/control
new file mode 100644
index 00000000..48067be8
--- /dev/null
+++ b/proxmox-node-status/debian/control
@@ -0,0 +1,65 @@
+Source: rust-proxmox-node-status
+Section: rust
+Priority: optional
+Build-Depends: debhelper-compat (= 13),
+ dh-sequence-cargo
+Build-Depends-Arch: cargo:native <!nocheck>,
+ rustc:native (>= 1.82) <!nocheck>,
+ libstd-rust-dev <!nocheck>,
+ librust-proxmox-schema-5+api-macro-dev <!nocheck>,
+ librust-proxmox-schema-5+api-types-dev <!nocheck>,
+ librust-proxmox-schema-5+default-dev <!nocheck>,
+ librust-serde-1+default-dev <!nocheck>,
+ librust-serde-1+derive-dev <!nocheck>,
+ librust-serde-json-1+default-dev <!nocheck>
+Maintainer: Proxmox Support Team <support@proxmox.com>
+Standards-Version: 4.7.2
+Vcs-Git: git://git.proxmox.com/git/proxmox.git
+Vcs-Browser: https://git.proxmox.com/?p=proxmox.git
+Homepage: https://proxmox.com
+X-Cargo-Crate: proxmox-node-status
+
+Package: librust-proxmox-node-status-dev
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${misc:Depends},
+ librust-proxmox-schema-5+api-macro-dev,
+ librust-proxmox-schema-5+api-types-dev,
+ librust-proxmox-schema-5+default-dev,
+ librust-serde-1+default-dev,
+ librust-serde-1+derive-dev,
+ librust-serde-json-1+default-dev
+Suggests:
+ librust-proxmox-node-status+api-dev (= ${binary:Version})
+Provides:
+ librust-proxmox-node-status+default-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1+default-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1.0-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1.0+default-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1.0.0-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1.0.0+default-dev (= ${binary:Version})
+Description: API implementation and types for querying a nodes status - Rust source code
+ Source code for Debianized Rust crate "proxmox-node-status"
+
+Package: librust-proxmox-node-status+api-dev
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${misc:Depends},
+ librust-proxmox-node-status-dev (= ${binary:Version}),
+ librust-anyhow-1+default-dev,
+ librust-hex-0.4+default-dev,
+ librust-nix-0.29+default-dev,
+ librust-openssl-0.10+default-dev,
+ librust-proxmox-router-3+default-dev (>= 3.2.2-~~),
+ librust-proxmox-sys-1+default-dev,
+ librust-tokio-1+default-dev (>= 1.6-~~)
+Provides:
+ librust-proxmox-node-status-1+api-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1.0+api-dev (= ${binary:Version}),
+ librust-proxmox-node-status-1.0.0+api-dev (= ${binary:Version})
+Description: API implementation and types for querying a nodes status - feature "api"
+ This metapackage enables feature "api" for the Rust proxmox-node-status crate,
+ by pulling in any additional dependencies needed by that feature.
diff --git a/proxmox-node-status/debian/copyright b/proxmox-node-status/debian/copyright
new file mode 100644
index 00000000..d6e3c304
--- /dev/null
+++ b/proxmox-node-status/debian/copyright
@@ -0,0 +1,18 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files:
+ *
+Copyright: 2025 Proxmox Server Solutions GmbH <support@proxmox.com>
+License: AGPL-3.0-or-later
+ This program is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option) any
+ later version.
+ .
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU Affero General Public License along
+ with this program. If not, see <https://www.gnu.org/licenses/>.
diff --git a/proxmox-node-status/debian/debcargo.toml b/proxmox-node-status/debian/debcargo.toml
new file mode 100644
index 00000000..b7864cdb
--- /dev/null
+++ b/proxmox-node-status/debian/debcargo.toml
@@ -0,0 +1,7 @@
+overlay = "."
+crate_src_path = ".."
+maintainer = "Proxmox Support Team <support@proxmox.com>"
+
+[source]
+vcs_git = "git://git.proxmox.com/git/proxmox.git"
+vcs_browser = "https://git.proxmox.com/?p=proxmox.git"
diff --git a/proxmox-node-status/src/api.rs b/proxmox-node-status/src/api.rs
new file mode 100644
index 00000000..4d65d216
--- /dev/null
+++ b/proxmox-node-status/src/api.rs
@@ -0,0 +1,184 @@
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::sync::OnceLock;
+
+use anyhow::{bail, format_err, Error};
+
+use proxmox_schema::api;
+use proxmox_schema::api_types::NODE_SCHEMA;
+use proxmox_sys::boot_mode;
+use proxmox_sys::linux::procfs;
+
+pub use crate::types::{
+    BootModeInformation, KernelVersionInformation, NodeCpuInformation, NodeInformation,
+    NodeMemoryCounters, NodePowerCommand, NodeStatus, NodeSwapCounters, StorageStatus,
+};
+
+static TLS_CERT_PATH: OnceLock<PathBuf> = OnceLock::new();
+
+pub fn init_node_status_api<P: AsRef<Path>>(cert_path: P) -> Result<(), Error> {
+    TLS_CERT_PATH
+        .set(cert_path.as_ref().to_owned())
+        .map_err(|_e| format_err!("cannot set certificate path twice!"))
+}
+
+fn procfs_to_node_cpu_info(info: procfs::ProcFsCPUInfo) -> NodeCpuInformation {
+    NodeCpuInformation {
+        model: info.model,
+        sockets: info.sockets,
+        cpus: info.cpus,
+    }
+}
+
+fn boot_mode_to_info(bm: boot_mode::BootMode, sb: boot_mode::SecureBoot) -> BootModeInformation {
+    use boot_mode::BootMode;
+    use boot_mode::SecureBoot;
+
+    match (bm, sb) {
+        (BootMode::Efi, SecureBoot::Enabled) => BootModeInformation {
+            mode: crate::types::BootMode::Efi,
+            secureboot: true,
+        },
+        (BootMode::Efi, SecureBoot::Disabled) => BootModeInformation {
+            mode: crate::types::BootMode::Efi,
+            secureboot: false,
+        },
+        (BootMode::Bios, _) => BootModeInformation {
+            mode: crate::types::BootMode::LegacyBios,
+            secureboot: false,
+        },
+    }
+}
+
+fn certificate_fingerprint() -> Result<String, Error> {
+    let cert_path = TLS_CERT_PATH.get().ok_or_else(|| {
+        format_err!("certificate path needs to be set before calling node status endpoints")
+    })?;
+    let x509 = openssl::x509::X509::from_pem(&proxmox_sys::fs::file_get_contents(cert_path)?)?;
+    let fp = x509.digest(openssl::hash::MessageDigest::sha256())?;
+
+    Ok(hex::encode(fp)
+        .as_bytes()
+        .chunks(2)
+        .map(|v| std::str::from_utf8(v).unwrap())
+        .collect::<Vec<&str>>()
+        .join(":"))
+}
+
+#[api(
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        type: NodeStatus,
+    },
+)]
+/// Read node memory, CPU and (root) disk usage
+pub async fn get_status() -> Result<NodeStatus, Error> {
+    let meminfo: procfs::ProcFsMemInfo = procfs::read_meminfo()?;
+    let memory = NodeMemoryCounters {
+        total: meminfo.memtotal,
+        used: meminfo.memused,
+        free: meminfo.memfree,
+    };
+
+    let swap = NodeSwapCounters {
+        total: meminfo.swaptotal,
+        used: meminfo.swapused,
+        free: meminfo.swapfree,
+    };
+
+    let kstat: procfs::ProcFsStat = procfs::read_proc_stat()?;
+    let cpu = kstat.cpu;
+    let wait = kstat.iowait_percent;
+
+    let loadavg = procfs::Loadavg::read()?;
+    let loadavg = [loadavg.one(), loadavg.five(), loadavg.fifteen()];
+
+    let cpuinfo = procfs::read_cpuinfo()?;
+    let cpuinfo = procfs_to_node_cpu_info(cpuinfo);
+
+    let uname = nix::sys::utsname::uname()?;
+    let kernel_version = KernelVersionInformation::from_uname_parts(
+        uname.sysname(),
+        uname.release(),
+        uname.version(),
+        uname.machine(),
+    );
+
+    let disk = tokio::task::spawn_blocking(move || proxmox_sys::fs::fs_info(c"/"))
+        .await
+        .map_err(|err| format_err!("error waiting for fs_info call: {err}"))??;
+
+    let boot_info = boot_mode_to_info(boot_mode::BootMode::query(), boot_mode::SecureBoot::query());
+
+    Ok(NodeStatus {
+        memory,
+        swap,
+        root: StorageStatus {
+            total: disk.total,
+            used: disk.used,
+            avail: disk.available,
+        },
+        uptime: procfs::read_proc_uptime()?.0 as u64,
+        loadavg,
+        kversion: kernel_version.get_legacy(),
+        current_kernel: kernel_version,
+        cpuinfo,
+        cpu,
+        wait,
+        info: NodeInformation {
+            fingerprint: certificate_fingerprint()?,
+        },
+        boot_info,
+    })
+}
+
+#[api(
+    protected: true,
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+            command: {
+                type: NodePowerCommand,
+            },
+        }
+    },
+)]
+/// Reboot or shutdown the node.
+pub fn reboot_or_shutdown(command: NodePowerCommand) -> Result<(), Error> {
+    let systemctl_command = match command {
+        NodePowerCommand::Reboot => "reboot",
+        NodePowerCommand::Shutdown => "poweroff",
+    };
+
+    let output = Command::new("systemctl")
+        .arg(systemctl_command)
+        .output()
+        .map_err(|err| format_err!("failed to execute systemctl - {err}"))?;
+
+    if !output.status.success() {
+        match output.status.code() {
+            Some(code) => {
+                let msg = String::from_utf8(output.stderr)
+                    .map(|m| {
+                        if m.is_empty() {
+                            String::from("no error message")
+                        } else {
+                            m
+                        }
+                    })
+                    .unwrap_or_else(|_| String::from("non utf8 error message (suppressed)"));
+                bail!("command failed with status code: {code} - {msg}");
+            }
+            None => bail!("systemctl terminated by signal"),
+        }
+    }
+    Ok(())
+}
diff --git a/proxmox-node-status/src/lib.rs b/proxmox-node-status/src/lib.rs
new file mode 100644
index 00000000..2372b569
--- /dev/null
+++ b/proxmox-node-status/src/lib.rs
@@ -0,0 +1,11 @@
+
+#[cfg(feature = "api")]
+mod api;
+#[cfg(feature = "api")]
+pub use crate::api::{init_node_status_api, API_METHOD_GET_STATUS, API_METHOD_REBOOT_OR_SHUTDOWN};
+
+mod types;
+pub use crate::types::{
+    BootMode, BootModeInformation, KernelVersionInformation, NodeCpuInformation, NodeInformation,
+    NodeMemoryCounters, NodePowerCommand, NodeStatus, NodeSwapCounters, StorageStatus,
+};
diff --git a/proxmox-node-status/src/types.rs b/proxmox-node-status/src/types.rs
new file mode 100644
index 00000000..cc0ba424
--- /dev/null
+++ b/proxmox-node-status/src/types.rs
@@ -0,0 +1,184 @@
+use std::ffi::OsStr;
+
+use serde::{Deserialize, Serialize};
+
+use proxmox_schema::api;
+
+#[api]
+#[derive(Serialize, Deserialize, Copy, Clone)]
+#[serde(rename_all = "kebab-case")]
+/// The possible BootModes
+pub enum BootMode {
+    /// The BootMode is EFI/UEFI
+    Efi,
+    /// The BootMode is Legacy BIOS
+    LegacyBios,
+}
+
+#[api]
+#[derive(Serialize, Deserialize, Clone)]
+#[serde(rename_all = "lowercase")]
+/// Holds the Bootmodes
+pub struct BootModeInformation {
+    /// The BootMode, either Efi or Bios
+    pub mode: BootMode,
+    /// SecureBoot status
+    pub secureboot: bool,
+}
+
+#[api]
+#[derive(Serialize, Deserialize, Default)]
+#[serde(rename_all = "lowercase")]
+/// The current kernel version (output of `uname`)
+pub struct KernelVersionInformation {
+    /// The systemname/nodename
+    pub sysname: String,
+    /// The kernel release number
+    pub release: String,
+    /// The kernel version
+    pub version: String,
+    /// The machine architecture
+    pub machine: String,
+}
+
+impl KernelVersionInformation {
+    pub fn from_uname_parts(
+        sysname: &OsStr,
+        release: &OsStr,
+        version: &OsStr,
+        machine: &OsStr,
+    ) -> Self {
+        KernelVersionInformation {
+            sysname: sysname.to_str().map(String::from).unwrap_or_default(),
+            release: release.to_str().map(String::from).unwrap_or_default(),
+            version: version.to_str().map(String::from).unwrap_or_default(),
+            machine: machine.to_str().map(String::from).unwrap_or_default(),
+        }
+    }
+
+    pub fn get_legacy(&self) -> String {
+        format!("{} {} {}", self.sysname, self.release, self.version)
+    }
+}
+
+#[api]
+#[derive(Serialize, Deserialize, Default)]
+#[serde(rename_all = "kebab-case")]
+/// Information about the CPU
+pub struct NodeCpuInformation {
+    /// The CPU model
+    pub model: String,
+    /// The number of CPU sockets
+    pub sockets: usize,
+    /// The number of CPU cores (incl. threads)
+    pub cpus: usize,
+}
+
+#[api]
+#[derive(Serialize, Deserialize, Default)]
+#[serde(rename_all = "kebab-case")]
+/// Contains general node information such as the fingerprint`
+pub struct NodeInformation {
+    /// The SSL Fingerprint
+    pub fingerprint: String,
+}
+
+#[api]
+#[derive(Serialize, Deserialize, Default)]
+#[serde(rename_all = "kebab-case")]
+/// Node memory usage counters
+pub struct NodeMemoryCounters {
+    /// Total memory
+    pub total: u64,
+    /// Used memory
+    pub used: u64,
+    /// Free memory
+    pub free: u64,
+}
+
+#[api(
+    properties: {
+        memory: {
+            type: NodeMemoryCounters,
+        },
+        root: {
+            type: StorageStatus,
+        },
+        swap: {
+            type: NodeSwapCounters,
+        },
+        loadavg: {
+            type: Array,
+            items: {
+                type: Number,
+                description: "the load",
+            }
+        },
+        cpuinfo: {
+            type: NodeCpuInformation,
+        },
+        info: {
+            type: NodeInformation,
+        }
+    },
+)]
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// The Node status
+pub struct NodeStatus {
+    pub memory: NodeMemoryCounters,
+    pub root: StorageStatus,
+    pub swap: NodeSwapCounters,
+    /// The current uptime of the server.
+    pub uptime: u64,
+    /// Load for 1, 5 and 15 minutes.
+    pub loadavg: [f64; 3],
+    /// The current kernel version (NEW struct type).
+    pub current_kernel: KernelVersionInformation,
+    /// The current kernel version (LEGACY string type).
+    pub kversion: String,
+    /// Total CPU usage since last query.
+    pub cpu: f64,
+    /// Total IO wait since last query.
+    pub wait: f64,
+    pub cpuinfo: NodeCpuInformation,
+    pub info: NodeInformation,
+    /// Current boot mode
+    pub boot_info: BootModeInformation,
+}
+
+#[api]
+#[derive(Serialize, Deserialize, Default)]
+#[serde(rename_all = "kebab-case")]
+/// Node swap usage counters
+pub struct NodeSwapCounters {
+    /// Total swap
+    pub total: u64,
+    /// Used swap
+    pub used: u64,
+    /// Free swap
+    pub free: u64,
+}
+
+#[api()]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
+/// Node Power command type.
+pub enum NodePowerCommand {
+    /// Restart the server
+    Reboot,
+    /// Shutdown the server
+    Shutdown,
+}
+
+#[api()]
+#[derive(Default, Serialize, Deserialize)]
+/// Storage space usage information.
+pub struct StorageStatus {
+    /// Total space (bytes).
+    pub total: u64,
+    /// Used space (bytes).
+    pub used: u64,
+    /// Available space (bytes).
+    pub avail: u64,
+}
--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH yew-comp 1/2] node info: extend NodeStatus enum to include NodeStatus from proxmox-rs
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH proxmox 1/1] node-status: add node status crate Shannon Sterz
@ 2025-11-06 12:43 ` Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH yew-comp 2/2] node status panel: add a panel that show the current status of a node Shannon Sterz
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Dominik Csapak <d.csapak@proxmox.com>
---
 Cargo.toml       |  1 +
 src/node_info.rs | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/Cargo.toml b/Cargo.toml
index 39109c0..ecce886 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -84,6 +84,7 @@ proxmox-apt-api-types = { version = "2.0", optional = true }
 proxmox-access-control = "1.1"
 proxmox-dns-api = { version = "1", optional = true }
 proxmox-network-api = { version = "1", optional = true }
+proxmox-node-status = { version = "1", features = [] }

 pve-api-types = "8"
 pbs-api-types = "1"
diff --git a/src/node_info.rs b/src/node_info.rs
index 17ba6cd..5604787 100644
--- a/src/node_info.rs
+++ b/src/node_info.rs
@@ -1,4 +1,5 @@
 use proxmox_human_byte::HumanByte;
+use proxmox_node_status::BootMode;
 use pwt::{prelude::*, widget::Container};

 use crate::{MeterLabel, StatusRow};
@@ -7,6 +8,7 @@ use crate::{MeterLabel, StatusRow};
 pub enum NodeStatus<'a> {
     Pve(&'a pve_api_types::NodeStatus),
     Pbs(&'a pbs_api_types::NodeStatus),
+    Common(&'a proxmox_node_status::NodeStatus),
 }

 impl<'a> From<&'a pve_api_types::NodeStatus> for NodeStatus<'a> {
@@ -29,6 +31,7 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
     let (cpu, cpus_total) = match data {
         Some(NodeStatus::Pve(node_status)) => (node_status.cpu, node_status.cpuinfo.cpus as u64),
         Some(NodeStatus::Pbs(node_status)) => (node_status.cpu, node_status.cpuinfo.cpus as u64),
+        Some(NodeStatus::Common(node_status)) => (node_status.cpu, node_status.cpuinfo.cpus as u64),
         None => (0.0, 1),
     };

@@ -39,6 +42,7 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             .and_then(|wait| wait.as_f64())
             .unwrap_or_default(),
         Some(NodeStatus::Pbs(node_status)) => node_status.wait,
+        Some(NodeStatus::Common(node_status)) => node_status.wait,
         None => 0.0,
     };

@@ -48,6 +52,9 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             node_status.memory.total as u64,
         ),
         Some(NodeStatus::Pbs(node_status)) => (node_status.memory.used, node_status.memory.total),
+        Some(NodeStatus::Common(node_status)) => {
+            (node_status.memory.used, node_status.memory.total)
+        }
         None => (0, 1),
     };

@@ -57,6 +64,10 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             "{:.2} {:.2} {:.2}",
             node_status.loadavg[0], node_status.loadavg[1], node_status.loadavg[2]
         ),
+        Some(NodeStatus::Common(node_status)) => format!(
+            "{:.2} {:.2} {:.2}",
+            node_status.loadavg[0], node_status.loadavg[1], node_status.loadavg[2]
+        ),
         None => tr!("N/A"),
     };

@@ -66,6 +77,7 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             node_status.rootfs.total as u64,
         ),
         Some(NodeStatus::Pbs(node_status)) => (node_status.root.used, node_status.root.total),
+        Some(NodeStatus::Common(node_status)) => (node_status.root.used, node_status.root.total),
         None => (0, 1),
     };

@@ -90,6 +102,7 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             }
         }
         Some(NodeStatus::Pbs(node_status)) => (node_status.swap.used, node_status.swap.total),
+        Some(NodeStatus::Common(node_status)) => (node_status.swap.used, node_status.swap.total),
         None => (0, 1),
     };

@@ -102,6 +115,10 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             node_status.cpuinfo.model.clone(),
             node_status.cpuinfo.sockets as u64,
         ),
+        Some(NodeStatus::Common(node_status)) => (
+            node_status.cpuinfo.model.clone(),
+            node_status.cpuinfo.sockets as u64,
+        ),
         None => (String::new(), 1),
     };

@@ -121,9 +138,20 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
             node_status.current_kernel.release.clone(),
             node_status.current_kernel.version.clone(),
         ),
+        Some(NodeStatus::Common(node_status)) => (
+            node_status.current_kernel.sysname.clone(),
+            node_status.current_kernel.release.clone(),
+            node_status.current_kernel.version.clone(),
+        ),
         None => (String::new(), String::new(), String::new()),
     };

+    let boot_mode = if let Some(NodeStatus::Common(node_status)) = data {
+        Some(&node_status.boot_info)
+    } else {
+        None
+    };
+
     Container::new()
         .class("pwt-d-grid pwt-gap-2 pwt-align-items-center")
         .style("grid-template-columns", "1fr 20px 1fr")
@@ -221,4 +249,14 @@ pub fn node_info(data: Option<NodeStatus>) -> Container {
                 .style("grid-column", "1/-1")
                 .status(format!("{} {} {}", k_sysname, k_release, k_version)),
         )
+        .with_optional_child(boot_mode.map(|m| {
+            let mode = match m.mode {
+                BootMode::Efi => tr!("Legacy BIOS"),
+                BootMode::LegacyBios if m.secureboot => tr!("UEFI (Secure Boot Enabled)"),
+                BootMode::LegacyBios => tr!("UEFI"),
+            };
+            StatusRow::new(tr!("Boot Mode"))
+                .style("grid-column", "1/-1")
+                .status(mode)
+        }))
 }
--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH yew-comp 2/2] node status panel: add a panel that show the current status of a node
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH proxmox 1/1] node-status: add node status crate Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH yew-comp 1/2] node info: extend NodeStatus enum to include NodeStatus from proxmox-rs Shannon Sterz
@ 2025-11-06 12:43 ` Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status Shannon Sterz
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

it also allows shutting down or reloading the node.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/lib.rs               |   3 +
 src/node_status_panel.rs | 246 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+)
 create mode 100644 src/node_status_panel.rs

diff --git a/src/lib.rs b/src/lib.rs
index 3a9e32b..e097b05 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -91,6 +91,9 @@ pub use loadable_component::{
 mod node_info;
 pub use node_info::{node_info, NodeStatus};

+mod node_status_panel;
+pub use node_status_panel::NodeStatusPanel;
+
 mod notes_view;
 pub use notes_view::{NotesView, NotesWithDigest, ProxmoxNotesView};

diff --git a/src/node_status_panel.rs b/src/node_status_panel.rs
new file mode 100644
index 0000000..be14d71
--- /dev/null
+++ b/src/node_status_panel.rs
@@ -0,0 +1,246 @@
+use std::future::Future;
+use std::rc::Rc;
+
+use anyhow::Error;
+use html::IntoPropValue;
+use pwt::css::{AlignItems, ColorScheme, FlexFit};
+use pwt::widget::form::DisplayField;
+use yew::virtual_dom::{VComp, VNode};
+
+use pwt::prelude::*;
+use pwt::widget::{error_message, Fa, Panel, Row, Tooltip};
+use pwt::widget::{Button, Dialog};
+use pwt_macros::builder;
+
+use proxmox_node_status::{NodePowerCommand, NodeStatus};
+
+use crate::utils::copy_text_to_clipboard;
+use crate::{
+    http_get, http_post, node_info, ConfirmButton, LoadableComponent, LoadableComponentContext,
+    LoadableComponentMaster,
+};
+
+#[derive(Properties, Clone, PartialEq)]
+#[builder]
+pub struct NodeStatusPanel {
+    /// URL path to load the node's status from.
+    #[builder(IntoPropValue, into_prop_value)]
+    #[prop_or_default]
+    status_base_url: Option<AttrValue>,
+}
+
+impl NodeStatusPanel {
+    pub fn new() -> Self {
+        yew::props!(Self {})
+    }
+}
+
+impl Default for NodeStatusPanel {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+enum Msg {
+    Error(Error),
+    Loaded(Rc<NodeStatus>),
+    RebootOrShutdown(NodePowerCommand),
+    Reload,
+}
+
+#[derive(PartialEq)]
+enum ViewState {
+    FingerprintDialog,
+}
+
+struct ProxmoxNodeStatusPanel {
+    node_status: Option<Rc<NodeStatus>>,
+    error: Option<Error>,
+}
+
+impl ProxmoxNodeStatusPanel {
+    fn change_power_state(&self, ctx: &LoadableComponentContext<Self>, command: NodePowerCommand) {
+        let Some(url) = ctx.props().status_base_url.clone() else {
+            return;
+        };
+        let link = ctx.link().clone();
+
+        ctx.link().spawn(async move {
+            let data = Some(serde_json::json!({
+                "command": command,
+            }));
+
+            match http_post(url.as_str(), data).await {
+                Ok(()) => link.send_message(Msg::Reload),
+                Err(err) => link.send_message(Msg::Error(err)),
+            }
+        });
+    }
+
+    fn fingerprint_dialog(
+        &self,
+        ctx: &LoadableComponentContext<Self>,
+        fingerprint: &str,
+    ) -> Dialog {
+        let link = ctx.link();
+        let link_button = ctx.link();
+        let fingerprint = fingerprint.to_owned();
+
+        Dialog::new(tr!("Fingerprint"))
+            .resizable(true)
+            .min_width(500)
+            .on_close(move |_| link.change_view(None))
+            .with_child(
+                Row::new()
+                    .gap(2)
+                    .margin_start(2)
+                    .margin_end(2)
+                    .with_child(
+                        DisplayField::new()
+                            .class(pwt::css::FlexFit)
+                            .value(fingerprint.clone())
+                            .border(true),
+                    )
+                    .with_child(
+                        Tooltip::new(
+                            Button::new_icon("fa fa-clipboard")
+                                .class(ColorScheme::Primary)
+                                .on_activate(move |_| copy_text_to_clipboard(&fingerprint)),
+                        )
+                        .tip(tr!("Copy token secret to clipboard.")),
+                    ),
+            )
+            .with_child(
+                Row::new()
+                    .padding(2)
+                    .with_flex_spacer()
+                    .with_child(
+                        Button::new(tr!("OK")).on_activate(move |_| link_button.change_view(None)),
+                    )
+                    .with_flex_spacer(),
+            )
+    }
+}
+
+impl LoadableComponent for ProxmoxNodeStatusPanel {
+    type Message = Msg;
+    type ViewState = ViewState;
+    type Properties = NodeStatusPanel;
+
+    fn create(ctx: &crate::LoadableComponentContext<Self>) -> Self {
+        ctx.link().repeated_load(5000);
+
+        Self {
+            node_status: None,
+            error: None,
+        }
+    }
+
+    fn load(
+        &self,
+        ctx: &crate::LoadableComponentContext<Self>,
+    ) -> std::pin::Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>> {
+        let url = ctx.props().status_base_url.clone();
+        let link = ctx.link().clone();
+
+        Box::pin(async move {
+            if let Some(url) = url {
+                match http_get(url.as_str(), None).await {
+                    Ok(res) => link.send_message(Msg::Loaded(Rc::new(res))),
+                    Err(err) => link.send_message(Msg::Error(err)),
+                }
+            }
+            Ok(())
+        })
+    }
+
+    fn update(&mut self, ctx: &crate::LoadableComponentContext<Self>, msg: Self::Message) -> bool {
+        match msg {
+            Msg::Error(err) => {
+                self.error = Some(err);
+                true
+            }
+            Msg::Loaded(status) => {
+                self.node_status = Some(status);
+                self.error = None;
+                true
+            }
+            Msg::RebootOrShutdown(command) => {
+                self.change_power_state(ctx, command);
+                false
+            }
+            Msg::Reload => true,
+        }
+    }
+
+    fn dialog_view(
+        &self,
+        ctx: &LoadableComponentContext<Self>,
+        view_state: &Self::ViewState,
+    ) -> Option<Html> {
+        if view_state == &ViewState::FingerprintDialog {
+            if let Some(ref node_status) = self.node_status {
+                return Some(
+                    self.fingerprint_dialog(&ctx, &node_status.info.fingerprint)
+                        .into(),
+                );
+            }
+        }
+        None
+    }
+
+    fn main_view(&self, ctx: &crate::LoadableComponentContext<Self>) -> Html {
+        let status = self
+            .node_status
+            .as_ref()
+            .map(|r| crate::NodeStatus::Common(r));
+
+        Panel::new()
+            .border(false)
+            .class(FlexFit)
+            .title(
+                Row::new()
+                    .class(AlignItems::Center)
+                    .gap(2)
+                    .with_child(Fa::new("book"))
+                    .with_child(tr!("Node Status"))
+                    .into_html(),
+            )
+            .with_tool(
+                ConfirmButton::new(tr!("Reboot"))
+                    .confirm_message(tr!("Are you sure you want to reboot the node?"))
+                    .on_activate(
+                        ctx.link()
+                            .callback(|_| Msg::RebootOrShutdown(NodePowerCommand::Reboot)),
+                    )
+                    .icon_class("fa fa-undo"),
+            )
+            .with_tool(
+                ConfirmButton::new(tr!("Shutdown"))
+                    .confirm_message(tr!("Are you sure you want to shut down the node?"))
+                    .on_activate(
+                        ctx.link()
+                            .callback(|_| Msg::RebootOrShutdown(NodePowerCommand::Shutdown)),
+                    )
+                    .icon_class("fa fa-power-off"),
+            )
+            .with_tool(
+                Button::new(tr!("Show Fingerprint"))
+                    .icon_class("fa fa-hashtag")
+                    .class(ColorScheme::Primary)
+                    .on_activate(
+                        ctx.link()
+                            .change_view_callback(|_| ViewState::FingerprintDialog),
+                    ),
+            )
+            .with_child(node_info(status))
+            .with_optional_child(self.error.as_ref().map(|e| error_message(&e.to_string())))
+            .into()
+    }
+}
+
+impl From<NodeStatusPanel> for VNode {
+    fn from(value: NodeStatusPanel) -> Self {
+        VComp::new::<LoadableComponentMaster<ProxmoxNodeStatusPanel>>(Rc::new(value), None).into()
+    }
+}
--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
                   ` (2 preceding siblings ...)
  2025-11-06 12:43 ` [pdm-devel] [PATCH yew-comp 2/2] node status panel: add a panel that show the current status of a node Shannon Sterz
@ 2025-11-06 12:43 ` Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 2/3] ui: make NodeStatusPanel available as a widget Shannon Sterz
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Dominik Csapak <d.csapak@proxmox.com>
---
 Cargo.toml                                    |  2 ++
 lib/pdm-api-types/src/acl.rs                  |  2 ++
 server/Cargo.toml                             |  1 +
 server/src/api/nodes/mod.rs                   |  2 ++
 server/src/api/nodes/status.rs                | 18 ++++++++++++++++++
 server/src/bin/proxmox-datacenter-api/main.rs |  2 ++
 6 files changed, 27 insertions(+)
 create mode 100644 server/src/api/nodes/status.rs

diff --git a/Cargo.toml b/Cargo.toml
index 49c7583..3252ccb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -78,6 +78,7 @@ proxmox-time-api = "1"
 proxmox-network-api = "1"
 proxmox-syslog-api = "1"
 proxmox-acme-api = "1"
+proxmox-node-status = "1"

 # API types for PVE (and later PMG?)
 pve-api-types = "8.0.5"
@@ -163,6 +164,7 @@ zstd = { version = "0.13" }
 # proxmox-log = { path = "../proxmox/proxmox-log" }
 # proxmox-metrics = { path = "../proxmox/proxmox-metrics" }
 # proxmox-network-api = { path = "../proxmox/proxmox-network-api" }
+# proxmox-node-status = { path = "../proxmox/proxmox-node-status" }
 # proxmox-notify = { path = "../proxmox/proxmox-notify" }
 # proxmox-openid = { path = "../proxmox/proxmox-openid" }
 # proxmox-product-config = { path = "../proxmox/proxmox-product-config" }
diff --git a/lib/pdm-api-types/src/acl.rs b/lib/pdm-api-types/src/acl.rs
index 9e69c2f..5592102 100644
--- a/lib/pdm-api-types/src/acl.rs
+++ b/lib/pdm-api-types/src/acl.rs
@@ -26,6 +26,8 @@ constnamedbitmap! {
         PRIV_SYS_MODIFY("System.Modify");
         /// `Sys.Console` allows access to the system's console
         PRIV_SYS_CONSOLE("Sys.Console");
+        /// `Sys.PowerManagement` allows powering off or rebooting the system.
+        PRIV_SYS_POWER_MANAGEMENT("Sys.PowerManagement");

         /// `Resource.Audit` allows auditing guests, storages and other resources.
         PRIV_RESOURCE_AUDIT("Resource.Audit");
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 94420b4..a215aaf 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -72,6 +72,7 @@ proxmox-time-api = { workspace = true, features = [ "impl" ] }
 proxmox-network-api = { workspace = true, features = [ "impl" ] }
 proxmox-syslog-api = { workspace = true, features = [ "impl" ] }
 proxmox-acme-api = { workspace = true, features = [ "impl" ] }
+proxmox-node-status = { workspace = true, features = [ "api" ] }

 pdm-api-types.workspace = true
 pdm-buildcfg.workspace = true
diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs
index 6f30ba7..f70fcaf 100644
--- a/server/src/api/nodes/mod.rs
+++ b/server/src/api/nodes/mod.rs
@@ -10,6 +10,7 @@ pub mod dns;
 pub mod journal;
 pub mod network;
 pub mod rrddata;
+pub mod status;
 pub mod syslog;
 pub mod tasks;
 pub mod termproxy;
@@ -45,6 +46,7 @@ pub const SUBDIRS: SubdirMap = &sorted!([
     ("journal", &journal::ROUTER),
     ("network", &network::ROUTER),
     ("rrdata", &rrddata::ROUTER),
+    ("status", &status::ROUTER),
     ("syslog", &syslog::ROUTER),
     ("tasks", &tasks::ROUTER),
     ("termproxy", &termproxy::ROUTER),
diff --git a/server/src/api/nodes/status.rs b/server/src/api/nodes/status.rs
new file mode 100644
index 0000000..b3bbed5
--- /dev/null
+++ b/server/src/api/nodes/status.rs
@@ -0,0 +1,18 @@
+use pdm_api_types::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT};
+use proxmox_router::{ApiMethod, Permission, Router};
+
+const API_METHOD_GET_STATUS_WITH_ACCESS: ApiMethod = proxmox_node_status::API_METHOD_GET_STATUS
+    .access(
+        None,
+        &Permission::Privilege(&["system", "status"], PRIV_SYS_AUDIT, false),
+    );
+
+const API_METHOD_REBOOT_OR_SHUTDOWN_WITH_ACCESS: ApiMethod =
+    proxmox_node_status::API_METHOD_REBOOT_OR_SHUTDOWN.access(
+        None,
+        &Permission::Privilege(&["system", "status"], PRIV_SYS_POWER_MANAGEMENT, false),
+    );
+
+pub const ROUTER: Router = Router::new()
+    .get(&API_METHOD_GET_STATUS_WITH_ACCESS)
+    .post(&API_METHOD_REBOOT_OR_SHUTDOWN_WITH_ACCESS);
diff --git a/server/src/bin/proxmox-datacenter-api/main.rs b/server/src/bin/proxmox-datacenter-api/main.rs
index 420a3b4..0e80c82 100644
--- a/server/src/bin/proxmox-datacenter-api/main.rs
+++ b/server/src/bin/proxmox-datacenter-api/main.rs
@@ -391,6 +391,8 @@ fn make_tls_acceptor() -> Result<SslAcceptor, Error> {
     let key_path = configdir!("/auth/api.key");
     let cert_path = configdir!("/auth/api.pem");

+    proxmox_node_status::init_node_status_api(cert_path)?;
+
     proxmox_rest_server::connection::TlsAcceptorBuilder::new()
         .certificate_paths_pem(key_path, cert_path)
         .build()
--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 2/3] ui: make NodeStatusPanel available as a widget
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
                   ` (3 preceding siblings ...)
  2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status Shannon Sterz
@ 2025-11-06 12:43 ` Shannon Sterz
  2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 3/3] nodes: remove unnecessary rustfmt::skip macro Shannon Sterz
  2025-11-06 12:44 ` [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 ui/src/administration/mod.rs |  4 +++-
 ui/src/dashboard/types.rs    |  1 +
 ui/src/dashboard/view.rs     | 15 ++++++++++++++-
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/ui/src/administration/mod.rs b/ui/src/administration/mod.rs
index a9f7ac6..72a4ffa 100644
--- a/ui/src/administration/mod.rs
+++ b/ui/src/administration/mod.rs
@@ -16,7 +16,9 @@ use pwt_macros::builder;
 //mod services;
 //pub use services::Services;

-use proxmox_yew_comp::{AptPackageManager, AptRepositories, ExistingProduct, Syslog, Tasks};
+use proxmox_yew_comp::{
+    AptPackageManager, AptRepositories, ExistingProduct, NodeStatusPanel, Syslog, Tasks,
+};

 #[derive(Clone, PartialEq, Properties)]
 #[builder]
diff --git a/ui/src/dashboard/types.rs b/ui/src/dashboard/types.rs
index c79c38a..ce4bbb7 100644
--- a/ui/src/dashboard/types.rs
+++ b/ui/src/dashboard/types.rs
@@ -61,6 +61,7 @@ pub enum WidgetType {
     TaskSummary {
         grouping: TaskSummaryGrouping,
     },
+    NodeStatus,
 }

 #[derive(Serialize, Deserialize, PartialEq, Clone, Copy)]
diff --git a/ui/src/dashboard/view.rs b/ui/src/dashboard/view.rs
index c781d99..b5cd722 100644
--- a/ui/src/dashboard/view.rs
+++ b/ui/src/dashboard/view.rs
@@ -3,6 +3,7 @@ use std::rc::Rc;
 use anyhow::Error;
 use futures::join;
 use js_sys::Date;
+use proxmox_yew_comp::NodeStatusPanel;
 use serde_json::json;
 use yew::virtual_dom::{VComp, VNode};

@@ -123,6 +124,11 @@ fn render_widget(
             let (hours, since) = get_task_options(refresh_config.task_last_hours);
             create_task_summary_panel(statistics, remotes, hours, since)
         }
+        WidgetType::NodeStatus => {
+            return NodeStatusPanel::new()
+                .status_base_url("/nodes/localhost/status")
+                .into()
+        }
     };

     if let Some(title) = &item.title {
@@ -215,6 +221,9 @@ fn required_api_calls(layout: &ViewLayout) -> (bool, bool, bool) {
                         }
                         WidgetType::Leaderboard { .. } => top_entities = true,
                         WidgetType::TaskSummary { .. } => task_statistics = true,
+                        WidgetType::NodeStatus => {
+                            // widget handles this by itself
+                        }
                     }
                 }
             }
@@ -465,7 +474,11 @@ async fn load_template() -> Result<ViewTemplate, Error> {
                   \"widget-type\": \"pbs-datastores\"
                 },
                 {
-                  \"flex\": 5.0,
+                  \"flex\": 2.0,
+                  \"widget-type\": \"node-status\"
+                },
+                {
+                  \"flex\": 3.0,
                   \"widget-type\": \"subscription\"
                 }
               ],
--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 3/3] nodes: remove unnecessary rustfmt::skip macro
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
                   ` (4 preceding siblings ...)
  2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 2/3] ui: make NodeStatusPanel available as a widget Shannon Sterz
@ 2025-11-06 12:43 ` Shannon Sterz
  2025-11-06 12:44 ` [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:43 UTC (permalink / raw)
  To: pdm-devel

with more items being present, rustfmt formats this list correctly.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/nodes/mod.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs
index f70fcaf..a0fe14a 100644
--- a/server/src/api/nodes/mod.rs
+++ b/server/src/api/nodes/mod.rs
@@ -36,7 +36,6 @@ pub const ITEM_ROUTER: Router = Router::new()
     .get(&list_subdirs_api_method!(SUBDIRS))
     .subdirs(SUBDIRS);

-#[rustfmt::skip] // it'll put both entries on 1 line...
 #[sortable]
 pub const SUBDIRS: SubdirMap = &sorted!([
     ("apt", &apt::ROUTER),
--
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager
  2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
                   ` (5 preceding siblings ...)
  2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 3/3] nodes: remove unnecessary rustfmt::skip macro Shannon Sterz
@ 2025-11-06 12:44 ` Shannon Sterz
  6 siblings, 0 replies; 10+ messages in thread
From: Shannon Sterz @ 2025-11-06 12:44 UTC (permalink / raw)
  To: Shannon Sterz; +Cc: pdm-devel

ah, forgot to add the v2 in the subject line for all of these. sorry. v1
is here: https://lore.proxmox.com/pdm-devel/20251028164435.576642-1-s.sterz@proxmox.com/

On Thu Nov 6, 2025 at 1:43 PM CET, Shannon Sterz wrote:
> this series adds a node status panel as a widget for a view to proxmox
> datacenter manager. it allows for getting a rough overview of system
> load as well as accessing the node's fingerprint and rebooting and
> powering off the node.
>
> the fist patch moves the api endpoints from proxmox-backup server to
> their own proxmox-rs crate. the next two commits extend yew-comp to
> allow implementing a node status panel of the newly extracted api
> endpoints return types.
>
> the next three commits first add the new api endpoints to proxmox
> datacenter manager, add the ui panel as a widget type and remove a
> suproflous macro.
>
> Changelog
> ---------
>
> changes since v1:
>
> - move the node status panel to its own widget type in pdm
> - properly import api feature (thanks @ Dominik Csapak)
> - smaller clean ups (thanks @ Dominik Csapak)
>
> proxmox:
>
> Shannon Sterz (1):
>   node-status: add node status crate
>
>  Cargo.toml                               |   1 +
>  proxmox-node-status/Cargo.toml           |  37 +++++
>  proxmox-node-status/debian/changelog     |   5 +
>  proxmox-node-status/debian/control       |  65 ++++++++
>  proxmox-node-status/debian/copyright     |  18 +++
>  proxmox-node-status/debian/debcargo.toml |   7 +
>  proxmox-node-status/src/api.rs           | 184 +++++++++++++++++++++++
>  proxmox-node-status/src/lib.rs           |  11 ++
>  proxmox-node-status/src/types.rs         | 184 +++++++++++++++++++++++
>  9 files changed, 512 insertions(+)
>  create mode 100644 proxmox-node-status/Cargo.toml
>  create mode 100644 proxmox-node-status/debian/changelog
>  create mode 100644 proxmox-node-status/debian/control
>  create mode 100644 proxmox-node-status/debian/copyright
>  create mode 100644 proxmox-node-status/debian/debcargo.toml
>  create mode 100644 proxmox-node-status/src/api.rs
>  create mode 100644 proxmox-node-status/src/lib.rs
>  create mode 100644 proxmox-node-status/src/types.rs
>
>
> proxmox-yew-comp:
>
> Shannon Sterz (2):
>   node info: extend NodeStatus enum to include NodeStatus from
>     proxmox-rs
>   node status panel: add a panel that show the current status of a node
>
>  Cargo.toml               |   1 +
>  src/lib.rs               |   3 +
>  src/node_info.rs         |  38 ++++++
>  src/node_status_panel.rs | 246 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 288 insertions(+)
>  create mode 100644 src/node_status_panel.rs
>
>
> proxmox-datacenter-manager:
>
> Shannon Sterz (3):
>   api-types/api: add endpoints for querying the node's status
>   ui: add NodeStatusPanel to the administration menu
>   nodes: remove unnecessary rustfmt::skip macro
>
>  Cargo.toml                                    |  2 ++
>  lib/pdm-api-types/src/acl.rs                  |  2 ++
>  server/Cargo.toml                             |  1 +
>  server/src/api/nodes/mod.rs                   |  3 ++-
>  server/src/api/nodes/status.rs                | 18 ++++++++++++++++++
>  server/src/bin/proxmox-datacenter-api/main.rs |  2 ++
>  ui/src/administration/mod.rs                  |  4 +++-
>  ui/src/dashboard/types.rs                     |  1 +
>  ui/src/dashboard/view.rs                      | 15 ++++++++++++++-
>  9 files changed, 45 insertions(+), 3 deletions(-)
>  create mode 100644 server/src/api/nodes/status.rs
>
>
> Summary over all repositories:
>   22 files changed, 845 insertions(+), 3 deletions(-)
>
> --
> Generated by git-murpp 0.8.1



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status
  2025-10-28 16:44 ` [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status Shannon Sterz
@ 2025-11-03 13:11   ` Dominik Csapak
  0 siblings, 0 replies; 10+ messages in thread
From: Dominik Csapak @ 2025-11-03 13:11 UTC (permalink / raw)
  To: Proxmox Datacenter Manager development discussion, Shannon Sterz

one comment inline

On 10/28/25 5:44 PM, Shannon Sterz wrote:
> Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
> ---
>   Cargo.toml                                    |  2 ++
>   lib/pdm-api-types/src/acl.rs                  |  2 ++
>   server/Cargo.toml                             |  1 +
>   server/src/api/nodes/mod.rs                   |  2 ++
>   server/src/api/nodes/status.rs                | 18 ++++++++++++++++++
>   server/src/bin/proxmox-datacenter-api/main.rs |  2 ++
>   6 files changed, 27 insertions(+)
>   create mode 100644 server/src/api/nodes/status.rs
> 
> diff --git a/Cargo.toml b/Cargo.toml
> index 49c7583..3252ccb 100644
> --- a/Cargo.toml
> +++ b/Cargo.toml
> @@ -78,6 +78,7 @@ proxmox-time-api = "1"
>   proxmox-network-api = "1"
>   proxmox-syslog-api = "1"
>   proxmox-acme-api = "1"
> +proxmox-node-status = "1"
>   
>   # API types for PVE (and later PMG?)
>   pve-api-types = "8.0.5"
> @@ -163,6 +164,7 @@ zstd = { version = "0.13" }
>   # proxmox-log = { path = "../proxmox/proxmox-log" }
>   # proxmox-metrics = { path = "../proxmox/proxmox-metrics" }
>   # proxmox-network-api = { path = "../proxmox/proxmox-network-api" }
> +# proxmox-node-status = { path = "../proxmox/proxmox-node-status" }
>   # proxmox-notify = { path = "../proxmox/proxmox-notify" }
>   # proxmox-openid = { path = "../proxmox/proxmox-openid" }
>   # proxmox-product-config = { path = "../proxmox/proxmox-product-config" }
> diff --git a/lib/pdm-api-types/src/acl.rs b/lib/pdm-api-types/src/acl.rs
> index 9e69c2f..5592102 100644
> --- a/lib/pdm-api-types/src/acl.rs
> +++ b/lib/pdm-api-types/src/acl.rs
> @@ -26,6 +26,8 @@ constnamedbitmap! {
>           PRIV_SYS_MODIFY("System.Modify");
>           /// `Sys.Console` allows access to the system's console
>           PRIV_SYS_CONSOLE("Sys.Console");
> +        /// `Sys.PowerManagement` allows powering off or rebooting the system.
> +        PRIV_SYS_POWER_MANAGEMENT("Sys.PowerManagement");
>   
>           /// `Resource.Audit` allows auditing guests, storages and other resources.
>           PRIV_RESOURCE_AUDIT("Resource.Audit");
> diff --git a/server/Cargo.toml b/server/Cargo.toml
> index 94420b4..88e3802 100644
> --- a/server/Cargo.toml
> +++ b/server/Cargo.toml
> @@ -72,6 +72,7 @@ proxmox-time-api = { workspace = true, features = [ "impl" ] }
>   proxmox-network-api = { workspace = true, features = [ "impl" ] }
>   proxmox-syslog-api = { workspace = true, features = [ "impl" ] }
>   proxmox-acme-api = { workspace = true, features = [ "impl" ] }
> +proxmox-node-status = { workspace = true }
>   

features = [ "api" ]

is missing here, otherwise it doesn't compile due to it not finding
the api functions

>   pdm-api-types.workspace = true
>   pdm-buildcfg.workspace = true
> diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs
> index 6f30ba7..f70fcaf 100644
> --- a/server/src/api/nodes/mod.rs
> +++ b/server/src/api/nodes/mod.rs
> @@ -10,6 +10,7 @@ pub mod dns;
>   pub mod journal;
>   pub mod network;
>   pub mod rrddata;
> +pub mod status;
>   pub mod syslog;
>   pub mod tasks;
>   pub mod termproxy;
> @@ -45,6 +46,7 @@ pub const SUBDIRS: SubdirMap = &sorted!([
>       ("journal", &journal::ROUTER),
>       ("network", &network::ROUTER),
>       ("rrdata", &rrddata::ROUTER),
> +    ("status", &status::ROUTER),
>       ("syslog", &syslog::ROUTER),
>       ("tasks", &tasks::ROUTER),
>       ("termproxy", &termproxy::ROUTER),
> diff --git a/server/src/api/nodes/status.rs b/server/src/api/nodes/status.rs
> new file mode 100644
> index 0000000..b3bbed5
> --- /dev/null
> +++ b/server/src/api/nodes/status.rs
> @@ -0,0 +1,18 @@
> +use pdm_api_types::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT};
> +use proxmox_router::{ApiMethod, Permission, Router};
> +
> +const API_METHOD_GET_STATUS_WITH_ACCESS: ApiMethod = proxmox_node_status::API_METHOD_GET_STATUS
> +    .access(
> +        None,
> +        &Permission::Privilege(&["system", "status"], PRIV_SYS_AUDIT, false),
> +    );
> +
> +const API_METHOD_REBOOT_OR_SHUTDOWN_WITH_ACCESS: ApiMethod =
> +    proxmox_node_status::API_METHOD_REBOOT_OR_SHUTDOWN.access(
> +        None,
> +        &Permission::Privilege(&["system", "status"], PRIV_SYS_POWER_MANAGEMENT, false),
> +    );
> +
> +pub const ROUTER: Router = Router::new()
> +    .get(&API_METHOD_GET_STATUS_WITH_ACCESS)
> +    .post(&API_METHOD_REBOOT_OR_SHUTDOWN_WITH_ACCESS);
> diff --git a/server/src/bin/proxmox-datacenter-api/main.rs b/server/src/bin/proxmox-datacenter-api/main.rs
> index 420a3b4..860612c 100644
> --- a/server/src/bin/proxmox-datacenter-api/main.rs
> +++ b/server/src/bin/proxmox-datacenter-api/main.rs
> @@ -391,6 +391,8 @@ fn make_tls_acceptor() -> Result<SslAcceptor, Error> {
>       let key_path = configdir!("/auth/api.key");
>       let cert_path = configdir!("/auth/api.pem");
>   
> +    proxmox_node_status::init_node_status_api(cert_path);
> +
>       proxmox_rest_server::connection::TlsAcceptorBuilder::new()
>           .certificate_paths_pem(key_path, cert_path)
>           .build()



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status
  2025-10-28 16:44 Shannon Sterz
@ 2025-10-28 16:44 ` Shannon Sterz
  2025-11-03 13:11   ` Dominik Csapak
  0 siblings, 1 reply; 10+ messages in thread
From: Shannon Sterz @ 2025-10-28 16:44 UTC (permalink / raw)
  To: pdm-devel

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 Cargo.toml                                    |  2 ++
 lib/pdm-api-types/src/acl.rs                  |  2 ++
 server/Cargo.toml                             |  1 +
 server/src/api/nodes/mod.rs                   |  2 ++
 server/src/api/nodes/status.rs                | 18 ++++++++++++++++++
 server/src/bin/proxmox-datacenter-api/main.rs |  2 ++
 6 files changed, 27 insertions(+)
 create mode 100644 server/src/api/nodes/status.rs

diff --git a/Cargo.toml b/Cargo.toml
index 49c7583..3252ccb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -78,6 +78,7 @@ proxmox-time-api = "1"
 proxmox-network-api = "1"
 proxmox-syslog-api = "1"
 proxmox-acme-api = "1"
+proxmox-node-status = "1"
 
 # API types for PVE (and later PMG?)
 pve-api-types = "8.0.5"
@@ -163,6 +164,7 @@ zstd = { version = "0.13" }
 # proxmox-log = { path = "../proxmox/proxmox-log" }
 # proxmox-metrics = { path = "../proxmox/proxmox-metrics" }
 # proxmox-network-api = { path = "../proxmox/proxmox-network-api" }
+# proxmox-node-status = { path = "../proxmox/proxmox-node-status" }
 # proxmox-notify = { path = "../proxmox/proxmox-notify" }
 # proxmox-openid = { path = "../proxmox/proxmox-openid" }
 # proxmox-product-config = { path = "../proxmox/proxmox-product-config" }
diff --git a/lib/pdm-api-types/src/acl.rs b/lib/pdm-api-types/src/acl.rs
index 9e69c2f..5592102 100644
--- a/lib/pdm-api-types/src/acl.rs
+++ b/lib/pdm-api-types/src/acl.rs
@@ -26,6 +26,8 @@ constnamedbitmap! {
         PRIV_SYS_MODIFY("System.Modify");
         /// `Sys.Console` allows access to the system's console
         PRIV_SYS_CONSOLE("Sys.Console");
+        /// `Sys.PowerManagement` allows powering off or rebooting the system.
+        PRIV_SYS_POWER_MANAGEMENT("Sys.PowerManagement");
 
         /// `Resource.Audit` allows auditing guests, storages and other resources.
         PRIV_RESOURCE_AUDIT("Resource.Audit");
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 94420b4..88e3802 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -72,6 +72,7 @@ proxmox-time-api = { workspace = true, features = [ "impl" ] }
 proxmox-network-api = { workspace = true, features = [ "impl" ] }
 proxmox-syslog-api = { workspace = true, features = [ "impl" ] }
 proxmox-acme-api = { workspace = true, features = [ "impl" ] }
+proxmox-node-status = { workspace = true }
 
 pdm-api-types.workspace = true
 pdm-buildcfg.workspace = true
diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs
index 6f30ba7..f70fcaf 100644
--- a/server/src/api/nodes/mod.rs
+++ b/server/src/api/nodes/mod.rs
@@ -10,6 +10,7 @@ pub mod dns;
 pub mod journal;
 pub mod network;
 pub mod rrddata;
+pub mod status;
 pub mod syslog;
 pub mod tasks;
 pub mod termproxy;
@@ -45,6 +46,7 @@ pub const SUBDIRS: SubdirMap = &sorted!([
     ("journal", &journal::ROUTER),
     ("network", &network::ROUTER),
     ("rrdata", &rrddata::ROUTER),
+    ("status", &status::ROUTER),
     ("syslog", &syslog::ROUTER),
     ("tasks", &tasks::ROUTER),
     ("termproxy", &termproxy::ROUTER),
diff --git a/server/src/api/nodes/status.rs b/server/src/api/nodes/status.rs
new file mode 100644
index 0000000..b3bbed5
--- /dev/null
+++ b/server/src/api/nodes/status.rs
@@ -0,0 +1,18 @@
+use pdm_api_types::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT};
+use proxmox_router::{ApiMethod, Permission, Router};
+
+const API_METHOD_GET_STATUS_WITH_ACCESS: ApiMethod = proxmox_node_status::API_METHOD_GET_STATUS
+    .access(
+        None,
+        &Permission::Privilege(&["system", "status"], PRIV_SYS_AUDIT, false),
+    );
+
+const API_METHOD_REBOOT_OR_SHUTDOWN_WITH_ACCESS: ApiMethod =
+    proxmox_node_status::API_METHOD_REBOOT_OR_SHUTDOWN.access(
+        None,
+        &Permission::Privilege(&["system", "status"], PRIV_SYS_POWER_MANAGEMENT, false),
+    );
+
+pub const ROUTER: Router = Router::new()
+    .get(&API_METHOD_GET_STATUS_WITH_ACCESS)
+    .post(&API_METHOD_REBOOT_OR_SHUTDOWN_WITH_ACCESS);
diff --git a/server/src/bin/proxmox-datacenter-api/main.rs b/server/src/bin/proxmox-datacenter-api/main.rs
index 420a3b4..860612c 100644
--- a/server/src/bin/proxmox-datacenter-api/main.rs
+++ b/server/src/bin/proxmox-datacenter-api/main.rs
@@ -391,6 +391,8 @@ fn make_tls_acceptor() -> Result<SslAcceptor, Error> {
     let key_path = configdir!("/auth/api.key");
     let cert_path = configdir!("/auth/api.pem");
 
+    proxmox_node_status::init_node_status_api(cert_path);
+
     proxmox_rest_server::connection::TlsAcceptorBuilder::new()
         .certificate_paths_pem(key_path, cert_path)
         .build()
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-11-06 12:44 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-06 12:43 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
2025-11-06 12:43 ` [pdm-devel] [PATCH proxmox 1/1] node-status: add node status crate Shannon Sterz
2025-11-06 12:43 ` [pdm-devel] [PATCH yew-comp 1/2] node info: extend NodeStatus enum to include NodeStatus from proxmox-rs Shannon Sterz
2025-11-06 12:43 ` [pdm-devel] [PATCH yew-comp 2/2] node status panel: add a panel that show the current status of a node Shannon Sterz
2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status Shannon Sterz
2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 2/3] ui: make NodeStatusPanel available as a widget Shannon Sterz
2025-11-06 12:43 ` [pdm-devel] [PATCH datacenter-manager 3/3] nodes: remove unnecessary rustfmt::skip macro Shannon Sterz
2025-11-06 12:44 ` [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/6] add node status panel to proxmox datacenter manager Shannon Sterz
  -- strict thread matches above, loose matches on Subject: below --
2025-10-28 16:44 Shannon Sterz
2025-10-28 16:44 ` [pdm-devel] [PATCH datacenter-manager 1/3] api-types/api: add endpoints for querying the node's status Shannon Sterz
2025-11-03 13:11   ` Dominik Csapak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal