public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager v2 2/4] lib/api: add new 'remote-list' info to the resource status
Date: Tue,  5 May 2026 09:31:57 +0200	[thread overview]
Message-ID: <20260505073203.398548-7-d.csapak@proxmox.com> (raw)
In-Reply-To: <20260505073203.398548-1-d.csapak@proxmox.com>

this will be used to show more status information for each remote
on the views. Put it there since we have many infos to aggregate a
status and we have to iterate over the remotes anyway here.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 lib/pdm-api-types/src/resource.rs | 49 +++++++++++++++++++++++++++++++
 server/src/api/resources.rs       | 38 ++++++++++++++++++++----
 2 files changed, 82 insertions(+), 5 deletions(-)

diff --git a/lib/pdm-api-types/src/resource.rs b/lib/pdm-api-types/src/resource.rs
index 895d1244..b2af4e7c 100644
--- a/lib/pdm-api-types/src/resource.rs
+++ b/lib/pdm-api-types/src/resource.rs
@@ -689,6 +689,12 @@ pub struct CpuStatistics {
             items: {
                 type: FailedRemote,
             },
+        },
+        "remote-list": {
+            type: Array,
+            items: {
+                type: RemoteInfo,
+            },
         }
     }
 )]
@@ -729,6 +735,49 @@ pub struct ResourcesStatus {
     /// List of the failed remotes including type and error
     #[serde(default, skip_serializing_if = "Vec::is_empty")]
     pub failed_remotes_list: Vec<FailedRemote>,
+
+    /// List of remote info
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    #[serde(rename = "remote-list")]
+    pub remote_list: Vec<RemoteInfo>,
+}
+
+#[api]
+#[derive(Clone, PartialEq, Serialize, Deserialize, Default)]
+/// Basic remote status
+pub enum RemoteStatus {
+    #[default]
+    /// Remote is healthy and reachable
+    Good,
+    /// Remote has at least one (non-fatal) issue
+    Warning,
+    /// Remote can't be reached or has a fatal error
+    Error,
+    /// Unknown status of a remote
+    Unknown,
+}
+
+#[api(
+    properties: {
+        messages: {
+            type: Array,
+            items: {
+                description: "A warning or error message",
+                type: String,
+            },
+        },
+    },
+)]
+#[derive(Clone, PartialEq, Serialize, Deserialize, Default)]
+/// Basic information about a remote
+pub struct RemoteInfo {
+    /// The name of the remote
+    pub name: String,
+    #[serde(default, skip_serializing_if = "Vec::is_empty")]
+    /// The error or warning messages when the state is not good.
+    pub messages: Vec<String>,
+    /// The overall status of the remote
+    pub status: RemoteStatus,
 }
 
 #[api]
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 04628a81..5dfab1d4 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -13,8 +13,8 @@ use pdm_api_types::remotes::{Remote, RemoteType};
 use pdm_api_types::resource::{
     FailedRemote, NetworkFabricResource, NetworkZoneResource, PbsDatastoreResource,
     PbsNodeResource, PveLxcResource, PveNetworkResource, PveNodeResource, PveQemuResource,
-    PveStorageResource, RemoteResources, Resource, ResourceType, ResourcesStatus, SdnStatus,
-    TopEntities, PBS_DATASTORE_HIGH_USAGE_THRESHOLD,
+    PveStorageResource, RemoteInfo, RemoteResources, RemoteStatus, Resource, ResourceType,
+    ResourcesStatus, SdnStatus, TopEntities, PBS_DATASTORE_HIGH_USAGE_THRESHOLD,
 };
 use pdm_api_types::subscription::{
     NodeSubscriptionInfo, RemoteSubscriptionState, RemoteSubscriptions, SubscriptionLevel,
@@ -470,16 +470,27 @@ pub async fn get_status(
     let mut counts = ResourcesStatus::default();
     let mut pve_cpu_allocated = 0.0;
     for remote_with_resources in remotes_with_resources {
-        if let Some(err) = remote_with_resources.error {
+        if let Some(err) = &remote_with_resources.error {
             counts.failed_remotes += 1;
             counts.failed_remotes_list.push(FailedRemote {
-                name: remote_with_resources.remote_name,
+                name: remote_with_resources.remote_name.clone(),
                 error: err.to_string(),
                 remote_type: remote_with_resources.remote.ty,
             });
         } else {
             counts.remotes += 1;
         }
+
+        let mut remote_status = if remote_with_resources.error.is_some() {
+            RemoteStatus::Error
+        } else {
+            RemoteStatus::Good
+        };
+        let mut remote_messages = match remote_with_resources.error {
+            Some(error) => vec![error],
+            None => Vec::new(),
+        };
+
         let mut seen_storages = HashSet::new();
         for resource in remote_with_resources.resources {
             match resource {
@@ -516,7 +527,13 @@ pub async fn get_status(
                 Resource::PveNode(r) => {
                     match r.status.as_str() {
                         "online" => counts.pve_nodes.online += 1,
-                        "offline" => counts.pve_nodes.offline += 1,
+                        "offline" => {
+                            if remote_status == RemoteStatus::Good {
+                                remote_status = RemoteStatus::Warning;
+                            }
+                            remote_messages.push(format!("Node '{}' is offline", r.node));
+                            counts.pve_nodes.offline += 1
+                        }
                         _ => counts.pve_nodes.unknown += 1,
                     }
                     counts.pve_cpu_stats.used += r.cpu * r.maxcpu;
@@ -533,6 +550,11 @@ pub async fn get_status(
                                 counts.sdn_zones.available += 1;
                             }
                             SdnStatus::Error => {
+                                if remote_status == RemoteStatus::Good {
+                                    remote_status = RemoteStatus::Warning;
+                                }
+                                remote_messages
+                                    .push(format!("SDN zone '{}' has an error", zone.id));
                                 counts.sdn_zones.error += 1;
                             }
                             SdnStatus::Pending => {
@@ -586,6 +608,12 @@ pub async fn get_status(
                 }
             }
         }
+
+        counts.remote_list.push(RemoteInfo {
+            name: remote_with_resources.remote_name,
+            status: remote_status,
+            messages: remote_messages,
+        });
     }
 
     counts.pve_cpu_stats.allocated = Some(pve_cpu_allocated);
-- 
2.47.3





  parent reply	other threads:[~2026-05-05  7:32 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-05  7:31 [PATCH datacenter-manager/yew-widget-toolkit/yew-widget-toolkit-assets v2 0/8] add a new map widget for custom views Dominik Csapak
2026-05-05  7:31 ` [PATCH yew-widget-toolkit v2 1/3] js-helper: add client-to-svg-coordinate conversion helper Dominik Csapak
2026-05-05  7:31 ` [PATCH yew-widget-toolkit v2 2/3] widget: charts: add interactive Map with zoom/pan and clustering Dominik Csapak
2026-05-05  7:31 ` [PATCH yew-widget-toolkit v2 3/3] widget: charts: add WorldMap with GeoJSON rendering Dominik Csapak
2026-05-05  7:31 ` [PATCH yew-widget-toolkit-assets v2 1/1] charts: add necessary classes for Map Dominik Csapak
2026-05-05  7:31 ` [PATCH datacenter-manager v2 1/4] lib/api/ui: add location property to remote config Dominik Csapak
2026-05-05  8:26   ` Thomas Lamprecht
2026-05-05  8:36     ` Dominik Csapak
2026-05-05  8:44       ` Thomas Lamprecht
2026-05-05  8:46         ` Dominik Csapak
2026-05-05  7:31 ` Dominik Csapak [this message]
2026-05-05  7:31 ` [PATCH datacenter-manager v2 3/4] ui: add world map geojson update script Dominik Csapak
2026-05-05  7:31 ` [PATCH datacenter-manager v2 4/4] ui: views: add map component Dominik Csapak

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=20260505073203.398548-7-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pdm-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 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