all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login
@ 2025-12-01 13:52 Dominik Csapak
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
                   ` (10 more replies)
  0 siblings, 11 replies; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:52 UTC (permalink / raw)
  To: pdm-devel

This adds subscription checks + popup for
* login
* 'refresh all' for remote update panel
* 'refresh' for single node update panels

this series contains the RFC patches from fabian too
(so it can be more easily applied)

changes from v1:
* include fabians patches, and rebase on them
* don't do the subscription logic in the ui, but in the backend
  (simplifies the ui changes)
* slightly reordered the patches

proxmox-yew-comp:

Dominik Csapak (2):
  subscription: refactor api subscription check for showing the alert
  apt package manager: add optional subscription check on 'Refresh'
    button

 src/apt_package_manager.rs | 63 ++++++++++++++++++++++++++++++++++++--
 src/apt_repositories.rs    |  8 ++---
 src/lib.rs                 |  2 +-
 src/subscription_alert.rs  | 13 ++++++++
 4 files changed, 76 insertions(+), 10 deletions(-)


proxmox-datacenter-manager:

Dominik Csapak (6):
  server: api: subscription: fix permission check
  server: api: pve/pbs: node: add subscription api call
  ui: pve/pbs: updates: add subscription_url
  ui: login: enable subscription check
  ui: refactor check_subscription into lib
  ui: remote updates: add subscription check on 'Refresh all'

Fabian Grünbichler (3):
  subscription: add serverid field to node subscription info
  api types: add new SubscriptionStatistics
  api: add subscription endpoints

 lib/pdm-api-types/src/subscription.rs |  17 +++
 server/src/api/nodes/mod.rs           |   2 +
 server/src/api/nodes/subscription.rs  | 194 ++++++++++++++++++++++++++
 server/src/api/pbs/node.rs            |  39 +++++-
 server/src/api/pve/node.rs            |  27 ++++
 server/src/api/resources.rs           |   6 +-
 ui/src/lib.rs                         |   9 ++
 ui/src/main.rs                        |  40 ++----
 ui/src/pbs/node/mod.rs                |   2 +
 ui/src/pve/node/mod.rs                |   2 +
 ui/src/remotes/updates.rs             |  48 ++++++-
 11 files changed, 351 insertions(+), 35 deletions(-)
 create mode 100644 server/src/api/nodes/subscription.rs


Summary over all repositories:
  15 files changed, 427 insertions(+), 45 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] 22+ messages in thread

* [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
@ 2025-12-01 13:52 ` Dominik Csapak
  2025-12-01 19:02   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:52 UTC (permalink / raw)
  To: pdm-devel

so we can reuse that

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/apt_repositories.rs   |  8 ++------
 src/lib.rs                |  2 +-
 src/subscription_alert.rs | 13 +++++++++++++
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/src/apt_repositories.rs b/src/apt_repositories.rs
index ae582a6..83463c9 100644
--- a/src/apt_repositories.rs
+++ b/src/apt_repositories.rs
@@ -19,6 +19,7 @@ use pwt::widget::data_table::{
 };
 use pwt::widget::{Button, Column, Container, Fa, Row, Toolbar, Tooltip};
 
