From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id A9C771FF1A6 for ; Fri, 5 Dec 2025 12:26:16 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 85F85156F3; Fri, 5 Dec 2025 12:26:44 +0100 (CET) From: Christoph Heiss To: pdm-devel@lists.proxmox.com Date: Fri, 5 Dec 2025 12:25:09 +0100 Message-ID: <20251205112528.373387-8-c.heiss@proxmox.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: <20251205112528.373387-1-c.heiss@proxmox.com> References: <20251205112528.373387-1-c.heiss@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1764933921003 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.050 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pdm-devel] [PATCH proxmox v2 07/14] installer-types: implement api type for all externally-used types X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" PDM will (re-)use most of these types directly in the API, thus make them compatible. Signed-off-by: Christoph Heiss --- Changes v1 -> v2: * no changes proxmox-installer-types/Cargo.toml | 6 +- proxmox-installer-types/debian/control | 21 ++++ proxmox-installer-types/src/answer.rs | 119 +++++++++++++++++++++++ proxmox-installer-types/src/lib.rs | 37 +++++++ proxmox-installer-types/src/post_hook.rs | 56 +++++++++++ 5 files changed, 238 insertions(+), 1 deletion(-) diff --git a/proxmox-installer-types/Cargo.toml b/proxmox-installer-types/Cargo.toml index 96413fe1..8f281e01 100644 --- a/proxmox-installer-types/Cargo.toml +++ b/proxmox-installer-types/Cargo.toml @@ -15,8 +15,12 @@ rust-version.workspace = true anyhow.workspace = true serde = { workspace = true, features = ["derive"] } serde_plain.workspace = true -proxmox-network-types.workspace = true +regex = { workspace = true, optional = true } +proxmox-network-types = { workspace = true, features = ["api-types"] } +proxmox-schema = { workspace = true, optional = true, features = ["api-macro"] } +proxmox-section-config = { workspace = true, optional = true } [features] default = [] +api-types = ["dep:regex", "dep:proxmox-schema", "dep:proxmox-section-config", "proxmox-network-types/api-types"] legacy = [] diff --git a/proxmox-installer-types/debian/control b/proxmox-installer-types/debian/control index d208a014..30c5e7ed 100644 --- a/proxmox-installer-types/debian/control +++ b/proxmox-installer-types/debian/control @@ -30,6 +30,8 @@ Depends: librust-serde-1+default-dev, librust-serde-1+derive-dev, librust-serde-plain-1+default-dev +Suggests: + librust-proxmox-installer-types+api-types-dev (= ${binary:Version}) Provides: librust-proxmox-installer-types+default-dev (= ${binary:Version}), librust-proxmox-installer-types+legacy-dev (= ${binary:Version}), @@ -44,3 +46,22 @@ Provides: librust-proxmox-installer-types-0.1.0+legacy-dev (= ${binary:Version}) Description: Type definitions used within the installer - Rust source code Source code for Debianized Rust crate "proxmox-installer-types" + +Package: librust-proxmox-installer-types+api-types-dev +Architecture: any +Multi-Arch: same +Depends: + ${misc:Depends}, + librust-proxmox-installer-types-dev (= ${binary:Version}), + librust-proxmox-network-types-0.1+api-types-dev, + librust-proxmox-schema-5+api-macro-dev (>= 5.0.1-~~), + librust-proxmox-schema-5+default-dev (>= 5.0.1-~~), + librust-proxmox-section-config-3+default-dev (>= 3.1.0-~~), + librust-regex-1+default-dev (>= 1.5-~~) +Provides: + librust-proxmox-installer-types-0+api-types-dev (= ${binary:Version}), + librust-proxmox-installer-types-0.1+api-types-dev (= ${binary:Version}), + librust-proxmox-installer-types-0.1.0+api-types-dev (= ${binary:Version}) +Description: Type definitions used within the installer - feature "api-types" + This metapackage enables feature "api-types" for the Rust proxmox-installer- + types crate, by pulling in any additional dependencies needed by that feature. diff --git a/proxmox-installer-types/src/answer.rs b/proxmox-installer-types/src/answer.rs index 7129a941..acfadcf8 100644 --- a/proxmox-installer-types/src/answer.rs +++ b/proxmox-installer-types/src/answer.rs @@ -15,15 +15,32 @@ use std::{ }; use proxmox_network_types::{fqdn::Fqdn, ip_address::Cidr}; + +#[cfg(feature = "api-types")] +use proxmox_schema::{api, api_types::PASSWORD_FORMAT, StringSchema, Updater, UpdaterType}; + +#[cfg(feature = "api-types")] +type IpAddr = proxmox_network_types::ip_address::api_types::IpAddr; +#[cfg(not(feature = "api-types"))] type IpAddr = std::net::IpAddr; +#[cfg(feature = "api-types")] +proxmox_schema::const_regex! { + /// A unique two-letter country code, according to ISO 3166-1 (alpha-2). + pub COUNTRY_CODE_REGEX = r"^[a-z]{2}$"; +} + /// Defines API types used by proxmox-fetch-answer, the first part of the /// auto-installer. pub mod fetch { use serde::{Deserialize, Serialize}; + #[cfg(feature = "api-types")] + use proxmox_schema::api; + use crate::SystemInfo; + #[cfg_attr(feature = "api-types", api)] #[derive(Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] /// Metadata of the HTTP POST payload, such as schema version of the document. @@ -50,6 +67,13 @@ pub mod fetch { } } + #[cfg_attr(feature = "api-types", api( + properties: { + sysinfo: { + flatten: true, + }, + }, + ))] #[derive(Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] /// Data sent in the body of POST request when retrieving the answer file via HTTP(S). @@ -91,6 +115,14 @@ pub struct AutoInstallerConfig { pub first_boot: Option, } +/// Machine root password schema. +#[cfg(feature = "api-types")] +pub const ROOT_PASSWORD_SCHEMA: proxmox_schema::Schema = StringSchema::new("Root Password.") + .format(&PASSWORD_FORMAT) + .min_length(8) + .max_length(64) + .schema(); + #[derive(Clone, Default, Deserialize, Debug, Serialize, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// General target system options for setting up the system in an automated @@ -130,6 +162,7 @@ pub struct GlobalOptions { pub root_ssh_keys: Vec, } +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Deserialize, Serialize, Debug, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Action to take after the installation completed successfully. @@ -144,6 +177,7 @@ pub enum RebootMode { serde_plain::derive_fromstr_from_deserialize!(RebootMode); #[derive(Clone, Deserialize, Debug, Serialize, PartialEq)] +#[cfg_attr(feature = "api-types", derive(Updater))] #[serde( untagged, expecting = "either a fully-qualified domain name or extendend configuration for usage with DHCP must be specified" @@ -204,6 +238,7 @@ pub enum FqdnSourceMode { FromDhcp, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Deserialize, Debug, Serialize, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Configuration for the post-installation hook, which runs after an @@ -216,6 +251,7 @@ pub struct PostNotificationHookInfo { pub cert_fingerprint: Option, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Deserialize, Debug, PartialEq, Serialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Possible sources for the optional first-boot hook script/executable file. @@ -227,6 +263,7 @@ pub enum FirstBootHookSourceMode { FromIso, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Default, Deserialize, Debug, PartialEq, Serialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Possible orderings for the `proxmox-first-boot` systemd service. @@ -256,6 +293,7 @@ impl FirstBootHookServiceOrdering { } } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Deserialize, Debug, Serialize, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Describes from where to fetch the first-boot hook script, either being baked into the ISO or @@ -328,6 +366,13 @@ pub enum NetworkConfig { FromAnswer(NetworkConfigFromAnswer), } +#[cfg_attr(feature = "api-types", api( + "id-property": "filesystem", + "id-schema": { + type: String, + description: "filesystem name", + }, +))] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] #[serde(rename_all = "kebab-case", tag = "filesystem")] /// Filesystem-specific options to set on the root disk. @@ -365,6 +410,7 @@ impl Display for DiskSelection { } } +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Default, Deserialize, Debug, PartialEq, Serialize)] #[serde(rename_all = "lowercase", deny_unknown_fields)] /// Whether the associated filters must all match for a device or if any one @@ -486,6 +532,7 @@ impl DiskSetup { } } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "lowercase", deny_unknown_fields)] /// Available filesystem during installation. @@ -500,6 +547,34 @@ pub enum Filesystem { Btrfs, } +#[cfg_attr(feature = "api-types", api( + properties: { + ashift: { + type: Integer, + minimum: 9, + maximum: 16, + default: 12, + optional: true, + }, + "arc-max": { + type: Integer, + // ZFS specifies 64 MiB as the absolute minimum. + minimum: 64, + optional: true, + }, + copies: { + type: Integer, + minimum: 1, + maximum: 3, + optional: true, + }, + hdsize: { + type: Number, + minimum: 2., + optional: true, + }, + }, +))] #[derive(Clone, Copy, Default, Deserialize, Debug, Serialize, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// ZFS-specific filesystem options. @@ -530,6 +605,35 @@ pub struct ZfsOptions { pub hdsize: Option, } +#[cfg_attr(feature = "api-types", api( + properties: { + hdsize: { + type: Number, + minimum: 2., + optional: true, + }, + swapsize: { + type: Number, + minimum: 0., + optional: true, + }, + maxroot: { + type: Number, + minimum: 2., + optional: true, + }, + maxvz: { + type: Number, + minimum: 0., + optional: true, + }, + minfree: { + type: Number, + minimum: 0., + optional: true, + }, + }, +))] #[derive(Clone, Copy, Default, Deserialize, Serialize, Debug, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// LVM-specific filesystem options, when using ext4 or xfs as filesystem. @@ -557,6 +661,14 @@ pub struct LvmOptions { pub minfree: Option, } +#[cfg_attr(feature = "api-types", api( + properties: { + hdsize: { + minimum: 2., + optional: true, + }, + }, +))] #[derive(Clone, Copy, Default, Deserialize, Debug, Serialize, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Btrfs-specific filesystem options. @@ -573,6 +685,7 @@ pub struct BtrfsOptions { pub compress: Option, } +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Deserialize, Serialize, Debug, Default, PartialEq)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] /// Keyboard layout of the system. @@ -664,6 +777,7 @@ impl Display for KeyboardLayout { serde_plain::derive_fromstr_from_deserialize!(KeyboardLayout); +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] #[serde(rename_all(deserialize = "lowercase", serialize = "UPPERCASE"))] /// Available Btrfs RAID levels. @@ -681,6 +795,7 @@ pub enum BtrfsRaidLevel { serde_plain::derive_display_from_serialize!(BtrfsRaidLevel); +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "lowercase")] /// Possible compression algorithms usable with Btrfs. See the accompanying @@ -708,6 +823,7 @@ pub const BTRFS_COMPRESS_OPTIONS: &[BtrfsCompressOption] = { &[On, Off, Zlib, Lzo, Zstd] }; +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] #[serde(rename_all = "UPPERCASE")] /// Available ZFS RAID levels. @@ -734,6 +850,7 @@ pub enum ZfsRaidLevel { serde_plain::derive_display_from_serialize!(ZfsRaidLevel); +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "lowercase")] /// Possible compression algorithms usable with ZFS. @@ -764,6 +881,7 @@ pub const ZFS_COMPRESS_OPTIONS: &[ZfsCompressOption] = { &[On, Off, Lzjb, Lz4, Zle, Gzip, Zstd] }; +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "kebab-case")] /// Possible checksum algorithms usable with ZFS. @@ -787,6 +905,7 @@ pub const ZFS_CHECKSUM_OPTIONS: &[ZfsChecksumOption] = { }; #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +#[cfg_attr(feature = "api-types", derive(Updater, UpdaterType))] /// The filesystem to use for the installation. pub enum FilesystemType { #[default] diff --git a/proxmox-installer-types/src/lib.rs b/proxmox-installer-types/src/lib.rs index 12679bdc..f39d05d3 100644 --- a/proxmox-installer-types/src/lib.rs +++ b/proxmox-installer-types/src/lib.rs @@ -10,6 +10,9 @@ pub mod answer; pub mod post_hook; +#[cfg(feature = "api-types")] +use proxmox_schema::api; + use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeMap, HashMap}, @@ -21,6 +24,7 @@ use proxmox_network_types::mac_address::MacAddress; /// Default placeholder value for the administrator email address. pub const EMAIL_DEFAULT_PLACEHOLDER: &str = "mail@example.invalid"; +#[cfg_attr(feature = "api-types", api)] #[derive(Copy, Clone, Eq, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "lowercase")] /// Whether the system boots using legacy BIOS or (U)EFI. @@ -43,6 +47,16 @@ pub struct UdevInfo { pub nics: BTreeMap, } +#[cfg_attr(feature = "api-types", api( + properties: { + network_interfaces: { + type: Array, + items: { + type: NetworkInterface, + }, + }, + }, +))] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// Information about the hardware and installer in use. pub struct SystemInfo { @@ -56,6 +70,7 @@ pub struct SystemInfo { pub network_interfaces: Vec, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// The per-product configuration of the installer. pub struct ProductConfig { @@ -78,6 +93,7 @@ impl ProductConfig { } } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// Information about the ISO itself. pub struct IsoInfo { @@ -97,6 +113,25 @@ impl IsoInfo { } } +#[cfg_attr(feature = "api-types", api( + properties: { + baseboard: { + type: Object, + properties: {}, + additional_properties: true, + }, + chassis: { + type: Object, + properties: {}, + additional_properties: true, + }, + system: { + type: Object, + properties: {}, + additional_properties: true, + }, + }, +))] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// Collection of various DMI information categories. pub struct SystemDMI { @@ -108,6 +143,7 @@ pub struct SystemDMI { pub system: HashMap, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] /// A unique network interface. pub struct NetworkInterface { @@ -117,6 +153,7 @@ pub struct NetworkInterface { pub mac: MacAddress, } +#[cfg_attr(feature = "api-types", api)] #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "lowercase")] diff --git a/proxmox-installer-types/src/post_hook.rs b/proxmox-installer-types/src/post_hook.rs index 8fbe54f8..b97df954 100644 --- a/proxmox-installer-types/src/post_hook.rs +++ b/proxmox-installer-types/src/post_hook.rs @@ -3,12 +3,21 @@ use serde::{Deserialize, Serialize}; use proxmox_network_types::ip_address::Cidr; +#[cfg(feature = "api-types")] +use proxmox_schema::api; use crate::{ answer::{FilesystemType, RebootMode}, BootType, IsoInfo, ProxmoxProduct, SystemDMI, UdevProperties, }; +#[cfg_attr(feature = "api-types", api( + properties: { + "secureboot": { + optional: true, + }, + }, +))] #[derive(Clone, Serialize, Deserialize, PartialEq)] /// Information about the system boot status. pub struct BootInfo { @@ -19,6 +28,7 @@ pub struct BootInfo { secureboot: bool, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Serialize, Deserialize, PartialEq)] /// Holds all the public keys for the different algorithms available. pub struct SshPublicHostKeys { @@ -30,6 +40,18 @@ pub struct SshPublicHostKeys { pub rsa: String, } +#[cfg_attr(feature = "api-types", api( + properties: { + "udev-properties": { + type: Object, + additional_properties: true, + properties: {}, + }, + "is-bootdisk": { + optional: true, + }, + }, +))] #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "kebab-case")] /// Holds information about a single disk in the system. @@ -43,6 +65,21 @@ pub struct DiskInfo { pub udev_properties: UdevProperties, } +#[cfg_attr(feature = "api-types", api( + properties: { + "udev-properties": { + type: Object, + additional_properties: true, + properties: {}, + }, + "is-management": { + optional: true, + }, + "is-pinned": { + optional: true, + }, + }, +))] /// Holds information about the management network interface. #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "kebab-case")] @@ -66,6 +103,7 @@ pub struct NetworkInterfaceInfo { pub udev_properties: UdevProperties, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "kebab-case")] /// Information about the installed product itself. @@ -78,6 +116,7 @@ pub struct ProductInfo { pub version: String, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Serialize, Deserialize, PartialEq)] /// The current kernel version. /// Aligns with the format as used by the `/nodes//status` API of each product. @@ -92,6 +131,7 @@ pub struct KernelVersionInformation { pub machine: String, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Serialize, Deserialize, PartialEq)] /// Information about the CPU(s) installed in the system pub struct CpuInfo { @@ -109,6 +149,7 @@ pub struct CpuInfo { pub sockets: u32, } +#[cfg_attr(feature = "api-types", api)] #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "kebab-case")] /// Metadata of the hook, such as schema version of the document. @@ -135,6 +176,21 @@ impl Default for PostHookInfoSchema { } } +#[cfg_attr(feature = "api-types", api( + properties: { + filesystem: { + type: String, + }, + disks: { + type: Array, + items: { type: DiskInfo }, + }, + "network-interfaces": { + type: Array, + items: { type: NetworkInterfaceInfo }, + } + }, +))] #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "kebab-case")] /// All data sent as request payload with the post-installation-webhook POST request. -- 2.51.2 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel