all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs
@ 2026-04-10 10:02 Fabian Grünbichler
  2026-04-10 10:02 ` [PATCH proxmox 1/6] systemd: add support for machine-id generation Fabian Grünbichler
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

instead of only supporting one variant of server IDs, get a list of possible
candidates via the proxmox-subscription crate. if a subscription is already
configured, the matching server ID will be reused to avoid reissuing.

this is just smoke tested for PVE, and missing PDM/PMG/POM changes as well as
end-to-end testing..

proxmox:

Fabian Grünbichler (2):
  systemd: add support for machine-id generation
  proxmox-subscription: add new machine-id based serverid

 proxmox-subscription/Cargo.toml               |   3 +-
 proxmox-subscription/debian/control           |   2 +
 proxmox-subscription/src/lib.rs               |   2 +-
 proxmox-subscription/src/subscription_info.rs | 105 ++++++++++++++++--
 proxmox-systemd/src/lib.rs                    |   2 +
 proxmox-systemd/src/sd_id128.rs               |  70 ++++++++++++
 proxmox-systemd/src/sys.rs                    |   6 +
 7 files changed, 176 insertions(+), 14 deletions(-)
 create mode 100644 proxmox-systemd/src/sd_id128.rs


proxmox-backup:

Fabian Grünbichler (1):
  subscription: adapt to multiple server ID variants

 src/api2/node/subscription.rs | 38 ++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 10 deletions(-)


proxmox-perl-rs:

Fabian Grünbichler (1):
  common: subscription: expose server ID candidates

 common/src/bindings/subscription.rs | 11 +++++++++++
 1 file changed, 11 insertions(+)


pve-manager:

Fabian Grünbichler (2):
  subscription: adapt to multiple server ID variants
  api2tools: remove unused get_hwaddress

 PVE/API2/Subscription.pm | 26 ++++++++++++++++++++------
 PVE/API2Tools.pm         | 23 -----------------------
 2 files changed, 20 insertions(+), 29 deletions(-)


Summary over all repositories:
  11 files changed, 235 insertions(+), 53 deletions(-)

-- 
Generated by murpp 0.11.0




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

* [PATCH proxmox 1/6] systemd: add support for machine-id generation
  2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
@ 2026-04-10 10:02 ` Fabian Grünbichler
  2026-04-10 10:02 ` [RFC proxmox 2/6] proxmox-subscription: add new machine-id based serverid Fabian Grünbichler
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

the plain machine-id should not be leaked to external systems, but libsystemd
provides helpers for deriving application-id based identifiers that are useful
for identifying a machine externally.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---

Notes:
    to be used in the next patch by proxmox-subscription

 proxmox-systemd/src/lib.rs      |  2 +
 proxmox-systemd/src/sd_id128.rs | 70 +++++++++++++++++++++++++++++++++
 proxmox-systemd/src/sys.rs      |  6 +++
 3 files changed, 78 insertions(+)
 create mode 100644 proxmox-systemd/src/sd_id128.rs

diff --git a/proxmox-systemd/src/lib.rs b/proxmox-systemd/src/lib.rs
index 456d88c3..f79c204c 100644
--- a/proxmox-systemd/src/lib.rs
+++ b/proxmox-systemd/src/lib.rs
@@ -7,3 +7,5 @@ pub use escape::{escape_unit, unescape_unit, unescape_unit_path, UnescapeError};
 
 pub mod journal;
 pub mod notify;
+
+pub mod sd_id128;
diff --git a/proxmox-systemd/src/sd_id128.rs b/proxmox-systemd/src/sd_id128.rs
new file mode 100644
index 00000000..a98a6663
--- /dev/null
+++ b/proxmox-systemd/src/sd_id128.rs
@@ -0,0 +1,70 @@
+use std::fmt;
+
+use crate::sys::{self, sd_id128_t};
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum SystemdId128Error {
+    InvalidAppId,
+    GenerationError,
+}
+
+impl std::error::Error for SystemdId128Error {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        None
+    }
+}
+
+impl fmt::Display for SystemdId128Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            SystemdId128Error::InvalidAppId => f.write_str("Provided application ID is invalid."),
+            SystemdId128Error::GenerationError => {
+                f.write_str("Failed to generate machine-id based on application ID.")
+            }
+        }
+    }
+}
+
+pub fn get_app_specific_id(app_id: [u8; 16]) -> Result<[u8; 16], SystemdId128Error> {
+    let mut res = sd_id128_t { bytes: [0; 16] };
+
+    if app_id.iter().all(|b| *b == 0) {
+        return Err(SystemdId128Error::InvalidAppId);
+    }
+    unsafe {
+        sys::sd_id128_get_machine_app_specific(sd_id128_t { bytes: app_id }, &mut res);
+    }
+    if res.bytes.iter().all(|b| *b == 0) {
+        return Err(SystemdId128Error::GenerationError);
+    }
+    Ok(res.bytes)
+}
+
+#[test]
+fn test_invalid_app_id() {
+    let invalid = [0; 16];
+    let res = get_app_specific_id(invalid);
+    assert!(res.is_err());
+    assert_eq!(res, Err(SystemdId128Error::InvalidAppId));
+}
+
+#[test]
+fn test_valid_app_id() {
+    // no machine-id, no app-specific ID either..
+    if !std::path::Path::new("/etc/machine-id").exists() {
+        return;
+    }
+
+    // UUID generated with `systemd-id128 new` and converted from hex
+    let valid = 950247666410175165299169499632875718_u128.to_le_bytes();
+
+    let res = get_app_specific_id(valid);
+    assert!(res.is_ok());
+
+    let res2 = get_app_specific_id(valid);
+    assert!(res2.is_ok());
+
+    // cannot verify the expected result, since that depends on the machine the test runs on
+    // we can verify that two generations using the same machine and app-id give identical results
+    assert_eq!(res, res2);
+}
diff --git a/proxmox-systemd/src/sys.rs b/proxmox-systemd/src/sys.rs
index eabd44d1..ea2b6061 100644
--- a/proxmox-systemd/src/sys.rs
+++ b/proxmox-systemd/src/sys.rs
@@ -4,6 +4,11 @@ use std::os::fd::RawFd;
 
 pub const LISTEN_FDS_START: RawFd = 3;
 
+#[repr(C)]
+pub struct sd_id128_t {
+    pub bytes: [u8; 16],
+}
+
 #[link(name = "systemd")]
 unsafe extern "C" {
     pub fn sd_journal_stream_fd(
@@ -24,6 +29,7 @@ unsafe extern "C" {
         unset_environment: c_int,
         names: *mut *mut *mut c_char,
     ) -> c_int;
+    pub fn sd_id128_get_machine_app_specific(app_id: sd_id128_t, ret: *mut sd_id128_t) -> c_int;
 }
 
 pub fn check_call(ret: c_int) -> Result<c_int, io::Error> {
-- 
2.47.3





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

* [RFC proxmox 2/6] proxmox-subscription: add new machine-id based serverid
  2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
  2026-04-10 10:02 ` [PATCH proxmox 1/6] systemd: add support for machine-id generation Fabian Grünbichler
@ 2026-04-10 10:02 ` Fabian Grünbichler
  2026-04-10 10:02 ` [RFC proxmox-backup 3/6] subscription: adapt to multiple server ID variants Fabian Grünbichler
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

and adapt the code to allow querying all possible serverids, and accepting the
existing one if it matches one of the candidates.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---

Notes:
    requires bumped librust-proxmox-systemd-dev

 proxmox-subscription/Cargo.toml               |   3 +-
 proxmox-subscription/debian/control           |   2 +
 proxmox-subscription/src/lib.rs               |   2 +-
 proxmox-subscription/src/subscription_info.rs | 105 ++++++++++++++++--
 4 files changed, 98 insertions(+), 14 deletions(-)

diff --git a/proxmox-subscription/Cargo.toml b/proxmox-subscription/Cargo.toml
index dda31a69..4db7ca71 100644
--- a/proxmox-subscription/Cargo.toml
+++ b/proxmox-subscription/Cargo.toml
@@ -23,11 +23,12 @@ proxmox-base64 = { workspace = true, optional = true }
 proxmox-http = { workspace = true, optional = true, features = ["client-trait", "http-helpers"] }
 proxmox-serde.workspace = true
 proxmox-sys = { workspace = true, optional = true }
+proxmox-systemd = { workspace = true, optional = true }
 proxmox-time = { workspace = true, optional = true }
 
 proxmox-schema = { workspace = true, features = ["api-macro"], optional = true }
 
 [features]
 default = ["impl"]
-impl = [ "dep:proxmox-base64", "dep:hex", "dep:openssl", "dep:proxmox-http", "dep:proxmox-sys", "dep:proxmox-time"]
+impl = [ "dep:proxmox-base64", "dep:hex", "dep:openssl", "dep:proxmox-http", "dep:proxmox-sys", "dep:proxmox-systemd", "dep:proxmox-time"]
 api-types = ["dep:proxmox-schema"]
diff --git a/proxmox-subscription/debian/control b/proxmox-subscription/debian/control
index 5fbfcccb..5584d0c1 100644
--- a/proxmox-subscription/debian/control
+++ b/proxmox-subscription/debian/control
@@ -16,6 +16,7 @@ Build-Depends-Arch: cargo:native <!nocheck>,
  librust-proxmox-serde-1+default-dev <!nocheck>,
  librust-proxmox-serde-1+serde-json-dev <!nocheck>,
  librust-proxmox-sys-1+default-dev <!nocheck>,
+ librust-proxmox-systemd-1+default-dev <!nocheck>,
  librust-proxmox-time-2+default-dev (>= 2.1.0-~~) <!nocheck>,
  librust-regex-1+default-dev (>= 1.5-~~) <!nocheck>,
  librust-serde-1+default-dev <!nocheck>,
@@ -78,6 +79,7 @@ Depends:
  librust-proxmox-http-1+default-dev (>= 1.0.5-~~),
  librust-proxmox-http-1+http-helpers-dev (>= 1.0.5-~~),
  librust-proxmox-sys-1+default-dev,
+ librust-proxmox-systemd-1+default-dev,
  librust-proxmox-time-2+default-dev (>= 2.1.0-~~)
 Provides:
  librust-proxmox-subscription+default-dev (= ${binary:Version}),
diff --git a/proxmox-subscription/src/lib.rs b/proxmox-subscription/src/lib.rs
index 2ed96903..eb1573e6 100644
--- a/proxmox-subscription/src/lib.rs
+++ b/proxmox-subscription/src/lib.rs
@@ -3,7 +3,7 @@
 mod subscription_info;
 #[cfg(feature = "impl")]
 pub use subscription_info::{
-    get_hardware_address, ProductType, SubscriptionInfo, SubscriptionStatus,
+    get_hardware_address_candidates, ProductType, ServerId, SubscriptionInfo, SubscriptionStatus,
 };
 
 #[cfg(not(feature = "impl"))]
diff --git a/proxmox-subscription/src/subscription_info.rs b/proxmox-subscription/src/subscription_info.rs
index f53b3ce3..f0daa51f 100644
--- a/proxmox-subscription/src/subscription_info.rs
+++ b/proxmox-subscription/src/subscription_info.rs
@@ -47,6 +47,43 @@ impl std::fmt::Display for SubscriptionStatus {
     }
 }
 
+/// Variant discriminator for `ServerId`
+#[derive(Clone, Copy, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
+pub enum ServerIdType {
+    /// Legacy variant tied to SSH host key, for backwards compatibility
+    SshMd5,
+    /// Tied to /etc/machine-id
+    MachineId,
+}
+
+impl Display for ServerIdType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let txt = match self {
+            ServerIdType::SshMd5 => "SSH MD5",
+            ServerIdType::MachineId => "machine-id",
+        };
+        f.write_str(txt)
+    }
+}
+
+/// Serverid used to bind subscription key to system
+pub struct ServerId {
+    ty: ServerIdType,
+    id: String,
+}
+
+impl ServerId {
+    pub fn kind(&self) -> ServerIdType {
+        self.ty
+    }
+}
+
+impl Display for ServerId {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(&self.id)
+    }
+}
+
 #[cfg_attr(feature = "api-types", api())]
 #[cfg_attr(feature = "api-types", derive(Updater))]
 #[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
@@ -133,7 +170,7 @@ pub struct SubscriptionInfo {
 }
 
 #[cfg(feature = "impl")]
-pub use _impl::get_hardware_address;
+pub use _impl::get_hardware_address_candidates;
 
 #[cfg(feature = "impl")]
 pub(crate) use _impl::{md5sum, SHARED_KEY_DATA};
@@ -151,6 +188,10 @@ mod _impl {
 
     use crate::sign::Verifier;
 
+    // Generated using `systemd-sd128 new`
+    pub(crate) const PMX_APPLICATION_ID: [u8; 16] =
+        0x0e6b456a63fe4892997e9f42ebfaf980_u128.to_le_bytes();
+
     pub(crate) const SHARED_KEY_DATA: &str = "kjfdlskfhiuewhfk947368";
 
     /// How long the local key is valid for in between remote checks
@@ -245,7 +286,7 @@ mod _impl {
         /// `status` is set to [SubscriptionStatus::Invalid] and `message` to a human-readable
         ///  message in case it does not.
         pub fn check_server_id(&mut self) {
-            match (self.serverid.as_ref(), get_hardware_address()) {
+            match (self.serverid.as_ref(), get_hardware_address_candidates()) {
                 (_, Err(err)) => {
                     self.status = SubscriptionStatus::Invalid;
                     self.message = Some(format!("Failed to obtain server ID - {err}."));
@@ -256,7 +297,9 @@ mod _impl {
                     self.message = Some("Missing server ID.".to_string());
                     self.signature = None;
                 }
-                (Some(contained), Ok(expected)) if &expected != contained => {
+                (Some(contained), Ok(expected))
+                    if !expected.iter().any(|serverid| serverid.id == *contained) =>
+                {
                     self.status = SubscriptionStatus::Invalid;
                     self.message = Some("Server ID mismatch.".to_string());
                     self.signature = None;
@@ -316,16 +359,54 @@ mod _impl {
         hash(MessageDigest::md5(), data).map_err(Error::from)
     }
 
+    fn get_hardware_address(ty: super::ServerIdType) -> Result<super::ServerId, Error> {
+        fn get_ssh_key() -> Result<Vec<u8>, Error> {
+            static FILENAME: &str = "/etc/ssh/ssh_host_rsa_key.pub";
+
+            proxmox_sys::fs::file_get_contents(FILENAME)
+                .map_err(|e| format_err!("Error getting host key - {}", e))
+        }
+
+        let id = match ty {
+            crate::subscription_info::ServerIdType::SshMd5 => {
+                let digest = md5sum(&get_ssh_key()?)
+                    .map_err(|e| format_err!("Error digesting host key - {}", e))?;
+
+                hex::encode(digest).to_uppercase()
+            }
+            crate::subscription_info::ServerIdType::MachineId => {
+                let machine_id =
+                    proxmox_systemd::sd_id128::get_app_specific_id(PMX_APPLICATION_ID)?;
+                hex::encode(machine_id).to_uppercase()
+            }
+        };
+        Ok(super::ServerId { ty, id })
+    }
+
     /// Generate the current system's "server ID".
-    pub fn get_hardware_address() -> Result<String, Error> {
-        static FILENAME: &str = "/etc/ssh/ssh_host_rsa_key.pub";
-
-        let contents = proxmox_sys::fs::file_get_contents(FILENAME)
-            .map_err(|e| format_err!("Error getting host key - {}", e))?;
-        let digest =
-            md5sum(&contents).map_err(|e| format_err!("Error digesting host key - {}", e))?;
-
-        Ok(hex::encode(digest).to_uppercase())
+    pub fn get_hardware_address_candidates() -> Result<Vec<super::ServerId>, Error> {
+        let mut res = Vec::new();
+        let mut errors = Vec::new();
+        let variants = [super::ServerIdType::MachineId, super::ServerIdType::SshMd5];
+        for ty in variants {
+            match get_hardware_address(ty) {
+                Ok(id) => res.push(id),
+                Err(err) => errors.push((ty, err)),
+            }
+        }
+        if res.is_empty() {
+            let error_strings: Vec<String> = errors
+                .into_iter()
+                .map(|(ty, err)| format!("{ty}: {err}"))
+                .collect();
+            let msg = if error_strings.is_empty() {
+                "unknown error".to_string()
+            } else {
+                error_strings.join(", ")
+            };
+            bail!("Failed to get any hardware address candidate: {msg}",);
+        }
+        Ok(res)
     }
 
     fn parse_next_due(value: &str) -> Result<i64, Error> {
-- 
2.47.3





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

* [RFC proxmox-backup 3/6] subscription: adapt to multiple server ID variants
  2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
  2026-04-10 10:02 ` [PATCH proxmox 1/6] systemd: add support for machine-id generation Fabian Grünbichler
  2026-04-10 10:02 ` [RFC proxmox 2/6] proxmox-subscription: add new machine-id based serverid Fabian Grünbichler
@ 2026-04-10 10:02 ` Fabian Grünbichler
  2026-04-10 10:02 ` [RFC proxmox-perl-rs 4/6] common: subscription: expose server ID candidates Fabian Grünbichler
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

if there already is a subscription info, re-use the server ID contained within.
if not, use the first candidate.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---

Notes:
    requires bumped librust-proxmox-subscription-dev

 src/api2/node/subscription.rs | 38 ++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/src/api2/node/subscription.rs b/src/api2/node/subscription.rs
index 03d613ee2..6935e4e3f 100644
--- a/src/api2/node/subscription.rs
+++ b/src/api2/node/subscription.rs
@@ -102,7 +102,15 @@ pub fn check_subscription(force: bool) -> Result<(), Error> {
         Ok(None) => return Ok(()),
     };
 
-    let server_id = proxmox_subscription::get_hardware_address()?;
+    let server_id = if let Some(existing) = info.serverid.as_ref() {
+        existing.to_owned()
+    } else {
+        proxmox_subscription::get_hardware_address_candidates()?
+            .first()
+            .ok_or_else(|| format_err!("Failed to generate serverid"))?
+            .to_string()
+    };
+
     let key = if let Some(key) = info.key.as_ref() {
         // always update apt auth if we have a key to ensure user can access enterprise repo
         proxmox_subscription::files::update_apt_auth(
@@ -110,7 +118,7 @@ pub fn check_subscription(force: bool) -> Result<(), Error> {
             apt_auth_file_opts(),
             APT_AUTH_URL,
             Some(key.to_owned()),
-            Some(server_id.to_owned()),
+            Some(server_id.clone()),
         )?;
         key.to_owned()
     } else {
@@ -124,6 +132,7 @@ pub fn check_subscription(force: bool) -> Result<(), Error> {
     if !force && info.status == SubscriptionStatus::Active {
         // will set to INVALID if last check too long ago
         info.check_age(true);
+
         if info.status == SubscriptionStatus::Active {
             return Ok(());
         }
@@ -156,13 +165,19 @@ pub fn get_subscription(
     ) {
         Err(err) => bail!("could not read subscription status: {}", err),
         Ok(Some(info)) => info,
-        Ok(None) => SubscriptionInfo {
-            status: SubscriptionStatus::NotFound,
-            message: Some("There is no subscription key".into()),
-            serverid: Some(proxmox_subscription::get_hardware_address()?),
-            url: Some(PRODUCT_URL.into()),
-            ..Default::default()
-        },
+        Ok(None) => {
+            let candidates = proxmox_subscription::get_hardware_address_candidates()?;
+            let serverid = candidates
+                .first()
+                .ok_or_else(|| format_err!("Failed to generate serverid"))?;
+            SubscriptionInfo {
+                status: SubscriptionStatus::NotFound,
+                message: Some("There is no subscription key".into()),
+                serverid: Some(serverid.to_string()),
+                url: Some(PRODUCT_URL.into()),
+                ..Default::default()
+            }
+        }
     };
 
     let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
@@ -200,7 +215,10 @@ pub fn get_subscription(
 )]
 /// Set a subscription key and check it.
 pub fn set_subscription(key: String) -> Result<(), Error> {
-    let server_id = proxmox_subscription::get_hardware_address()?;
+    let server_id = proxmox_subscription::get_hardware_address_candidates()?
+        .first()
+        .ok_or_else(|| format_err!("Failed to generate serverid"))?
+        .to_string();
 
     check_and_write_subscription(key, server_id)
 }
-- 
2.47.3





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

* [RFC proxmox-perl-rs 4/6] common: subscription: expose server ID candidates
  2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
                   ` (2 preceding siblings ...)
  2026-04-10 10:02 ` [RFC proxmox-backup 3/6] subscription: adapt to multiple server ID variants Fabian Grünbichler
@ 2026-04-10 10:02 ` Fabian Grünbichler
  2026-04-10 10:02 ` [RFC manager 5/6] subscription: adapt to multiple server ID variants Fabian Grünbichler
  2026-04-10 10:02 ` [RFC manager 6/6] api2tools: remove unused get_hwaddress Fabian Grünbichler
  5 siblings, 0 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---

Notes:
    requires bumped librust-proxmox-subscription-dev

 common/src/bindings/subscription.rs | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/common/src/bindings/subscription.rs b/common/src/bindings/subscription.rs
index 313683c..286f4ac 100644
--- a/common/src/bindings/subscription.rs
+++ b/common/src/bindings/subscription.rs
@@ -126,4 +126,15 @@ pub mod proxmox_rs_subscription {
 
         Ok(info)
     }
+
+    /// Get server ID candidates.
+    ///
+    /// See [`proxmox_subscription::get_hardware_address_candidates()`]
+    #[export]
+    pub fn get_hardware_address_candidates() -> Result<Vec<(String, String)>, Error> {
+        Ok(proxmox_subscription::get_hardware_address_candidates()?
+            .into_iter()
+            .map(|id| (id.kind().to_string(), id.to_string()))
+            .collect())
+    }
 }
-- 
2.47.3





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

* [RFC manager 5/6] subscription: adapt to multiple server ID variants
  2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
                   ` (3 preceding siblings ...)
  2026-04-10 10:02 ` [RFC proxmox-perl-rs 4/6] common: subscription: expose server ID candidates Fabian Grünbichler
@ 2026-04-10 10:02 ` Fabian Grünbichler
  2026-04-10 10:02 ` [RFC manager 6/6] api2tools: remove unused get_hwaddress Fabian Grünbichler
  5 siblings, 0 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

if there already is a subscription info with ID, reuse it. if not, use the
first candidate.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---

Notes:
    requires bumped libpve-rs-perl

 PVE/API2/Subscription.pm | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/PVE/API2/Subscription.pm b/PVE/API2/Subscription.pm
index 59e7fe747..0a9e59810 100644
--- a/PVE/API2/Subscription.pm
+++ b/PVE/API2/Subscription.pm
@@ -58,7 +58,7 @@ sub check_key {
 
 sub read_etc_subscription {
     my $req_sockets = get_sockets();
-    my $server_id = PVE::API2Tools::get_hwaddress();
+    my $server_id_candidates = Proxmox::RS::Subscription::get_hardware_address_candidates();
 
     my $info = Proxmox::RS::Subscription::read_subscription($filename);
 
@@ -89,7 +89,7 @@ my sub cache_is_valid {
 sub write_etc_subscription {
     my ($info) = @_;
 
-    my $server_id = PVE::API2Tools::get_hwaddress();
+    my $server_id_candidates = Proxmox::RS::Subscription::get_hardware_address_candidates();
     mkdir "/etc/apt/auth.conf.d";
     Proxmox::RS::Subscription::write_subscription(
         $filename,
@@ -205,7 +205,8 @@ __PACKAGE__->register_method({
         my $authuser = $rpcenv->get_user();
         my $has_permission = $rpcenv->check($authuser, "/nodes/$node", ['Sys.Audit'], 1);
 
-        my $server_id = PVE::API2Tools::get_hwaddress();
+        my $server_id_candidates = Proxmox::RS::Subscription::get_hardware_address_candidates();
+        my $server_id = $server_id_candidates->[0]->[1];
         my $url = "https://www.proxmox.com/en/proxmox-virtual-environment/pricing";
 
         my $info = read_etc_subscription();
@@ -227,7 +228,13 @@ __PACKAGE__->register_method({
             };
         }
 
-        $info->{serverid} = $server_id;
+        # none set yet
+        $info->{serverid} = $server_id if !defined($info->{serverid});
+
+        if ((grep { my $id = $_->[1]; $id eq $info->{serverid} } $server_id_candidates->@*) < 1) {
+            # mismatch, reset
+            $info->{serverid} = $server_id;
+        }
         $info->{sockets} = get_sockets();
         $info->{url} = $url;
 
@@ -264,8 +271,12 @@ __PACKAGE__->register_method({
         my $info = read_etc_subscription();
         return undef if !$info;
 
-        my $server_id = PVE::API2Tools::get_hwaddress();
+        my $server_id_candidates = Proxmox::RS::Subscription::get_hardware_address_candidates();
         my $key = $info->{key};
+        my $server_id = $info->{serverid} // $server_id_candidates->[0]->[1];
+        if ((grep { my $id = $_->[1]; $id eq $server_id } $server_id_candidates->@*) < 1) {
+            die "no matching server ID found\n";
+        }
 
         die
             "Updating offline key not possible - please remove and re-add subscription key to switch to online key.\n"
@@ -324,7 +335,10 @@ __PACKAGE__->register_method({
         };
 
         my $req_sockets = get_sockets();
-        my $server_id = PVE::API2Tools::get_hwaddress();
+        my $server_id_candidates = Proxmox::RS::Subscription::get_hardware_address_candidates();
+        my $server_id = $server_id_candidates->[0]->[1];
+
+        die "Failed to generate server ID\n" if !$server_id;
 
         check_key($key, $req_sockets);
 
-- 
2.47.3





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

* [RFC manager 6/6] api2tools: remove unused get_hwaddress
  2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
                   ` (4 preceding siblings ...)
  2026-04-10 10:02 ` [RFC manager 5/6] subscription: adapt to multiple server ID variants Fabian Grünbichler
@ 2026-04-10 10:02 ` Fabian Grünbichler
  5 siblings, 0 replies; 7+ messages in thread
From: Fabian Grünbichler @ 2026-04-10 10:02 UTC (permalink / raw)
  To: pve-devel

it is now only implemented in the proxmox-subscription crate.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 PVE/API2Tools.pm | 23 -----------------------
 1 file changed, 23 deletions(-)

diff --git a/PVE/API2Tools.pm b/PVE/API2Tools.pm
index a1a6f39e1..bca21aa5f 100644
--- a/PVE/API2Tools.pm
+++ b/PVE/API2Tools.pm
@@ -18,29 +18,6 @@ use PVE::SafeSyslog;
 use PVE::Storage::Plugin;
 use PVE::Tools;
 
-my $hwaddress;
-my $hwaddress_st = {};
-
-sub get_hwaddress {
-    my $fn = '/etc/ssh/ssh_host_rsa_key.pub';
-    my $st = stat($fn);
-
-    if (
-        defined($hwaddress)
-        && $hwaddress_st->{mtime} == $st->mtime
-        && $hwaddress_st->{ino} == $st->ino
-        && $hwaddress_st->{dev} == $st->dev
-    ) {
-        return $hwaddress;
-    }
-
-    my $sshkey = PVE::Tools::file_get_contents($fn);
-    $hwaddress = uc(md5_hex($sshkey));
-    $hwaddress_st->@{ 'mtime', 'ino', 'dev' } = ($st->mtime, $st->ino, $st->dev);
-
-    return $hwaddress;
-}
-
 # each rrd key for a resource will only exist once. The key format might be different though. Therefore return on first hit
 sub get_rrd_key {
     my ($rrd, $type, $id) = @_;
-- 
2.47.3





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

end of thread, other threads:[~2026-04-10 10:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-10 10:02 [RFC manager/proxmox{,-backup,-perl-rs} 0/6] adapt subscription handling to alternative server IDs Fabian Grünbichler
2026-04-10 10:02 ` [PATCH proxmox 1/6] systemd: add support for machine-id generation Fabian Grünbichler
2026-04-10 10:02 ` [RFC proxmox 2/6] proxmox-subscription: add new machine-id based serverid Fabian Grünbichler
2026-04-10 10:02 ` [RFC proxmox-backup 3/6] subscription: adapt to multiple server ID variants Fabian Grünbichler
2026-04-10 10:02 ` [RFC proxmox-perl-rs 4/6] common: subscription: expose server ID candidates Fabian Grünbichler
2026-04-10 10:02 ` [RFC manager 5/6] subscription: adapt to multiple server ID variants Fabian Grünbichler
2026-04-10 10:02 ` [RFC manager 6/6] api2tools: remove unused get_hwaddress Fabian Grünbichler

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