+use crate::subscription_alert::subscription_is_active;
 use crate::{
     EditWindow, ExistingProduct, LoadableComponent, LoadableComponentContext,
     LoadableComponentMaster, ProjectInfo, SubscriptionAlert,
@@ -694,12 +695,7 @@ fn standard_repo_info(
 
 impl ProxmoxAptRepositories {
     fn active_subscription(&self) -> bool {
-        match &self.subscription_status {
-            Some(Ok(data)) => {
-                data["status"].as_str().map(|s| s.to_lowercase()).as_deref() == Some("active")
-            }
-            _ => false,
-        }
+        subscription_is_active(&self.subscription_status)
     }
 
     fn create_show_subscription_dialog(
diff --git a/src/lib.rs b/src/lib.rs
index 1fefed8..8e43d35 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -181,7 +181,7 @@ mod submit_value_callback;
 pub use submit_value_callback::{IntoSubmitValueCallback, SubmitValueCallback};
 
 mod subscription_alert;
-pub use subscription_alert::{ProxmoxSubscriptionAlert, SubscriptionAlert};
+pub use subscription_alert::{subscription_is_active, ProxmoxSubscriptionAlert, SubscriptionAlert};
 
 mod subscription_panel;
 pub use subscription_panel::{ProxmoxSubscriptionPanel, SubscriptionPanel};
diff --git a/src/subscription_alert.rs b/src/subscription_alert.rs
index 2dca3c4..7734123 100644
--- a/src/subscription_alert.rs
+++ b/src/subscription_alert.rs
@@ -1,5 +1,8 @@
 use std::rc::Rc;
 
+use anyhow::Error;
+use serde_json::Value;
+
 use yew::html::{IntoEventCallback, IntoPropValue};
 use yew::virtual_dom::{VComp, VNode};
 
@@ -63,3 +66,13 @@ impl From<SubscriptionAlert> for VNode {
         VNode::from(comp)
     }
 }
+
+/// Check if the result of the subscription check returned an active subscription
+pub fn subscription_is_active(result: &Option<Result<Value, Error>>) -> bool {
+    match result {
+        Some(Ok(data)) => {
+            data["status"].as_str().map(|s| s.to_lowercase()).as_deref() == Some("active")
+        }
+        _ => false,
+    }
+}
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

but only if the 'subscription_url' is set on the component.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/apt_package_manager.rs | 63 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 3 deletions(-)

diff --git a/src/apt_package_manager.rs b/src/apt_package_manager.rs
index d01f275..78e82a0 100644
--- a/src/apt_package_manager.rs
+++ b/src/apt_package_manager.rs
@@ -5,6 +5,7 @@ use std::pin::Pin;
 use std::rc::Rc;
 
 use anyhow::Error;
+use serde_json::Value;
 
 use yew::html::IntoEventCallback;
 use yew::html::IntoPropValue;
@@ -17,8 +18,11 @@ use pwt::widget::data_table::{
     DataTable, DataTableCellRenderArgs, DataTableColumn, DataTableHeader, DataTableHeaderGroup,
 };
 use pwt::widget::{Button, Container, Toolbar, Tooltip};
+use pwt::AsyncPool;
 
 use crate::percent_encoding::percent_encode_component;
+use crate::subscription_alert::subscription_is_active;
+use crate::SubscriptionAlert;
 use crate::{
     DataViewWindow, LoadableComponent, LoadableComponentContext, LoadableComponentMaster, XTermJs,
 };
@@ -56,6 +60,11 @@ pub struct AptPackageManager {
     #[prop_or_default]
     #[builder_cb(IntoEventCallback, into_event_callback, ())]
     pub on_upgrade: Option<Callback<()>>,
+
+    #[prop_or_default]
+    #[builder(IntoPropValue, into_prop_value)]
+    /// The base url for the subscription check
+    pub subscription_url: Option<AttrValue>,
 }
 
 impl Default for AptPackageManager {
@@ -142,12 +151,14 @@ fn update_list_to_tree(updates: &[APTUpdateInfo]) -> SlabTree<TreeEntry> {
 #[derive(Clone, PartialEq)]
 pub enum ViewState {
     ShowChangelog(String),
+    ShowSubscriptionPopup,
 }
 
 pub struct ProxmoxAptPackageManager {
     tree_store: TreeStore<TreeEntry>,
     selection: Selection,
     columns: Rc<Vec<DataTableHeader<TreeEntry>>>,
+    async_pool: AsyncPool,
 }
 
 impl LoadableComponent for ProxmoxAptPackageManager {
@@ -164,9 +175,33 @@ impl LoadableComponent for ProxmoxAptPackageManager {
             tree_store,
             selection,
             columns,
+            async_pool: AsyncPool::new(),
         }
     }
 
+    fn update(&mut self, ctx: &LoadableComponentContext<Self>, _msg: Self::Message) -> bool {
+        let link = ctx.link().clone();
+        let props = ctx.props();
+        let url = props
+            .clone()
+            .subscription_url
+            .unwrap_or("/nodes/localhost/subscription".into());
+        let task_base_url = props.task_base_url.clone();
+        let command = format!("{}/update", props.base_url);
+        self.async_pool.spawn(async move {
+            let data = crate::http_get::<Value>(url.as_str(), None).await;
+            let is_active = subscription_is_active(&Some(data));
+
+            if is_active {
+                link.task_base_url(task_base_url);
+                link.start_task(&command, None, false);
+            } else {
+                link.change_view(Some(ViewState::ShowSubscriptionPopup));
+            }
+        });
+        true
+    }
+
     fn load(
         &self,
         ctx: &LoadableComponentContext<Self>,
@@ -211,13 +246,20 @@ impl LoadableComponent for ProxmoxAptPackageManager {
             .class("pwt-w-100")
             .class("pwt-overflow-hidden")
             .class("pwt-border-bottom")
-            .with_child(Button::new(tr!("Refresh")).onclick({
+            .with_child(Button::new(tr!("Refresh")).on_activate({
                 let link = ctx.link();
-
+                let sub_check = props.subscription_url.is_some();
                 link.task_base_url(props.task_base_url.clone());
 
                 let command = format!("{}/update", props.base_url);
-                move |_| link.start_task(&command, None, false)
+
+                move |_| {
+                    if sub_check {
+                        link.send_message(());
+                    } else {
+                        link.start_task(&command, None, false);
+                    }
+                }
             }))
             .with_child(
                 Button::new(tr!("Upgrade"))
@@ -263,6 +305,21 @@ impl LoadableComponent for ProxmoxAptPackageManager {
             ViewState::ShowChangelog(package) => {
                 Some(self.create_show_changelog_dialog(ctx, package))
             }
+            ViewState::ShowSubscriptionPopup => {
+                let link = ctx.link().clone();
+                let props = ctx.props();
+                let task_base_url = props.task_base_url.clone();
+                let command = format!("{}/update", props.base_url);
+                Some(
+                    SubscriptionAlert::new("notfound")
+                        .on_close(move |_| {
+                            link.change_view(None);
+                            link.task_base_url(task_base_url.clone());
+                            link.start_task(&command, None, false);
+                        })
+                        .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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
  2025-12-01 13:53 ` [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

From: Fabian Grünbichler <f.gruenbichler@proxmox.com>

needed to re-use it internally for enterprise repository access.

intentionally not serialized to avoid leaking it.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 lib/pdm-api-types/src/subscription.rs | 4 ++++
 server/src/api/resources.rs           | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/lib/pdm-api-types/src/subscription.rs b/lib/pdm-api-types/src/subscription.rs
index 35910bc7..64167cb8 100644
--- a/lib/pdm-api-types/src/subscription.rs
+++ b/lib/pdm-api-types/src/subscription.rs
@@ -110,6 +110,10 @@ pub struct NodeSubscriptionInfo {
 
     /// The subscription level of the node
     pub level: SubscriptionLevel,
+
+    /// Serverid of the node, if accessible
+    #[serde(skip_serializing)]
+    pub serverid: Option<String>,
 }
 
 #[api(
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 55056e1c..4beaa542 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -891,6 +891,7 @@ async fn fetch_remote_subscription_info(
                             status,
                             sockets: info.sockets,
                             key: info.key,
+                            serverid: info.serverid,
                             level: info
                                 .level
                                 .and_then(|level| level.parse().ok())
@@ -910,6 +911,7 @@ async fn fetch_remote_subscription_info(
                     sockets: None,
                     key: info.key,
                     level,
+                    serverid: info.serverid,
                 }
             });
 
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (2 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

From: Fabian Grünbichler <f.gruenbichler@proxmox.com>

this is a different view for the global subscription status - instead of
looking at the lowest level per remote, count all nodes.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 lib/pdm-api-types/src/subscription.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/lib/pdm-api-types/src/subscription.rs b/lib/pdm-api-types/src/subscription.rs
index 64167cb8..d38611e3 100644
--- a/lib/pdm-api-types/src/subscription.rs
+++ b/lib/pdm-api-types/src/subscription.rs
@@ -143,3 +143,16 @@ pub struct RemoteSubscriptions {
 
     pub state: RemoteSubscriptionState,
 }
+
+#[api]
+#[derive(Default, Serialize, Deserialize, Clone, PartialEq)]
+#[serde(rename_all = "kebab-case")]
+/// Lists the subscription level per node for the remote
+pub struct SubscriptionStatistics {
+    /// Total number of nodes across all remotes
+    pub total_nodes: usize,
+    /// Total number of active subscriptions across all remotes
+    pub active_subscriptions: usize,
+    /// Total number of community level subscriptions across all remotes
+    pub community: usize,
+}
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (3 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

From: Fabian Grünbichler <f.gruenbichler@proxmox.com>

for the PDM system itself, by proxy of how many of the remote nodes have valid
subscriptions above a certain level.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 server/src/api/nodes/mod.rs          |   2 +
 server/src/api/nodes/subscription.rs | 194 +++++++++++++++++++++++++++
 server/src/api/resources.rs          |   2 +-
 3 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 server/src/api/nodes/subscription.rs

diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs
index a0fe14ab..3a795d65 100644
--- a/server/src/api/nodes/mod.rs
+++ b/server/src/api/nodes/mod.rs
@@ -11,6 +11,7 @@ pub mod journal;
 pub mod network;
 pub mod rrddata;
 pub mod status;
+pub mod subscription;
 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),
+    ("subscription", &subscription::ROUTER),
     ("status", &status::ROUTER),
     ("syslog", &syslog::ROUTER),
     ("tasks", &tasks::ROUTER),
diff --git a/server/src/api/nodes/subscription.rs b/server/src/api/nodes/subscription.rs
new file mode 100644
index 00000000..d9b44d59
--- /dev/null
+++ b/server/src/api/nodes/subscription.rs
@@ -0,0 +1,194 @@
+use std::collections::HashMap;
+
+use anyhow::{bail, Error};
+
+use proxmox_router::{Permission, Router};
+use proxmox_schema::api;
+use proxmox_schema::api_types::NODE_SCHEMA;
+use proxmox_subscription::files::update_apt_auth;
+use proxmox_subscription::{SubscriptionInfo, SubscriptionStatus};
+use proxmox_sys::fs::CreateOptions;
+
+use pdm_api_types::remotes::RemoteType;
+use pdm_api_types::subscription::{
+    NodeSubscriptionInfo, SubscriptionLevel, SubscriptionStatistics,
+};
+use pdm_api_types::PRIV_SYS_MODIFY;
+
+use crate::api::resources::get_subscription_info_for_remote;
+
+const PRODUCT_URL: &str = "https://www.proxmox.com/en/proxmox-datacenter-manager/pricing";
+const APT_AUTH_FN: &str = "/etc/apt/auth.conf.d/pdm.conf";
+const APT_AUTH_URL: &str = "enterprise.proxmox.com/debian/pdm";
+
+// minimum ratio of nodes with active subscriptions
+const SUBSCRIPTION_THRESHOLD: f64 = 0.9;
+// max ratio of nodes with community subscriptions, among nodes with subscriptions
+const COMMUNITY_THRESHOLD: f64 = 0.4;
+
+fn apt_auth_file_opts() -> CreateOptions {
+    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
+    CreateOptions::new().perm(mode).owner(nix::unistd::ROOT)
+}
+
+async fn get_all_subscription_infos(
+) -> Result<HashMap<String, (RemoteType, HashMap<String, Option<NodeSubscriptionInfo>>)>, Error> {
+    let (remotes_config, _digest) = pdm_config::remotes::config()?;
+
+    let mut subscription_info = HashMap::new();
+    for (remote_name, remote) in remotes_config.iter() {
+        match get_subscription_info_for_remote(remote, 24 * 60 * 60).await {
+            Ok(info) => {
+                subscription_info.insert(remote_name.to_string(), (remote.ty, info));
+            }
+            Err(err) => {
+                log::debug!("Failed to get subscription info for remote {remote_name} - {err}");
+                subscription_info.insert(remote_name.to_string(), (remote.ty, HashMap::new()));
+            }
+        }
+    }
+    Ok(subscription_info)
+}
+
+fn count_subscriptions(
+    subscription_infos: &HashMap<
+        String,
+        (RemoteType, HashMap<String, Option<NodeSubscriptionInfo>>),
+    >,
+) -> SubscriptionStatistics {
+    let mut stats = SubscriptionStatistics::default();
+    for (_remote, (_remote_type, remote_infos)) in subscription_infos.iter() {
+        if remote_infos.is_empty() {
+            // count remotes without info as at least one node
+            stats.total_nodes += 1;
+            continue;
+        }
+        for (_node, node_info) in remote_infos.iter() {
+            stats.total_nodes += 1;
+            if let Some(info) = node_info {
+                if info.status == SubscriptionStatus::Active {
+                    stats.active_subscriptions += 1;
+                    if info.level == SubscriptionLevel::Community {
+                        stats.community += 1;
+                    }
+                }
+            }
+        }
+    }
+    stats
+}
+
+fn check_counts(stats: SubscriptionStatistics) -> Result<(), Error> {
+    let subscribed_ratio = stats.active_subscriptions as f64 / stats.total_nodes as f64;
+    let community_ratio = stats.community as f64 / stats.active_subscriptions as f64;
+
+    if subscribed_ratio > SUBSCRIPTION_THRESHOLD {
+        if community_ratio < COMMUNITY_THRESHOLD {
+            return Ok(());
+        } else {
+            bail!("Too many remote nodes with community level subscription!");
+        }
+    } else {
+        bail!("Too many remote nodes without active subscription!");
+    }
+}
+
+#[api(
+    access: { permission: &Permission::Anybody, },
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        type: SubscriptionInfo,
+    }
+)]
+/// Return subscription status
+pub async fn get_subscription() -> Result<SubscriptionInfo, Error> {
+    let infos = get_all_subscription_infos().await?;
+
+    let stats = count_subscriptions(&infos);
+
+    if let Err(err) = check_counts(stats) {
+        Ok(SubscriptionInfo {
+            status: SubscriptionStatus::Invalid,
+            message: Some(format!("{err}")),
+            serverid: None,
+            url: Some(PRODUCT_URL.into()),
+            ..Default::default()
+        })
+    } else {
+        Ok(SubscriptionInfo {
+            status: SubscriptionStatus::Active,
+            url: Some(PRODUCT_URL.into()),
+            ..Default::default()
+        })
+    }
+}
+
+#[api(
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
+    protected: true,
+    access: {
+        permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
+    },
+)]
+/// Update subscription information
+pub async fn check_subscription() -> Result<(), Error> {
+    let infos = get_all_subscription_infos().await?;
+    let stats = count_subscriptions(&infos);
+
+    if let Err(err) = check_counts(stats) {
+        update_apt_auth(APT_AUTH_FN, apt_auth_file_opts(), APT_AUTH_URL, None, None)?;
+        return Err(err);
+    }
+
+    let mut found = false;
+    'outer: for (remote, (remote_type, remote_info)) in infos.iter() {
+        if *remote_type != RemoteType::Pve || *remote_type != RemoteType::Pbs {
+            continue;
+        }
+        for (node, node_info) in remote_info.iter() {
+            if let Some(info) = node_info {
+                if info.status == SubscriptionStatus::Active
+                    && info.level >= SubscriptionLevel::Basic
+                    && info.key.is_some()
+                    && info.serverid.is_some()
+                {
+                    log::info!("Using subscription of node '{node}' of remote '{remote}' for enterprise repository access");
+                    update_apt_auth(
+                        APT_AUTH_FN,
+                        apt_auth_file_opts(),
+                        APT_AUTH_URL,
+                        info.key.clone(),
+                        info.serverid.clone(),
+                    )?;
+                    found = true;
+                    break 'outer;
+                }
+            }
+        }
+    }
+
+    if !found {
+        log::warn!(
+            "No valid Basic+ subscription found for configuring enterprise repository access.."
+        );
+        update_apt_auth(APT_AUTH_FN, apt_auth_file_opts(), APT_AUTH_URL, None, None)?;
+    }
+
+    Ok(())
+}
+
+pub const ROUTER: Router = Router::new()
+    .get(&API_METHOD_GET_SUBSCRIPTION)
+    .post(&API_METHOD_CHECK_SUBSCRIPTION);
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 4beaa542..adab021a 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -767,7 +767,7 @@ static SUBSCRIPTION_CACHE: LazyLock<RwLock<HashMap<String, CachedSubscriptionSta
 ///
 /// If recent enough cached data is available, it is returned
 /// instead of calling out to the remote.
-async fn get_subscription_info_for_remote(
+pub async fn get_subscription_info_for_remote(
     remote: &Remote,
     max_age: u64,
 ) -> Result<HashMap<String, Option<NodeSubscriptionInfo>>, Error> {
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (4 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

we have here a 'check_priv' that should return if the permission check
was successful. So instead of wrongly check for 'is_err', rather check
for 'is_ok'.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/resources.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index adab021a..1193c26a 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -616,7 +616,7 @@ pub async fn get_subscription_status(
                 PRIV_RESOURCE_AUDIT,
                 false,
             )
-            .is_err()
+            .is_ok()
     };
 
     for (remote_name, remote) in remotes_config {
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (5 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

returns the subscription information per node

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/pbs/node.rs | 39 +++++++++++++++++++++++++++++++++++++-
 server/src/api/pve/node.rs | 27 ++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/server/src/api/pbs/node.rs b/server/src/api/pbs/node.rs
index cf8cbea5..aafefc2a 100644
--- a/server/src/api/pbs/node.rs
+++ b/server/src/api/pbs/node.rs
@@ -1,6 +1,17 @@
-use proxmox_router::{list_subdirs_api_method, Router, SubdirMap};
+use anyhow::Error;
+
+use proxmox_router::{list_subdirs_api_method, Permission, Router, SubdirMap};
+use proxmox_schema::api;
 use proxmox_sortable_macro::sortable;
 
+use pdm_api_types::remotes::REMOTE_ID_SCHEMA;
+use pdm_api_types::PRIV_RESOURCE_AUDIT;
+
+use pbs_api_types::NODE_SCHEMA;
+
+use crate::connection;
+use crate::pbs_client::get_remote;
+
 pub const ROUTER: Router = Router::new()
     .get(&list_subdirs_api_method!(SUBDIRS))
     .subdirs(SUBDIRS);
@@ -8,6 +19,10 @@ pub const ROUTER: Router = Router::new()
 #[sortable]
 const SUBDIRS: SubdirMap = &sorted!([
     ("apt", &crate::api::remote_updates::APT_ROUTER),
+    (
+        "subscription",
+        &Router::new().get(&API_METHOD_GET_SUBSCRIPTION)
+    ),
     (
         "termproxy",
         &Router::new().post(&crate::api::remote_shell::API_METHOD_SHELL_TICKET)
@@ -17,3 +32,25 @@ const SUBDIRS: SubdirMap = &sorted!([
         &Router::new().upgrade(&crate::api::remote_shell::API_METHOD_SHELL_WEBSOCKET)
     ),
 ]);
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+            node: { schema: NODE_SCHEMA }, // not used, always localhost
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_AUDIT, false),
+        description: "The user needs to have at least the `Resource.Audit` privilege on `/resource/{remote}`."
+    },
+    returns: { type: proxmox_subscription::SubscriptionInfo }
+)]
+/// Get subscription for the PBS remote
+async fn get_subscription(remote: String) -> Result<proxmox_subscription::SubscriptionInfo, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+    let remote = get_remote(&remotes, &remote)?;
+    Ok(connection::make_pbs_client(remote)?
+        .get_subscription()
+        .await?)
+}
diff --git a/server/src/api/pve/node.rs b/server/src/api/pve/node.rs
index d8690f63..376234c7 100644
--- a/server/src/api/pve/node.rs
+++ b/server/src/api/pve/node.rs
@@ -29,6 +29,10 @@ const SUBDIRS: SubdirMap = &sorted!([
     ),
     ("storage", &STORAGE_ROUTER),
     ("status", &Router::new().get(&API_METHOD_GET_STATUS)),
+    (
+        "subscription",
+        &Router::new().get(&API_METHOD_GET_SUBSCRIPTION)
+    ),
 ]);
 
 const STORAGE_ROUTER: Router = Router::new()
@@ -153,3 +157,26 @@ async fn get_status(remote: String, node: String) -> Result<pve_api_types::NodeS
     let result = client.node_status(&node).await?;
     Ok(result)
 }
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+            node: { schema: NODE_SCHEMA },
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false),
+    },
+    returns: { type: pve_api_types::NodeStatus },
+)]
+/// Get subscription for the node
+async fn get_subscription(
+    remote: String,
+    node: String,
+) -> Result<pve_api_types::NodeSubscriptionInfo, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+    let client = super::connect_to_remote(&remotes, &remote)?;
+    let result = client.get_subscription(&node).await?;
+    Ok(result)
+}
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (6 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

so the 'Refresh' button does a subscription check.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/pbs/node/mod.rs | 2 ++
 ui/src/pve/node/mod.rs | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/ui/src/pbs/node/mod.rs b/ui/src/pbs/node/mod.rs
index 2033bb14..19ddce72 100644
--- a/ui/src/pbs/node/mod.rs
+++ b/ui/src/pbs/node/mod.rs
@@ -89,10 +89,12 @@ impl yew::Component for PbsNodePanelComp {
                     move |_| {
                         let base_url = format!("/pbs/remotes/{remote}/nodes/localhost/apt");
                         let task_base_url = format!("/pbs/remotes/{remote}/tasks");
+                        let sub_url = format!("/pbs/remotes/{remote}/nodes/localhost/subscription");
 
                         AptPackageManager::new()
                             .base_url(base_url)
                             .task_base_url(task_base_url)
+                            .subscription_url(sub_url)
                             .enable_upgrade(true)
                             .on_upgrade({
                                 let remote = remote.clone();
diff --git a/ui/src/pve/node/mod.rs b/ui/src/pve/node/mod.rs
index 1fcd92eb..332c26a8 100644
--- a/ui/src/pve/node/mod.rs
+++ b/ui/src/pve/node/mod.rs
@@ -86,10 +86,12 @@ impl yew::Component for PveNodePanelComp {
                     move |_| {
                         let base_url = format!("/pve/remotes/{remote}/nodes/{node}/apt");
                         let task_base_url = format!("/pve/remotes/{remote}/tasks");
+                        let sub_url = format!("/pve/remotes/{remote}/nodes/{node}/subscription");
 
                         AptPackageManager::new()
                             .base_url(base_url)
                             .task_base_url(task_base_url)
+                            .subscription_url(sub_url)
                             .enable_upgrade(true)
                             .on_upgrade({
                                 let remote = remote.clone();
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (7 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

show popup when the local subscription check fails

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* use nodes/localhost endpoint instead of the dashboard one

 ui/src/main.rs | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/ui/src/main.rs b/ui/src/main.rs
index 454a2927..9cff3833 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -1,6 +1,6 @@
 use anyhow::Error;
 use gloo_timers::callback::Timeout;
-use serde_json::json;
+use serde_json::{json, Value};
 use wasm_bindgen::JsCast;
 use web_sys::HtmlElement;
 
@@ -21,7 +21,6 @@ use proxmox_yew_comp::{
 };
 
 //use pbs::MainMenu;
-use pdm_api_types::subscription::{RemoteSubscriptionState, RemoteSubscriptions};
 use pdm_api_types::views::ViewConfig;
 use pdm_ui::{
     register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry, SearchProvider, TopNavBar,
@@ -64,16 +63,10 @@ struct DatacenterManagerApp {
 }
 
 async fn check_subscription() -> Msg {
-    let data: Result<Vec<RemoteSubscriptions>, _> = http_get("/resources/subscription", None).await;
+    let data: Result<Value, _> = http_get("/nodes/localhost/subscription", None).await;
 
-    let show_alert = match data {
-        Ok(list) => list
-            .into_iter()
-            .any(|info| info.state == RemoteSubscriptionState::None),
-        Err(_) => false,
-    };
-
-    if show_alert {
+    let is_active = proxmox_yew_comp::subscription_is_active(&Some(data));
+    if !is_active {
         Msg::ShowSubscriptionAlert
     } else {
         Msg::ConfirmSubscription
@@ -246,11 +239,8 @@ impl Component for DatacenterManagerApp {
                 true
             }
             Msg::ShowSubscriptionAlert => {
-                // Disable for alpha and rework for a beta or stable version to avoid friction if a
-                // few unsubscribed test instances are present in another subscribed (big) setup.
-                // self.show_subscription_alert = Some(true);
-                self.subscription_confirmed = true;
-                self.show_subscription_alert = Some(false);
+                self.subscription_confirmed = false;
+                self.show_subscription_alert = Some(true);
                 true
             }
             Msg::Logout => {
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (8 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

so we can reuse the global subscription check logic elsewhere

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/lib.rs  |  9 +++++++++
 ui/src/main.rs | 28 ++++++++++++----------------
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/ui/src/lib.rs b/ui/src/lib.rs
index 27a51084..d8225a42 100644
--- a/ui/src/lib.rs
+++ b/ui/src/lib.rs
@@ -3,6 +3,9 @@ use pdm_api_types::remotes::RemoteType;
 use pdm_api_types::resource::{PveLxcResource, PveNetworkResource, PveQemuResource};
 use pdm_client::types::Resource;
 use serde::{Deserialize, Serialize};
+use serde_json::Value;
+
+use proxmox_yew_comp::http_get;
 
 mod administration;
 
@@ -234,3 +237,9 @@ pub(crate) fn locale_compare(first: String, second: &str, numeric: bool) -> std:
         .locale_compare(second, &Array::new(), &options)
         .cmp(&0)
 }
+
+/// Returns true if the global subscription checks succeeded
+pub async fn check_subscription() -> bool {
+    let data: Result<Value, _> = http_get("/nodes/localhost/subscription", None).await;
+    proxmox_yew_comp::subscription_is_active(&Some(data))
+}
diff --git a/ui/src/main.rs b/ui/src/main.rs
index 9cff3833..b7dd3ef1 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -1,6 +1,6 @@
 use anyhow::Error;
 use gloo_timers::callback::Timeout;
-use serde_json::{json, Value};
+use serde_json::json;
 use wasm_bindgen::JsCast;
 use web_sys::HtmlElement;
 
@@ -23,8 +23,8 @@ use proxmox_yew_comp::{
 //use pbs::MainMenu;
 use pdm_api_types::views::ViewConfig;
 use pdm_ui::{
-    register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry, SearchProvider, TopNavBar,
-    ViewListContext,
+    check_subscription, register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry,
+    SearchProvider, TopNavBar, ViewListContext,
 };
 
 type MsgRemoteList = Result<RemoteList, Error>;
@@ -62,17 +62,6 @@ struct DatacenterManagerApp {
     async_pool: AsyncPool,
 }
 
-async fn check_subscription() -> Msg {
-    let data: Result<Value, _> = http_get("/nodes/localhost/subscription", None).await;
-
-    let is_active = proxmox_yew_comp::subscription_is_active(&Some(data));
-    if !is_active {
-        Msg::ShowSubscriptionAlert
-    } else {
-        Msg::ConfirmSubscription
-    }
-}
-
 /*
 async fn get_fingerprint() -> Option<Msg> {
     http_get("/nodes/localhost/status", None)
@@ -89,8 +78,15 @@ impl DatacenterManagerApp {
                 if self.subscription_confirmed {
                     ctx.link().send_message(Msg::ConfirmSubscription);
                 } else {
-                    self.async_pool
-                        .send_future(ctx.link().clone(), check_subscription());
+                    self.async_pool.send_future(ctx.link().clone(), async move {
+                        let is_active = check_subscription().await;
+
+                        if !is_active {
+                            Msg::ShowSubscriptionAlert
+                        } else {
+                            Msg::ConfirmSubscription
+                        }
+                    });
                 }
             } else {
                 ctx.link().send_message(Msg::ConfirmSubscription);
-- 
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] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all'
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (9 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

in pve/pbs we do a check on refreshing too, so it's only fitting to do
one here as well.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/remotes/updates.rs | 48 +++++++++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 5 deletions(-)

diff --git a/ui/src/remotes/updates.rs b/ui/src/remotes/updates.rs
index 020a2c4b..2237d310 100644
--- a/ui/src/remotes/updates.rs
+++ b/ui/src/remotes/updates.rs
@@ -19,7 +19,7 @@ use proxmox_deb_version;
 
 use proxmox_yew_comp::{
     AptPackageManager, AptRepositories, ExistingProduct, LoadableComponent,
-    LoadableComponentContext, LoadableComponentMaster,
+    LoadableComponentContext, LoadableComponentMaster, SubscriptionAlert,
 };
 use pwt::props::{CssBorderBuilder, CssPaddingBuilder, WidgetStyleBuilder};
 use pwt::widget::{Button, Container, Panel, Tooltip};
@@ -35,7 +35,7 @@ use pwt::{
     },
 };
 
-use crate::{get_deep_url, get_deep_url_low_level, pdm_client};
+use crate::{check_subscription, get_deep_url, get_deep_url_low_level, pdm_client};
 
 #[derive(PartialEq, Properties)]
 pub struct UpdateTree {}
@@ -120,6 +120,7 @@ enum RemoteUpdateTreeMsg {
     LoadFinished(UpdateSummary),
     KeySelected(Option<Key>),
     RefreshAll,
+    CheckSubscription,
 }
 
 struct UpdateTreeComponent {
@@ -303,10 +304,15 @@ fn build_store_from_response(update_summary: UpdateSummary) -> SlabTree<UpdateTr
     tree
 }
 
+#[derive(PartialEq)]
+enum ViewState {
+    ShowSubscriptionAlert,
+}
+
 impl LoadableComponent for UpdateTreeComponent {
     type Properties = UpdateTree;
     type Message = RemoteUpdateTreeMsg;
-    type ViewState = ();
+    type ViewState = ViewState;
 
     fn create(ctx: &LoadableComponentContext<Self>) -> Self {
         let link = ctx.link();
@@ -343,6 +349,24 @@ impl LoadableComponent for UpdateTreeComponent {
         })
     }
 
+    fn dialog_view(
+        &self,
+        ctx: &LoadableComponentContext<Self>,
+        view_state: &Self::ViewState,
+    ) -> Option<Html> {
+        let link = ctx.link().clone();
+        match view_state {
+            ViewState::ShowSubscriptionAlert => Some(
+                SubscriptionAlert::new("notfound")
+                    .on_close(move |_| {
+                        link.change_view(None);
+                        link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+                    })
+                    .into(),
+            ),
+        }
+    }
+
     fn update(&mut self, ctx: &LoadableComponentContext<Self>, msg: Self::Message) -> bool {
         match msg {
             Self::Message::LoadFinished(updates) => {
@@ -363,6 +387,18 @@ impl LoadableComponent for UpdateTreeComponent {
                     return true;
                 }
             }
+            Self::Message::CheckSubscription => {
+                let link = ctx.link();
+
+                link.clone().spawn(async move {
+                    let is_active = check_subscription().await;
+                    if !is_active {
+                        link.change_view(Some(ViewState::ShowSubscriptionAlert));
+                    } else {
+                        link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+                    }
+                });
+            }
             Self::Message::RefreshAll => {
                 let link = ctx.link();
 
@@ -407,7 +443,7 @@ impl UpdateTreeComponent {
         let refresh_all_button = Button::new(tr!("Refresh all")).on_activate({
             let link = ctx.link().clone();
             move |_| {
-                link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+                link.send_message(RemoteUpdateTreeMsg::CheckSubscription);
             }
         });
 
@@ -667,7 +703,9 @@ fn render_version_column(tree_entry: &UpdateTreeEntry, expanded: bool) -> Html {
             let (icon, extra) = match remote_entry.mixed_versions {
                 MixedVersions::None => ("", "".to_string()),
                 MixedVersions::DifferentMajor => ("times-circle", tr!("major difference")),
-                MixedVersions::DifferentMinor => ("exclamation-triangle", tr!("substantial difference")),
+                MixedVersions::DifferentMinor => {
+                    ("exclamation-triangle", tr!("substantial difference"))
+                }
                 MixedVersions::DifferentPatch => ("info-circle", tr!("small difference")),
             };
             let version_string = remote_entry.product_version.clone().unwrap_or_default();
-- 
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] 22+ messages in thread

* [pdm-devel] applied: [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
@ 2025-12-01 19:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 19:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:52:59 +0100, Dominik Csapak wrote:
> so we can reuse that
> 
> 

Applied, thanks!

[1/2] subscription: refactor api subscription check for showing the alert
      commit: e4a37b08caa53a1112e3deba9d0c1acd1f09e317
[2/2] apt package manager: add optional subscription check on 'Refresh' button
      commit: d63ed6a9bf4b3dd951e902724df387761705e6fe


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:01 +0100, Dominik Csapak wrote:
> needed to re-use it internally for enterprise repository access.
> 
> intentionally not serialized to avoid leaking it.
> 
> 

Applied, thanks!

[1/9] subscription: add serverid field to node subscription info
      commit: 2bacd0218f0f4645a00230661f62446c9cd9b9f0


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:02 +0100, Dominik Csapak wrote:
> this is a different view for the global subscription status - instead of
> looking at the lowest level per remote, count all nodes.
> 
> 

Applied, thanks!

[2/9] api types: add new SubscriptionStatistics
      commit: 34da28404b074ea62bd6f76c38d443f6b8b7042f


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 3/9] api: add subscription endpoints
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:03 +0100, Dominik Csapak wrote:
> for the PDM system itself, by proxy of how many of the remote nodes have valid
> subscriptions above a certain level.
> 
> 

Applied, thanks!

[3/9] api: add subscription endpoints
      commit: d7e8041d36b6ab95058d6f9b7782466e35ef6c7e


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:04 +0100, Dominik Csapak wrote:
> we have here a 'check_priv' that should return if the permission check
> was successful. So instead of wrongly check for 'is_err', rather check
> for 'is_ok'.
> 
> 

Applied, thanks!

[4/9] server: api: subscription: fix permission check
      commit: ab3a09a37faef1b7ded4cbc00650229da6434431


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:05 +0100, Dominik Csapak wrote:
> returns the subscription information per node
> 
> 

Applied, thanks!

[5/9] server: api: pve/pbs: node: add subscription api call
      commit: a7dfdf574f0d0de7ce4bb95abed5960b73c313d3


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:06 +0100, Dominik Csapak wrote:
> so the 'Refresh' button does a subscription check.
> 
> 

Applied, thanks!

[6/9] ui: pve/pbs: updates: add subscription_url
      commit: 298590097e2be56855cdbaff0132e463f2b4a3c8


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
@ 2025-12-01 23:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:07 +0100, Dominik Csapak wrote:
> show popup when the local subscription check fails
> 
> 

Applied, thanks!

[7/9] ui: login: enable subscription check
      commit: 3d543c93c797e679e669383a517c62ac4cf8754c


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
@ 2025-12-01 23:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:08 +0100, Dominik Csapak wrote:
> so we can reuse the global subscription check logic elsewhere
> 
> 

Applied, thanks!

[8/9] ui: refactor check_subscription into lib
      commit: 18853280426a39f93b024c06f927525d274d189c


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


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

* [pdm-devel] applied: [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all'
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
@ 2025-12-01 23:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:09 +0100, Dominik Csapak wrote:
> in pve/pbs we do a check on refreshing too, so it's only fitting to do
> one here as well.
> 
> 

Applied, thanks!

[9/9] ui: remote updates: add subscription check on 'Refresh all'
      commit: 2ff678f65138f336d3eb88ee45aa8af2624280d9


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


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

end of thread, other threads:[~2025-12-01 23:02 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
2025-12-01 19:02   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal