all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH proxmox 1/2] pve api types: add node config get api call
Date: Fri, 28 Nov 2025 11:18:19 +0100	[thread overview]
Message-ID: <20251128101848.1580111-2-d.csapak@proxmox.com> (raw)
In-Reply-To: <20251128101848.1580111-1-d.csapak@proxmox.com>

re-implement the ACME regexes here from what is defined in pve-manager,
since the ones we have in proxmox-schema are slightly different.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 pve-api-types/generate.pl            |  12 +-
 pve-api-types/src/generated/code.rs  |  22 +-
 pve-api-types/src/generated/types.rs | 335 ++++++++++++++++++++++++---
 pve-api-types/src/types/verifiers.rs |  28 +++
 4 files changed, 354 insertions(+), 43 deletions(-)

diff --git a/pve-api-types/generate.pl b/pve-api-types/generate.pl
index f72a776a..2caf1cff 100755
--- a/pve-api-types/generate.pl
+++ b/pve-api-types/generate.pl
@@ -42,8 +42,8 @@ Schema2Rust::register_format('CIDRv4' => { code => 'verifiers::verify_cidrv4' })
 Schema2Rust::register_format('CIDRv6' => { code => 'verifiers::verify_cidrv6' });
 Schema2Rust::register_format('ipv4mask' => { code => 'verifiers::verify_ipv4_mask' });
 Schema2Rust::register_format('mac-addr' => { regex => '^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$' });
-## Schema2Rust::register_format('pve-acme-alias' => { code => 'verify_pve_acme_alias' });
-## Schema2Rust::register_format('pve-acme-domain' => { code => 'verify_pve_acme_domain' });
+Schema2Rust::register_format('pve-acme-alias' => { code => 'verifiers::verify_pve_acme_alias' });
+Schema2Rust::register_format('pve-acme-domain' => { code => 'verifiers::verify_pve_acme_domain' });
 Schema2Rust::register_format('pve-bridge-id' => { regex => '^'.$BRIDGEID_RE.'$' });
 Schema2Rust::register_format('pve-configid' => { regex => $CONFIGID_RE });
 ## Schema2Rust::register_format('pve-groupid' => { code => 'verify_pve_groupid' });
@@ -213,13 +213,7 @@ Schema2Rust::derive('ClusterResource' => 'Clone', 'PartialEq');
 
 api(GET => '/nodes', 'list_nodes', 'return-name' => 'ClusterNodeIndexResponse');
 Schema2Rust::derive('ClusterNodeIndexResponse' => 'Clone', 'PartialEq');
-# api(
-#     GET => '/nodes/{node}/config',
-#     'get_node_config',
-#     'param-name' => 'GetNodeConfig',
-#     'return-name' => 'NodeConfig',
-#     # 'return-type' => { type => 'object', properties => PVE::NodeConfig::get_nodeconfig_schema() },
-# );
+api(GET => '/nodes/{node}/config', 'node_config', 'return-name' => 'NodeConfig');
 # api(PUT => '/nodes/{node}/config', 'set_node_config', 'param-name' => 'UpdateNodeConfig');
 # subscription api
 #
diff --git a/pve-api-types/src/generated/code.rs b/pve-api-types/src/generated/code.rs
index a74c99e2..0dd6d8e1 100644
--- a/pve-api-types/src/generated/code.rs
+++ b/pve-api-types/src/generated/code.rs
@@ -185,7 +185,6 @@
 /// - /nodes/{node}/certificates/acme/certificate
 /// - /nodes/{node}/certificates/custom
 /// - /nodes/{node}/certificates/info
-/// - /nodes/{node}/config
 /// - /nodes/{node}/disks
 /// - /nodes/{node}/disks/directory
 /// - /nodes/{node}/disks/directory/{name}
@@ -678,6 +677,15 @@ pub trait PveClient {
         Err(Error::Other("migrate_qemu not implemented"))
     }
 
+    /// Get node configuration options.
+    async fn node_config(
+        &self,
+        node: &str,
+        property: Option<NodeConfigProperty>,
+    ) -> Result<NodeConfig, Error> {
+        Err(Error::Other("node_config not implemented"))
+    }
+
     /// Get host firewall options.
     async fn node_firewall_options(&self, node: &str) -> Result<NodeFirewallOptions, Error> {
         Err(Error::Other("node_firewall_options not implemented"))
@@ -1368,6 +1376,18 @@ where
         Ok(self.0.post(url, &params).await?.expect_json()?.data)
     }
 
