[pdm-devel] [PATCH datacenter-manager 1/5] server: add an optional 'web-url' property for remotes

Dominik Csapak d.csapak at proxmox.com
Fri Jan 10 11:21:38 CET 2025


this contains two optional values to generate a URL for the UI:
* per_node_template: a 'per node' template to generate an url, used for
  all places where we have node information. If not set we use the
  base_url as fallback to generate the url.

* base_url: An URL for reaching the remote. This is e.g. useful if there
  is some reverse proxy or similar between the users browser and the
  remote.

If none is set, the UI will still use the configured connections to
generate an URL.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 lib/pdm-api-types/src/remotes.rs | 23 ++++++++++++++++++++++
 server/src/api/pve/mod.rs        |  2 ++
 server/src/api/remotes.rs        | 33 ++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/lib/pdm-api-types/src/remotes.rs b/lib/pdm-api-types/src/remotes.rs
index 2a8299b..01ee95a 100644
--- a/lib/pdm-api-types/src/remotes.rs
+++ b/lib/pdm-api-types/src/remotes.rs
@@ -36,6 +36,20 @@ pub struct NodeUrl {
     pub fingerprint: Option<String>,
 }
 
+#[api]
+/// Options for the URLs used in the Web UI.
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WebUrl {
+    /// A base URL for accessing the remote.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub base_url: Option<String>,
+
+    /// A template for a per node URL. replaces {{nodename}} with the nodename.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub per_node_template: Option<String>,
+}
+
 #[api]
 /// The type of a remote entry.
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize, Ord, PartialOrd)]
@@ -61,6 +75,10 @@ serde_plain::derive_fromstr_from_deserialize!(RemoteType);
                 description: "A cluster node IP or hostname.",
             },
         },
+        "web-url": {
+            type: String,
+            optional: true,
+        },
     },
 )]
 /// The information required to connect to a remote instance.
@@ -86,6 +104,11 @@ pub struct Remote {
     /// The access token's secret.
     #[updater(serde(skip_serializing_if = "Option::is_none"))]
     pub token: String,
+
+    /// Configuration for the Web UI URL link generation.
+    #[updater(serde(skip_serializing_if = "Option::is_none"))]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub web_url: Option<PropertyString<WebUrl>>,
 }
 
 impl ApiSectionDataEntry for Remote {
diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs
index 0c0ae37..dccfb72 100644
--- a/server/src/api/pve/mod.rs
+++ b/server/src/api/pve/mod.rs
@@ -1306,6 +1306,7 @@ pub async fn scan_remote_pve(
         })],
         authid: authid.clone(),
         token,
+        web_url: None,
     };
 
     let client = connect_or_login(&remote)
@@ -1384,6 +1385,7 @@ pub async fn list_realm_remote_pve(
         })],
         authid: "root at pam".parse()?,
         token: String::new(),
+        web_url: None,
     };
 
     let client = connection::make_pve_client(&remote)?;
diff --git a/server/src/api/remotes.rs b/server/src/api/remotes.rs
index d4412d0..e434e9b 100644
--- a/server/src/api/remotes.rs
+++ b/server/src/api/remotes.rs
@@ -3,6 +3,7 @@
 use std::error::Error as _;
 
 use anyhow::{bail, format_err, Error};
+use serde::{Deserialize, Serialize};
 
 use proxmox_access_control::CachedUserInfo;
 use proxmox_router::{
@@ -178,6 +179,15 @@ pub async fn add_remote(mut entry: Remote, create_token: Option<String>) -> Resu
     Ok(())
 }
 
+#[api()]
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Deletable property name
+pub enum DeletableProperty {
+    /// Delete the web-url property.
+    WebUrl,
+}
+
 // FIXME: Support `OneOf` in schema so we can use a derived Updater for all product types?
 // Otherwise we need to have a custom updater struct that covers all product remotes.
 #[api(
@@ -188,6 +198,14 @@ pub async fn add_remote(mut entry: Remote, create_token: Option<String>) -> Resu
                 flatten: true,
                 type: RemoteUpdater,
             },
+            delete: {
+                description: "List of properties to delete.",
+                type: Array,
+                optional: true,
+                items: {
+                    type: DeletableProperty,
+                }
+            },
             digest: {
                 optional: true,
                 type: ConfigDigest,
@@ -202,6 +220,7 @@ pub async fn add_remote(mut entry: Remote, create_token: Option<String>) -> Resu
 pub fn update_remote(
     id: String,
     updater: RemoteUpdater,
+    delete: Option<Vec<DeletableProperty>>,
     digest: Option<ConfigDigest>,
 ) -> Result<(), Error> {
     let (mut remotes, config_digest) = pdm_config::remotes::config()?;
@@ -211,6 +230,16 @@ pub fn update_remote(
         .get_mut(&id)
         .ok_or_else(|| http_err!(NOT_FOUND, "no such remote {id:?}"))?;
 
+    if let Some(delete) = delete {
+        for delete_prop in delete {
+            match delete_prop {
+                DeletableProperty::WebUrl => {
+                    entry.web_url = None;
+                }
+            }
+        }
+    }
+
     if let Some(v) = updater.nodes {
         entry.nodes = v;
     }
@@ -221,6 +250,10 @@ pub fn update_remote(
         entry.token = v;
     }
 
+    if updater.web_url.is_some() {
+        entry.web_url = updater.web_url;
+    }
+
     pdm_config::remotes::save_config(&remotes)?;
 
     Ok(())
-- 
2.39.5





More information about the pdm-devel mailing list