+    /// Get node configuration options.
+    async fn node_config(
+        &self,
+        node: &str,
+        property: Option<NodeConfigProperty>,
+    ) -> Result<NodeConfig, Error> {
+        let url = &ApiPathBuilder::new(format!("/api2/extjs/nodes/{node}/config"))
+            .maybe_arg("property", &property)
+            .build();
+        Ok(self.0.get(url).await?.expect_json()?.data)
+    }
+
     /// Get host firewall options.
     async fn node_firewall_options(&self, node: &str) -> Result<NodeFirewallOptions, Error> {
         let url = &format!("/api2/extjs/nodes/{node}/firewall/options");
diff --git a/pve-api-types/src/generated/types.rs b/pve-api-types/src/generated/types.rs
index 74f8638f..8963baf9 100644
--- a/pve-api-types/src/generated/types.rs
+++ b/pve-api-types/src/generated/types.rs
@@ -7500,6 +7500,275 @@ pub enum NetworkInterfaceVlanProtocol {
 serde_plain::derive_display_from_serialize!(NetworkInterfaceVlanProtocol);
 serde_plain::derive_fromstr_from_deserialize!(NetworkInterfaceVlanProtocol);
 
+#[api(
+    properties: {
+        acme: {
+            format: &ApiStringFormat::PropertyString(&NodeConfigAcme::API_SCHEMA),
+            optional: true,
+            type: String,
+        },
+        acmedomain: {
+            type: NodeConfigAcmedomainArray,
+        },
+        "ballooning-target": {
+            default: 80,
+            maximum: 100,
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        description: {
+            max_length: 65536,
+            optional: true,
+            type: String,
+        },
+        digest: {
+            max_length: 40,
+            optional: true,
+            type: String,
+        },
+        "startall-onboot-delay": {
+            default: 0,
+            maximum: 300,
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        wakeonlan: {
+            format: &ApiStringFormat::PropertyString(&NodeConfigWakeonlan::API_SCHEMA),
+            optional: true,
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfig {
+    /// Node specific ACME settings.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub acme: Option<String>,
+
+    /// ACME domain and validation plugin
+    #[serde(flatten)]
+    pub acmedomain: NodeConfigAcmedomainArray,
+
+    /// RAM usage target for ballooning (in percent of total memory)
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u8")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "ballooning-target")]
+    pub ballooning_target: Option<u8>,
+
+    /// Description for the Node. Shown in the web-interface node notes panel.
+    /// This is saved as comment inside the configuration file.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub description: Option<String>,
+
+    /// Prevent changes if current configuration file has different SHA1 digest.
+    /// This can be used to prevent concurrent modifications.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub digest: Option<String>,
+
+    /// Initial delay in seconds, before starting all the Virtual Guests with
+    /// on-boot enabled.
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u16")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "startall-onboot-delay")]
+    pub startall_onboot_delay: Option<u16>,
+
+    /// Node specific wake on LAN settings.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub wakeonlan: Option<String>,
+}
+generate_array_field! {
+    NodeConfigAcmedomainArray [ 6 ] :
+    r#"ACME domain and validation plugin"#,
+    String => {
+        description: "ACME domain and validation plugin",
+        format: &ApiStringFormat::PropertyString(&NodeConfigAcmedomain::API_SCHEMA),
+        type: String,
+    }
+    acmedomain
+}
+
+const_regex! {
+
+NODE_CONFIG_ACME_ACCOUNT_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_16() {
+    use regex::Regex;
+    let _: &Regex = &NODE_CONFIG_ACME_ACCOUNT_RE;
+}
+#[api(
+    properties: {
+        account: {
+            default: "default",
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_ACME_ACCOUNT_RE),
+            optional: true,
+            type: String,
+        },
+        domains: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_pve_acme_domain),
+            optional: true,
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfigAcme {
+    /// ACME account config file name.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub account: Option<String>,
+
+    /// List of domains for this node's ACME certificate
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub domains: Option<String>,
+}
+
+const_regex! {
+
+NODE_CONFIG_ACMEDOMAIN_PLUGIN_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_17() {
+    use regex::Regex;
+    let _: &Regex = &NODE_CONFIG_ACMEDOMAIN_PLUGIN_RE;
+}
+#[api(
+    default_key: "domain",
+    properties: {
+        alias: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_pve_acme_alias),
+            optional: true,
+            type: String,
+        },
+        domain: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_pve_acme_domain),
+            type: String,
+        },
+        plugin: {
+            default: "standalone",
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_ACMEDOMAIN_PLUGIN_RE),
+            optional: true,
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfigAcmedomain {
+    /// Alias for the Domain to verify ACME Challenge over DNS
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub alias: Option<String>,
+
+    /// domain for this node's ACME certificate
+    pub domain: String,
+
+    /// The ACME plugin ID
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub plugin: Option<String>,
+}
+
+#[api]
+/// Return only a specific property from the node configuration.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub enum NodeConfigProperty {
+    #[serde(rename = "acme")]
+    /// acme.
+    Acme,
+    #[serde(rename = "acmedomain0")]
+    /// acmedomain0.
+    Acmedomain0,
+    #[serde(rename = "acmedomain1")]
+    /// acmedomain1.
+    Acmedomain1,
+    #[serde(rename = "acmedomain2")]
+    /// acmedomain2.
+    Acmedomain2,
+    #[serde(rename = "acmedomain3")]
+    /// acmedomain3.
+    Acmedomain3,
+    #[serde(rename = "acmedomain4")]
+    /// acmedomain4.
+    Acmedomain4,
+    #[serde(rename = "acmedomain5")]
+    /// acmedomain5.
+    Acmedomain5,
+    #[serde(rename = "ballooning-target")]
+    /// ballooning-target.
+    BallooningTarget,
+    #[serde(rename = "description")]
+    /// description.
+    Description,
+    #[serde(rename = "startall-onboot-delay")]
+    /// startall-onboot-delay.
+    StartallOnbootDelay,
+    #[serde(rename = "wakeonlan")]
+    /// wakeonlan.
+    Wakeonlan,
+    /// Unknown variants for forward compatibility.
+    #[serde(untagged)]
+    UnknownEnumValue(FixedString),
+}
+serde_plain::derive_display_from_serialize!(NodeConfigProperty);
+serde_plain::derive_fromstr_from_deserialize!(NodeConfigProperty);
+
+const_regex! {
+
+NODE_CONFIG_WAKEONLAN_BIND_INTERFACE_RE = r##"^[a-zA-Z][a-zA-Z0-9_]{1,20}([:\.]\d+)?$"##;
+NODE_CONFIG_WAKEONLAN_MAC_RE = r##"^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$"##;
+
+}
+
+#[test]
+fn test_regex_compilation_18() {
+    use regex::Regex;
+    let _: &Regex = &NODE_CONFIG_WAKEONLAN_BIND_INTERFACE_RE;
+    let _: &Regex = &NODE_CONFIG_WAKEONLAN_MAC_RE;
+}
+#[api(
+    default_key: "mac",
+    properties: {
+        "bind-interface": {
+            default: "The interface carrying the default route",
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_WAKEONLAN_BIND_INTERFACE_RE),
+            optional: true,
+            type: String,
+        },
+        "broadcast-address": {
+            default: "255.255.255.255",
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_ipv4),
+            optional: true,
+            type: String,
+        },
+        mac: {
+            format: &ApiStringFormat::Pattern(&NODE_CONFIG_WAKEONLAN_MAC_RE),
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct NodeConfigWakeonlan {
+    /// Bind to this interface when sending wake on LAN packet
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "bind-interface")]
+    pub bind_interface: Option<String>,
+
+    /// IPv4 broadcast address to use when sending wake on LAN packet
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "broadcast-address")]
+    pub broadcast_address: Option<String>,
+
+    /// MAC address for wake on LAN
+    pub mac: String,
+}
+
 #[api(
     properties: {
         enable: {
@@ -8403,7 +8672,7 @@ PVE_QM_HOSTPCI_MAPPING_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_16() {
+fn test_regex_compilation_19() {
     use regex::Regex;
     let _: &Regex = &PVE_QM_HOSTPCI_MAPPING_RE;
 }
@@ -8572,7 +8841,7 @@ PVE_QM_IDE_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_17() {
+fn test_regex_compilation_20() {
     use regex::Regex;
     let _: &Regex = &PVE_QM_IDE_MODEL_RE;
     let _: &Regex = &PVE_QM_IDE_SERIAL_RE;
@@ -9639,7 +9908,7 @@ QEMU_CONFIG_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_18() {
+fn test_regex_compilation_21() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_AFFINITY_RE;
     let _: &Regex = &QEMU_CONFIG_BOOTDISK_RE;
@@ -10825,7 +11094,7 @@ QEMU_CONFIG_EFIDISK0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_19() {
+fn test_regex_compilation_22() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_EFIDISK0_SIZE_RE;
 }
@@ -11233,7 +11502,7 @@ QEMU_CONFIG_NET_MACADDR_RE = r##"^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$"##;
 }
 
 #[test]
-fn test_regex_compilation_20() {
+fn test_regex_compilation_23() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_NET_BRIDGE_RE;
     let _: &Regex = &QEMU_CONFIG_NET_MACADDR_RE;
@@ -11539,7 +11808,7 @@ QEMU_CONFIG_SATA_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_21() {
+fn test_regex_compilation_24() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_SATA_SERIAL_RE;
     let _: &Regex = &QEMU_CONFIG_SATA_SIZE_RE;
@@ -11872,7 +12141,7 @@ QEMU_CONFIG_SCSI_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_22() {
+fn test_regex_compilation_25() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_SCSI_SERIAL_RE;
     let _: &Regex = &QEMU_CONFIG_SCSI_SIZE_RE;
@@ -12336,7 +12605,7 @@ QEMU_CONFIG_TPMSTATE0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_23() {
+fn test_regex_compilation_26() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_TPMSTATE0_SIZE_RE;
 }
@@ -12441,7 +12710,7 @@ QEMU_CONFIG_USB_MAPPING_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_24() {
+fn test_regex_compilation_27() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_USB_MAPPING_RE;
 }
@@ -12611,7 +12880,7 @@ QEMU_CONFIG_VIRTIO_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_25() {
+fn test_regex_compilation_28() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_VIRTIO_SERIAL_RE;
     let _: &Regex = &QEMU_CONFIG_VIRTIO_SIZE_RE;
@@ -12942,7 +13211,7 @@ QEMU_CONFIG_VIRTIOFS_DIRID_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_26() {
+fn test_regex_compilation_29() {
     use regex::Regex;
     let _: &Regex = &QEMU_CONFIG_VIRTIOFS_DIRID_RE;
 }
@@ -13237,7 +13506,7 @@ QEMU_MOVE_DISK_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_27() {
+fn test_regex_compilation_30() {
     use regex::Regex;
     let _: &Regex = &QEMU_MOVE_DISK_STORAGE_RE;
 }
@@ -14837,7 +15106,7 @@ REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:
 }
 
 #[test]
-fn test_regex_compilation_28() {
+fn test_regex_compilation_31() {
     use regex::Regex;
     let _: &Regex = &REMOTE_MIGRATE_LXC_TARGET_BRIDGE_RE;
     let _: &Regex = &REMOTE_MIGRATE_LXC_TARGET_STORAGE_RE;
@@ -14954,7 +15223,7 @@ REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i
 }
 
 #[test]
-fn test_regex_compilation_29() {
+fn test_regex_compilation_32() {
     use regex::Regex;
     let _: &Regex = &REMOTE_MIGRATE_QEMU_TARGET_BRIDGE_RE;
     let _: &Regex = &REMOTE_MIGRATE_QEMU_TARGET_STORAGE_RE;
@@ -15271,7 +15540,7 @@ SDN_CONTROLLER_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F
 }
 
 #[test]
-fn test_regex_compilation_30() {
+fn test_regex_compilation_33() {
     use regex::Regex;
     let _: &Regex = &SDN_CONTROLLER_ISIS_IFACES_RE;
     let _: &Regex = &SDN_CONTROLLER_ISIS_NET_RE;
@@ -15424,7 +15693,7 @@ SDN_CONTROLLER_PENDING_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\
 }
 
 #[test]
-fn test_regex_compilation_31() {
+fn test_regex_compilation_34() {
     use regex::Regex;
     let _: &Regex = &SDN_CONTROLLER_PENDING_ISIS_IFACES_RE;
     let _: &Regex = &SDN_CONTROLLER_PENDING_ISIS_NET_RE;
@@ -15725,7 +15994,7 @@ SDN_ZONE_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
 }
 
 #[test]
-fn test_regex_compilation_32() {
+fn test_regex_compilation_35() {
     use regex::Regex;
     let _: &Regex = &SDN_ZONE_EXITNODES_RE;
     let _: &Regex = &SDN_ZONE_EXITNODES_PRIMARY_RE;
@@ -16002,7 +16271,7 @@ SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9]
 }
 
 #[test]
-fn test_regex_compilation_33() {
+fn test_regex_compilation_36() {
     use regex::Regex;
     let _: &Regex = &SDN_ZONE_PENDING_EXITNODES_RE;
     let _: &Regex = &SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE;
@@ -16332,7 +16601,7 @@ START_QEMU_TARGETSTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]):(?i:[a-z][a-z
 }
 
 #[test]
-fn test_regex_compilation_34() {
+fn test_regex_compilation_37() {
     use regex::Regex;
     let _: &Regex = &START_QEMU_MIGRATEDFROM_RE;
     let _: &Regex = &START_QEMU_TARGETSTORAGE_RE;
@@ -16506,7 +16775,7 @@ STOP_QEMU_MIGRATEDFROM_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
 }
 
 #[test]
-fn test_regex_compilation_35() {
+fn test_regex_compilation_38() {
     use regex::Regex;
     let _: &Regex = &STOP_QEMU_MIGRATEDFROM_RE;
 }
@@ -16608,7 +16877,7 @@ STORAGE_INFO_STORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_36() {
+fn test_regex_compilation_39() {
     use regex::Regex;
     let _: &Regex = &STORAGE_INFO_STORAGE_RE;
 }
@@ -17046,7 +17315,7 @@ UPDATE_CLUSTER_FIREWALL_OPTIONS_DELETE_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_37() {
+fn test_regex_compilation_40() {
     use regex::Regex;
     let _: &Regex = &UPDATE_CLUSTER_FIREWALL_OPTIONS_DELETE_RE;
 }
@@ -17138,7 +17407,7 @@ UPDATE_GUEST_FIREWALL_OPTIONS_DELETE_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_38() {
+fn test_regex_compilation_41() {
     use regex::Regex;
     let _: &Regex = &UPDATE_GUEST_FIREWALL_OPTIONS_DELETE_RE;
 }
@@ -17269,7 +17538,7 @@ UPDATE_LXC_CONFIG_TIMEZONE_RE = r##"^.*/.*$"##;
 }
 
 #[test]
-fn test_regex_compilation_39() {
+fn test_regex_compilation_42() {
     use regex::Regex;
     let _: &Regex = &UPDATE_LXC_CONFIG_DELETE_RE;
     let _: &Regex = &UPDATE_LXC_CONFIG_REVERT_RE;
@@ -17648,7 +17917,7 @@ UPDATE_NODE_FIREWALL_OPTIONS_DELETE_RE = r##"^(?i:[a-z][a-z0-9_-]+)$"##;
 }
 
 #[test]
-fn test_regex_compilation_40() {
+fn test_regex_compilation_43() {
     use regex::Regex;
     let _: &Regex = &UPDATE_NODE_FIREWALL_OPTIONS_DELETE_RE;
 }
@@ -17869,7 +18138,7 @@ UPDATE_QEMU_CONFIG_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9])$"##;
 }
 
 #[test]
-fn test_regex_compilation_41() {
+fn test_regex_compilation_44() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_AFFINITY_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_BOOTDISK_RE;
@@ -18781,7 +19050,7 @@ UPDATE_QEMU_CONFIG_ASYNC_VMSTATESTORAGE_RE = r##"^(?i:[a-z][a-z0-9\-_.]*[a-z0-9]
 }
 
 #[test]
-fn test_regex_compilation_42() {
+fn test_regex_compilation_45() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_ASYNC_AFFINITY_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_ASYNC_BOOTDISK_RE;
@@ -19671,7 +19940,7 @@ UPDATE_QEMU_CONFIG_EFIDISK0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_43() {
+fn test_regex_compilation_46() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_EFIDISK0_SIZE_RE;
 }
@@ -19756,7 +20025,7 @@ UPDATE_QEMU_CONFIG_IDE_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_44() {
+fn test_regex_compilation_47() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_IDE_MODEL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_IDE_SERIAL_RE;
@@ -20112,7 +20381,7 @@ UPDATE_QEMU_CONFIG_SATA_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_45() {
+fn test_regex_compilation_48() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SATA_SERIAL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SATA_SIZE_RE;
@@ -20457,7 +20726,7 @@ UPDATE_QEMU_CONFIG_SCSI_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_46() {
+fn test_regex_compilation_49() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SCSI_SERIAL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_SCSI_SIZE_RE;
@@ -20857,7 +21126,7 @@ UPDATE_QEMU_CONFIG_TPMSTATE0_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_47() {
+fn test_regex_compilation_50() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_TPMSTATE0_SIZE_RE;
 }
@@ -20920,7 +21189,7 @@ UPDATE_QEMU_CONFIG_VIRTIO_SIZE_RE = r##"^(\d+(\.\d+)?)([KMGT])?$"##;
 }
 
 #[test]
-fn test_regex_compilation_48() {
+fn test_regex_compilation_51() {
     use regex::Regex;
     let _: &Regex = &UPDATE_QEMU_CONFIG_VIRTIO_SERIAL_RE;
     let _: &Regex = &UPDATE_QEMU_CONFIG_VIRTIO_SIZE_RE;
diff --git a/pve-api-types/src/types/verifiers.rs b/pve-api-types/src/types/verifiers.rs
index 092893b3..462d30ef 100644
--- a/pve-api-types/src/types/verifiers.rs
+++ b/pve-api-types/src/types/verifiers.rs
@@ -24,6 +24,14 @@ pub fn verify_pve_volume_id_or_absolute_path(s: &str) -> Result<(), Error> {
 macro_rules! DNS_NAMERE { () => (r##"([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)"##) }
 #[rustfmt::skip]
 macro_rules! DNS_RE { () => (concat!("(", DNS_NAMERE!(), "\\.)*", DNS_NAMERE!(), "$")) }
+#[rustfmt::skip]
+macro_rules! ACME_NAME_RE { () => (r##"([a-zA-Z0-9]([a-zA-Z0-9_\-]*)?)"##) }
+#[rustfmt::skip]
+macro_rules! ACME_RE { () => (concat!("(", ACME_NAME_RE!(), "\\.)*", ACME_NAME_RE!(), "$")) }
+#[rustfmt::skip]
+macro_rules! ACME_ALIAS_NAME_RE { () => (r##"([a-zA-Z0-9_]([a-zA-Z0-9_\-]*)?)"##) }
+#[rustfmt::skip]
+macro_rules! ACME_ALIAS_RE { () => (concat!("(", ACME_ALIAS_NAME_RE!(), "\\.)*", ACME_ALIAS_NAME_RE!(), "$")) }
 
 const_regex! {
 
@@ -31,6 +39,10 @@ pub VOLUME_ID = r##"^(?i)([a-z][a-z0-9\-\_\.]*[a-z0-9]):(.+)$"##;
 //pub DNS_NAMERE = concat!("^", DNS_NAMERE!(), "$");
 pub DNS_RE = concat!("^", DNS_RE!(), "$");
 
+pub ACME_ALIAS_RE = concat!("^", ACME_ALIAS_RE!(), "$");
+
+pub ACME_RE = concat!("^", ACME_RE!(), "$");
+
 pub FE80_RE = r##"^(?i)fe80:"##;
 
 pub IFACE_RE = r##"^(?i)[a-z][a-z0-9_]{1,20}([:\.]\d+)?$"##;
@@ -282,3 +294,19 @@ pub fn verify_sdn_bgp_rt(s: &str) -> Result<(), Error> {
 
     Ok(())
 }
+
+pub fn verify_pve_acme_domain(s: &str) -> Result<(), Error> {
+    if ACME_RE.is_match(s) {
+        Ok(())
+    } else {
+        bail!("not a valid acme domain");
+    }
+}
+
+pub fn verify_pve_acme_alias(s: &str) -> Result<(), Error> {
+    if ACME_ALIAS_RE.is_match(s) {
+        Ok(())
+    } else {
+        bail!("not a valid acme alias");
+    }
+}
-- 
2.47.3



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


  reply	other threads:[~2025-11-28 10:19 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-28 10:18 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp 0/8] ui: add remote datacenter/node notes panels Dominik Csapak
2025-11-28 10:18 ` Dominik Csapak [this message]
2025-11-28 10:18 ` [pdm-devel] [PATCH proxmox 2/2] pve api types: add cluster options api call Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH yew-comp 1/1] notes edit: hide toolbar when editing is not possible Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 1/5] server: api: add nodes config api Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 2/5] server: api: pve: add cluster options api call Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 3/5] ui: pve: rename remote module Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 4/5] ui: pve: nodes: add panel for notes Dominik Csapak
2025-11-28 10:18 ` [pdm-devel] [PATCH datacenter-manager 5/5] ui: pve: datacenter: add remote notes panel Dominik Csapak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251128101848.1580111-2-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is 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