public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Christoph Heiss <c.heiss@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH installer v3 37/38] tree-wide: switch out `Answer` -> `AutoInstallerConfig` types
Date: Fri,  3 Apr 2026 18:54:09 +0200	[thread overview]
Message-ID: <20260403165437.2166551-38-c.heiss@proxmox.com> (raw)
In-Reply-To: <20260403165437.2166551-1-c.heiss@proxmox.com>

The new `AutoInstallerConfig` type comes from proxmox-installer-types
and wholly replaces `Answer`.

No functional changes.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v2 -> v3:
  * new patch

 proxmox-auto-install-assistant/Cargo.toml     |   1 +
 proxmox-auto-install-assistant/src/main.rs    |   8 +-
 proxmox-auto-installer/src/answer.rs          |   7 +-
 .../src/bin/proxmox-auto-installer.rs         |  20 +--
 proxmox-auto-installer/src/sysinfo.rs         |  21 +--
 proxmox-auto-installer/src/utils.rs           | 142 ++++++++++--------
 proxmox-auto-installer/tests/parse-answer.rs  |   6 +-
 .../tests/resources/iso-info.json             |   4 +-
 ...rface_pinning_overlong_interface_name.json |   2 +-
 proxmox-installer-common/src/disk_checks.rs   |   5 +-
 proxmox-installer-common/src/lib.rs           |   3 -
 proxmox-installer-common/src/options.rs       | 119 +++++----------
 proxmox-installer-common/src/setup.rs         |  87 +----------
 proxmox-post-hook/src/main.rs                 |  31 ++--
 proxmox-tui-installer/src/main.rs             |  12 +-
 proxmox-tui-installer/src/options.rs          |   2 +-
 proxmox-tui-installer/src/views/bootdisk.rs   |  18 ++-
 17 files changed, 183 insertions(+), 305 deletions(-)

diff --git a/proxmox-auto-install-assistant/Cargo.toml b/proxmox-auto-install-assistant/Cargo.toml
index 9a61fb5..61253be 100644
--- a/proxmox-auto-install-assistant/Cargo.toml
+++ b/proxmox-auto-install-assistant/Cargo.toml
@@ -14,6 +14,7 @@ homepage = "https://www.proxmox.com"
 anyhow.workspace = true
 proxmox-auto-installer.workspace = true
 proxmox-installer-common = { workspace = true, features = [ "cli" ] }
+proxmox-installer-types.workspace = true
 serde_json.workspace = true
 toml.workspace = true
 
diff --git a/proxmox-auto-install-assistant/src/main.rs b/proxmox-auto-install-assistant/src/main.rs
index a92ac75..ee12c1e 100644
--- a/proxmox-auto-install-assistant/src/main.rs
+++ b/proxmox-auto-install-assistant/src/main.rs
@@ -18,7 +18,6 @@ use std::{
 };
 
 use proxmox_auto_installer::{
-    answer::{Answer, FilterMatch},
     sysinfo,
     utils::{
         AutoInstSettings, FetchAnswerFrom, HttpOptions, default_partition_label,
@@ -28,6 +27,7 @@ use proxmox_auto_installer::{
     },
 };
 use proxmox_installer_common::{FIRST_BOOT_EXEC_MAX_SIZE, FIRST_BOOT_EXEC_NAME, cli};
+use proxmox_installer_types::answer::{AutoInstallerConfig, FilterMatch};
 
 static PROXMOX_ISO_FLAG: &str = "/auto-installer-capable";
 
@@ -95,7 +95,7 @@ impl cli::Subcommand for CommandDeviceMatchArgs {
     fn parse(args: &mut cli::Arguments) -> Result<Self> {
         let filter_match = args
             .opt_value_from_str("--filter-match")?
-            .unwrap_or(FilterMatch::Any);
+            .unwrap_or_default();
 
         let device_type = args.free_from_str().context("parsing device type")?;
         let mut filter = vec![];
@@ -630,7 +630,7 @@ fn validate_answer_file_keys(path: impl AsRef<Path> + fmt::Debug) -> Result<bool
     }
 }
 
-fn verify_hashed_password_interactive(answer: &Answer) -> Result<()> {
+fn verify_hashed_password_interactive(answer: &AutoInstallerConfig) -> Result<()> {
     if let Some(hashed) = &answer.global.root_password_hashed {
         println!("Verifying hashed root password.");
 
@@ -1313,7 +1313,7 @@ fn get_udev_properties(path: impl AsRef<Path> + fmt::Debug) -> Result<String> {
     Ok(String::from_utf8(udev_output.stdout)?)
 }
 
-fn parse_answer(path: impl AsRef<Path> + fmt::Debug) -> Result<Answer> {
+fn parse_answer(path: impl AsRef<Path> + fmt::Debug) -> Result<AutoInstallerConfig> {
     let mut file = match fs::File::open(&path) {
         Ok(file) => file,
         Err(err) => bail!("Opening answer file {path:?} failed: {err}"),
diff --git a/proxmox-auto-installer/src/answer.rs b/proxmox-auto-installer/src/answer.rs
index eec5b58..c7e7298 100644
--- a/proxmox-auto-installer/src/answer.rs
+++ b/proxmox-auto-installer/src/answer.rs
@@ -6,10 +6,11 @@ use std::{
     net::IpAddr,
 };
 
-use proxmox_installer_common::options::{
-    BtrfsCompressOption, NetworkInterfacePinningOptions, ZfsChecksumOption, ZfsCompressOption,
+use proxmox_installer_common::options::NetworkInterfacePinningOptions;
+use proxmox_installer_types::answer::{
+    BtrfsCompressOption, BtrfsRaidLevel, FilesystemType, ZfsChecksumOption, ZfsCompressOption,
+    ZfsRaidLevel,
 };
-use proxmox_installer_types::answer::{BtrfsRaidLevel, FilesystemType, ZfsRaidLevel};
 use proxmox_network_types::{Cidr, fqdn::Fqdn};
 
 // NOTE New answer file properties must use kebab-case, but should allow snake_case for backwards
diff --git a/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs b/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
index 7614fbb..0ced7d4 100644
--- a/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
+++ b/proxmox-auto-installer/src/bin/proxmox-auto-installer.rs
@@ -3,11 +3,12 @@ use log::{LevelFilter, error, info};
 use std::{
     env,
     fs::{self, File},
-    io::{BufRead, BufReader, Write},
+    io::{BufRead, BufReader, Read, Write},
     path::PathBuf,
     process::ExitCode,
 };
 
+use proxmox_auto_installer::{log::AutoInstLogger, utils::parse_answer};
 use proxmox_installer_common::{
     FIRST_BOOT_EXEC_MAX_SIZE, FIRST_BOOT_EXEC_NAME, RUNTIME_DIR, http,
     setup::{
@@ -15,12 +16,9 @@ use proxmox_installer_common::{
         spawn_low_level_installer,
     },
 };
-
-use proxmox_auto_installer::{
-    answer::{Answer, FirstBootHookInfo, FirstBootHookSourceMode, RebootMode},
-    log::AutoInstLogger,
-    udevinfo::UdevInfo,
-    utils::parse_answer,
+use proxmox_installer_types::{
+    UdevInfo,
+    answer::{AutoInstallerConfig, FirstBootHookInfo, FirstBootHookSourceMode, RebootMode},
 };
 
 static LOGGER: AutoInstLogger = AutoInstLogger;
@@ -70,7 +68,7 @@ fn setup_first_boot_executable(first_boot: &FirstBootHookInfo) -> Result<()> {
     }
 }
 
-fn auto_installer_setup(in_test_mode: bool) -> Result<(Answer, UdevInfo)> {
+fn auto_installer_setup(in_test_mode: bool) -> Result<(AutoInstallerConfig, UdevInfo)> {
     let base_path = if in_test_mode { "./testdir" } else { "/" };
     let mut path = PathBuf::from(base_path);
 
@@ -85,7 +83,9 @@ fn auto_installer_setup(in_test_mode: bool) -> Result<(Answer, UdevInfo)> {
             .map_err(|err| format_err!("Failed to retrieve udev info details: {err}"))?
     };
 
-    let answer = Answer::try_from_reader(std::io::stdin().lock())?;
+    let mut raw_toml = String::new();
+    std::io::stdin().read_to_string(&mut raw_toml)?;
+    let answer: AutoInstallerConfig = toml::from_str(&raw_toml)?;
 
     if let Some(first_boot) = &answer.first_boot {
         setup_first_boot_executable(first_boot)?;
@@ -151,7 +151,7 @@ fn main() -> ExitCode {
 }
 
 fn run_installation(
-    answer: &Answer,
+    answer: &AutoInstallerConfig,
     locales: &LocaleInfo,
     runtime_info: &RuntimeInfo,
     udevadm_info: &UdevInfo,
diff --git a/proxmox-auto-installer/src/sysinfo.rs b/proxmox-auto-installer/src/sysinfo.rs
index 5129829..38f419f 100644
--- a/proxmox-auto-installer/src/sysinfo.rs
+++ b/proxmox-auto-installer/src/sysinfo.rs
@@ -2,10 +2,7 @@ use anyhow::{Result, bail};
 use std::{fs, io, path::PathBuf};
 
 use crate::utils::get_nic_list;
-use proxmox_installer_common::{
-    RUNTIME_DIR,
-    setup::{ProxmoxProduct, SetupInfo},
-};
+use proxmox_installer_common::{RUNTIME_DIR, setup::SetupInfo};
 use proxmox_installer_types::{NetworkInterface, SystemInfo};
 
 pub fn get() -> Result<SystemInfo> {
@@ -20,20 +17,8 @@ pub fn get() -> Result<SystemInfo> {
     };
 
     Ok(SystemInfo {
-        product: proxmox_installer_types::ProductConfig {
-            fullname: setup_info.config.fullname,
-            product: match setup_info.config.product {
-                ProxmoxProduct::PVE => proxmox_installer_types::ProxmoxProduct::Pve,
-                ProxmoxProduct::PBS => proxmox_installer_types::ProxmoxProduct::Pbs,
-                ProxmoxProduct::PMG => proxmox_installer_types::ProxmoxProduct::Pmg,
-                ProxmoxProduct::PDM => proxmox_installer_types::ProxmoxProduct::Pdm,
-            },
-            enable_btrfs: setup_info.config.enable_btrfs,
-        },
-        iso: proxmox_installer_types::IsoInfo {
-            release: setup_info.iso_info.release,
-            isorelease: setup_info.iso_info.isorelease,
-        },
+        product: setup_info.config,
+        iso: setup_info.iso_info,
         network_interfaces: get_all_network_interfaces()?,
         dmi: proxmox_installer_common::dmi::get()?,
     })
diff --git a/proxmox-auto-installer/src/utils.rs b/proxmox-auto-installer/src/utils.rs
index 83be913..8173ee8 100644
--- a/proxmox-auto-installer/src/utils.rs
+++ b/proxmox-auto-installer/src/utils.rs
@@ -6,33 +6,40 @@ use std::{
     process::Command,
 };
 
-use crate::{
+use proxmox_installer_types::{
+    UdevInfo,
     answer::{
-        self, Answer, DiskSelection, FirstBootHookSourceMode, FqdnConfig, FqdnExtendedConfig,
-        FqdnSourceMode, Network,
+        AutoInstallerConfig, DiskSelection, Filesystem, FilesystemOptions, FilesystemType,
+        FilterMatch, FirstBootHookSourceMode, FqdnConfig, FqdnFromDhcpConfig, FqdnSourceMode,
+        NetworkConfig,
     },
-    udevinfo::UdevInfo,
 };
+
 use proxmox_installer_common::{
     ROOT_PASSWORD_MIN_LENGTH,
     disk_checks::check_swapsize,
-    options::{NetworkOptions, RaidLevel, ZfsChecksumOption, ZfsCompressOption, email_validate},
+    options::{FilesystemDiskInfo, NetworkInterfacePinningOptions, NetworkOptions, email_validate},
     setup::{
         InstallBtrfsOption, InstallConfig, InstallFirstBootSetup, InstallRootPassword,
         InstallZfsOption, LocaleInfo, RuntimeInfo, SetupInfo,
     },
 };
-use proxmox_installer_types::answer::FilesystemType;
+
 use serde::{Deserialize, Serialize};
 
 fn get_network_settings(
-    answer: &Answer,
+    answer: &AutoInstallerConfig,
     udev_info: &UdevInfo,
     runtime_info: &RuntimeInfo,
     setup_info: &SetupInfo,
 ) -> Result<NetworkOptions> {
     info!("Setting up network configuration");
 
+    let pinning_opts = answer
+        .network
+        .interface_name_pinning()
+        .map(|answer| answer.into());
+
     let mut network_options = match &answer.global.fqdn {
         // If the user set a static FQDN in the answer file, override it
         FqdnConfig::Simple(name) => {
@@ -40,12 +47,12 @@ fn get_network_settings(
                 setup_info,
                 &runtime_info.network,
                 None,
-                answer.network.interface_name_pinning.as_ref(),
+                pinning_opts.as_ref(),
             );
             opts.fqdn = name.to_owned();
             opts
         }
-        FqdnConfig::Extended(FqdnExtendedConfig {
+        FqdnConfig::FromDhcp(FqdnFromDhcpConfig {
             source: FqdnSourceMode::FromDhcp,
             domain,
         }) => {
@@ -68,12 +75,12 @@ fn get_network_settings(
                 setup_info,
                 &runtime_info.network,
                 domain.as_deref(),
-                answer.network.interface_name_pinning.as_ref(),
+                pinning_opts.as_ref(),
             )
         }
     };
 
-    if let answer::NetworkSettings::Manual(settings) = &answer.network.network_settings {
+    if let NetworkConfig::FromAnswer(settings) = &answer.network {
         network_options.address = settings.cidr;
         network_options.dns_server = settings.dns;
         network_options.gateway = settings.gateway;
@@ -206,7 +213,7 @@ pub fn get_matched_udev_indexes(
 }
 
 fn set_disks(
-    answer: &Answer,
+    answer: &AutoInstallerConfig,
     udev_info: &UdevInfo,
     runtime_info: &RuntimeInfo,
     config: &mut InstallConfig,
@@ -222,13 +229,13 @@ fn set_disks(
 }
 
 fn set_single_disk(
-    answer: &Answer,
+    answer: &AutoInstallerConfig,
     udev_info: &UdevInfo,
     runtime_info: &RuntimeInfo,
     config: &mut InstallConfig,
 ) -> Result<()> {
-    match &answer.disks.disk_selection {
-        answer::DiskSelection::Selection(disk_list) => {
+    match answer.disks.disk_selection()? {
+        DiskSelection::Selection(disk_list) => {
             let disk_name = disk_list[0].clone();
             let disk = runtime_info
                 .disks
@@ -239,8 +246,8 @@ fn set_single_disk(
                 None => bail!("disk in 'disk-selection' not found"),
             }
         }
-        answer::DiskSelection::Filter(filter) => {
-            let disk_index = get_single_udev_index(filter, &udev_info.disks)?;
+        DiskSelection::Filter(filter) => {
+            let disk_index = get_single_udev_index(&filter, &udev_info.disks)?;
             let disk = runtime_info
                 .disks
                 .iter()
@@ -253,13 +260,13 @@ fn set_single_disk(
 }
 
 fn set_selected_disks(
-    answer: &Answer,
+    answer: &AutoInstallerConfig,
     udev_info: &UdevInfo,
     runtime_info: &RuntimeInfo,
     config: &mut InstallConfig,
 ) -> Result<()> {
-    match &answer.disks.disk_selection {
-        answer::DiskSelection::Selection(disk_list) => {
+    match answer.disks.disk_selection()? {
+        DiskSelection::Selection(disk_list) => {
             info!("Disk selection found");
             for disk_name in disk_list.clone() {
                 let disk = runtime_info
@@ -273,17 +280,13 @@ fn set_selected_disks(
                 }
             }
         }
-        answer::DiskSelection::Filter(filter) => {
+        DiskSelection::Filter(filter) => {
             info!("No disk list found, looking for disk filters");
-            let filter_match = answer
-                .disks
-                .filter_match
-                .clone()
-                .unwrap_or(answer::FilterMatch::Any);
+            let filter_match = answer.disks.filter_match.unwrap_or_default();
             let selected_disk_indexes = get_matched_udev_indexes(
-                filter,
+                &filter,
                 &udev_info.disks,
-                filter_match == answer::FilterMatch::All,
+                filter_match == FilterMatch::All,
             )?;
 
             for i in selected_disk_indexes.into_iter() {
@@ -336,19 +339,23 @@ fn get_first_selected_disk(config: &InstallConfig) -> usize {
         .expect("could not parse key to usize")
 }
 
-fn verify_filesystem_settings(answer: &Answer, setup_info: &SetupInfo) -> Result<()> {
+fn verify_filesystem_settings(
+    answer: &AutoInstallerConfig,
+    setup_info: &SetupInfo,
+) -> Result<FilesystemOptions> {
     info!("Verifying filesystem settings");
 
-    if answer.disks.fs_type.is_btrfs() && !setup_info.config.enable_btrfs {
+    let fs_options = answer.disks.filesystem_details()?;
+    if answer.disks.filesystem == Filesystem::Btrfs && !setup_info.config.enable_btrfs {
         bail!(
             "BTRFS is not supported as a root filesystem for the product or the release of this ISO."
         );
     }
 
-    Ok(())
+    Ok(fs_options)
 }
 
-pub fn verify_locale_settings(answer: &Answer, locales: &LocaleInfo) -> Result<()> {
+pub fn verify_locale_settings(answer: &AutoInstallerConfig, locales: &LocaleInfo) -> Result<()> {
     info!("Verifying locale settings");
     if !locales
         .countries
@@ -385,7 +392,7 @@ pub fn verify_locale_settings(answer: &Answer, locales: &LocaleInfo) -> Result<(
 ///
 /// Ensures that the provided email-address is of valid format and that one
 /// of the two root password options is set appropriately.
-pub fn verify_email_and_root_password_settings(answer: &Answer) -> Result<()> {
+pub fn verify_email_and_root_password_settings(answer: &AutoInstallerConfig) -> Result<()> {
     info!("Verifying email and root password settings");
 
     email_validate(&answer.global.mailto).with_context(|| answer.global.mailto.clone())?;
@@ -411,40 +418,41 @@ pub fn verify_email_and_root_password_settings(answer: &Answer) -> Result<()> {
     }
 }
 
-pub fn verify_disks_settings(answer: &Answer) -> Result<()> {
-    if let DiskSelection::Selection(selection) = &answer.disks.disk_selection {
-        let min_disks = match answer.disks.fs_type {
-            FilesystemType::Ext4 | FilesystemType::Xfs => 1,
-            FilesystemType::Zfs(level) => level.get_min_disks(),
-            FilesystemType::Btrfs(level) => level.get_min_disks(),
-        };
+pub fn verify_disks_settings(answer: &AutoInstallerConfig) -> Result<()> {
+    let fs_options = answer.disks.filesystem_details()?;
+
+    if let DiskSelection::Selection(selection) = answer.disks.disk_selection()? {
+        let min_disks = fs_options.to_type().get_min_disks();
 
         if selection.len() < min_disks {
             bail!(
                 "{}: need at least {} disks",
-                answer.disks.fs_type,
+                fs_options.to_type(),
                 min_disks
             );
         }
 
         let mut disk_set = HashSet::new();
-        for disk in selection {
+        for disk in &selection {
             if !disk_set.insert(disk) {
                 bail!("List of disks contains duplicate device {disk}");
             }
         }
     }
 
-    if let answer::FsOptions::LVM(lvm) = &answer.disks.fs_options
-        && let Some((swapsize, hdsize)) = lvm.swapsize.zip(lvm.hdsize)
-    {
-        check_swapsize(swapsize, hdsize)?;
+    match fs_options {
+        FilesystemOptions::Ext4(lvm) | FilesystemOptions::Xfs(lvm) => {
+            if let Some((swapsize, hdsize)) = lvm.swapsize.zip(lvm.hdsize) {
+                check_swapsize(swapsize, hdsize)?;
+            }
+        }
+        _ => {}
     }
 
     Ok(())
 }
 
-pub fn verify_first_boot_settings(answer: &Answer) -> Result<()> {
+pub fn verify_first_boot_settings(answer: &AutoInstallerConfig) -> Result<()> {
     info!("Verifying first boot settings");
 
     if let Some(first_boot) = &answer.first_boot
@@ -457,10 +465,16 @@ pub fn verify_first_boot_settings(answer: &Answer) -> Result<()> {
     Ok(())
 }
 
-pub fn verify_network_settings(network: &Network, run_env: Option<&RuntimeInfo>) -> Result<()> {
+pub fn verify_network_settings(
+    network: &NetworkConfig,
+    run_env: Option<&RuntimeInfo>,
+) -> Result<()> {
     info!("Verifying network settings");
 
-    if let Some(pin_opts) = &network.interface_name_pinning {
+    let pin_opts: Option<NetworkInterfacePinningOptions> =
+        network.interface_name_pinning().map(|v| v.into());
+
+    if let Some(pin_opts) = pin_opts {
         pin_opts.verify()?;
 
         if let Some(run_env) = run_env {
@@ -483,7 +497,7 @@ pub fn verify_network_settings(network: &Network, run_env: Option<&RuntimeInfo>)
 }
 
 pub fn parse_answer(
-    answer: &Answer,
+    answer: &AutoInstallerConfig,
     udev_info: &UdevInfo,
     runtime_info: &RuntimeInfo,
     locales: &LocaleInfo,
@@ -491,11 +505,10 @@ pub fn parse_answer(
 ) -> Result<InstallConfig> {
     info!("Parsing answer file");
 
-    verify_filesystem_settings(answer, setup_info)?;
+    let fs_options = verify_filesystem_settings(answer, setup_info)?;
 
     info!("Setting File system");
-    let filesystem = answer.disks.fs_type;
-    info!("File system selected: {}", filesystem);
+    info!("File system selected: {}", fs_options.to_type());
 
     let network_settings = get_network_settings(answer, udev_info, runtime_info, setup_info)?;
 
@@ -517,7 +530,7 @@ pub fn parse_answer(
 
     let mut config = InstallConfig {
         autoreboot: 1_usize,
-        filesys: filesystem,
+        filesys: fs_options.to_type(),
         hdsize: 0.,
         swapsize: None,
         maxroot: None,
@@ -553,8 +566,8 @@ pub fn parse_answer(
     };
 
     set_disks(answer, udev_info, runtime_info, &mut config)?;
-    match &answer.disks.fs_options {
-        answer::FsOptions::LVM(lvm) => {
+    match fs_options {
+        FilesystemOptions::Ext4(lvm) | FilesystemOptions::Xfs(lvm) => {
             let disk = runtime_info
                 .disks
                 .iter()
@@ -568,21 +581,24 @@ pub fn parse_answer(
             config.maxvz = lvm.maxvz;
             config.minfree = lvm.minfree;
         }
-        answer::FsOptions::ZFS(zfs) => {
+        FilesystemOptions::Zfs(zfs) => {
             let first_selected_disk = get_first_selected_disk(&config);
 
             config.hdsize = zfs
                 .hdsize
                 .unwrap_or(runtime_info.disks[first_selected_disk].size);
             config.zfs_opts = Some(InstallZfsOption {
-                ashift: zfs.ashift.unwrap_or(12),
-                arc_max: zfs.arc_max.unwrap_or(runtime_info.default_zfs_arc_max),
-                compress: zfs.compress.unwrap_or(ZfsCompressOption::On),
-                checksum: zfs.checksum.unwrap_or(ZfsChecksumOption::On),
-                copies: zfs.copies.unwrap_or(1),
+                ashift: zfs.ashift.unwrap_or(12) as usize,
+                arc_max: zfs
+                    .arc_max
+                    .map(|v| v as usize)
+                    .unwrap_or(runtime_info.default_zfs_arc_max),
+                compress: zfs.compress.unwrap_or_default(),
+                checksum: zfs.checksum.unwrap_or_default(),
+                copies: zfs.copies.unwrap_or(1) as usize,
             });
         }
-        answer::FsOptions::BTRFS(btrfs) => {
+        FilesystemOptions::Btrfs(btrfs) => {
             let first_selected_disk = get_first_selected_disk(&config);
 
             config.hdsize = btrfs
diff --git a/proxmox-auto-installer/tests/parse-answer.rs b/proxmox-auto-installer/tests/parse-answer.rs
index 7dd4a9d..675678a 100644
--- a/proxmox-auto-installer/tests/parse-answer.rs
+++ b/proxmox-auto-installer/tests/parse-answer.rs
@@ -2,13 +2,11 @@ use serde_json::Value;
 use std::fs;
 use std::path::{Path, PathBuf};
 
-use proxmox_auto_installer::answer::Answer;
-use proxmox_auto_installer::udevinfo::UdevInfo;
 use proxmox_auto_installer::utils::parse_answer;
-
 use proxmox_installer_common::setup::{
     LocaleInfo, RuntimeInfo, SetupInfo, load_installer_setup_files, read_json,
 };
+use proxmox_installer_types::{UdevInfo, answer::AutoInstallerConfig};
 
 fn get_test_resource_path() -> Result<PathBuf, String> {
     Ok(std::env::current_dir()
@@ -16,7 +14,7 @@ fn get_test_resource_path() -> Result<PathBuf, String> {
         .join("tests/resources"))
 }
 
-fn get_answer(path: impl AsRef<Path>) -> Result<Answer, String> {
+fn get_answer(path: impl AsRef<Path>) -> Result<AutoInstallerConfig, String> {
     let answer_raw = fs::read_to_string(path).unwrap();
     toml::from_str(&answer_raw)
         .map_err(|err| format!("error parsing answer.toml: {}", err.message()))
diff --git a/proxmox-auto-installer/tests/resources/iso-info.json b/proxmox-auto-installer/tests/resources/iso-info.json
index 881dafd..2cfbd6d 100644
--- a/proxmox-auto-installer/tests/resources/iso-info.json
+++ b/proxmox-auto-installer/tests/resources/iso-info.json
@@ -14,8 +14,8 @@
   },
   "product": "pve",
   "product-cfg": {
-    "bridged_network": 1,
-    "enable_btrfs": 1,
+    "bridged_network": true,
+    "enable_btrfs": true,
     "fullname": "Proxmox VE",
     "port": "8006",
     "product": "pve"
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/network_interface_pinning_overlong_interface_name.json b/proxmox-auto-installer/tests/resources/parse_answer_fail/network_interface_pinning_overlong_interface_name.json
index af4ed79..f3c9169 100644
--- a/proxmox-auto-installer/tests/resources/parse_answer_fail/network_interface_pinning_overlong_interface_name.json
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/network_interface_pinning_overlong_interface_name.json
@@ -1,3 +1,3 @@
 {
-  "parse-error": "error parsing answer.toml: interface name 'waytoolonginterfacename' for 'ab:cd:ef:12:34:56' cannot be longer than 15 characters"
+  "error": "interface name 'waytoolonginterfacename' for 'ab:cd:ef:12:34:56' cannot be longer than 15 characters"
 }
diff --git a/proxmox-installer-common/src/disk_checks.rs b/proxmox-installer-common/src/disk_checks.rs
index f17a7a6..fbed578 100644
--- a/proxmox-installer-common/src/disk_checks.rs
+++ b/proxmox-installer-common/src/disk_checks.rs
@@ -1,9 +1,8 @@
+use anyhow::ensure;
 use std::collections::HashSet;
 
-use anyhow::ensure;
-
 use crate::options::{Disk, LvmBootdiskOptions};
-use crate::setup::BootType;
+use proxmox_installer_types::BootType;
 
 /// Checks a list of disks for duplicate entries, using their index as key.
 ///
diff --git a/proxmox-installer-common/src/lib.rs b/proxmox-installer-common/src/lib.rs
index fde17b7..ee34096 100644
--- a/proxmox-installer-common/src/lib.rs
+++ b/proxmox-installer-common/src/lib.rs
@@ -19,9 +19,6 @@ pub mod net {
 
 pub const RUNTIME_DIR: &str = "/run/proxmox-installer";
 
-/// Default placeholder value for the administrator email address.
-pub const EMAIL_DEFAULT_PLACEHOLDER: &str = "mail@example.invalid";
-
 /// Name of the executable for the first-boot hook.
 pub const FIRST_BOOT_EXEC_NAME: &str = "proxmox-first-boot";
 
diff --git a/proxmox-installer-common/src/options.rs b/proxmox-installer-common/src/options.rs
index 8e19663..ed00b4b 100644
--- a/proxmox-installer-common/src/options.rs
+++ b/proxmox-installer-common/src/options.rs
@@ -1,6 +1,6 @@
 use anyhow::{Result, bail};
 use regex::{Regex, RegexBuilder};
-use serde::{Deserialize, Serialize};
+use serde::Deserialize;
 use std::{
     cmp,
     collections::HashMap,
@@ -12,7 +12,13 @@ use std::{
 use crate::disk_checks::check_raid_min_disks;
 use crate::net::{MAX_IFNAME_LEN, MIN_IFNAME_LEN};
 use crate::setup::{LocaleInfo, NetworkInfo, RuntimeInfo, SetupInfo};
-use proxmox_installer_types::answer::{BtrfsRaidLevel, FilesystemType, ZfsRaidLevel};
+use proxmox_installer_types::{
+    EMAIL_DEFAULT_PLACEHOLDER,
+    answer::{
+        BtrfsCompressOption, BtrfsRaidLevel, FilesystemType, NetworkInterfacePinningOptionsAnswer,
+        ZfsChecksumOption, ZfsCompressOption, ZfsRaidLevel,
+    },
+};
 use proxmox_network_types::{fqdn::Fqdn, ip_address::Cidr};
 
 pub trait RaidLevel {
@@ -123,35 +129,22 @@ impl LvmBootdiskOptions {
     }
 }
 
-/// See the accompanying mount option in btrfs(5).
-#[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq)]
-#[serde(rename_all(deserialize = "lowercase"))]
-pub enum BtrfsCompressOption {
-    On,
-    #[default]
-    Off,
-    Zlib,
-    Lzo,
-    Zstd,
+pub trait FilesystemDiskInfo {
+    /// Returns the minimum number of disks needed for this filesystem.
+    fn get_min_disks(&self) -> usize;
 }
 
-impl fmt::Display for BtrfsCompressOption {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", format!("{self:?}").to_lowercase())
+impl FilesystemDiskInfo for FilesystemType {
+    fn get_min_disks(&self) -> usize {
+        match self {
+            FilesystemType::Ext4 => 1,
+            FilesystemType::Xfs => 1,
+            FilesystemType::Zfs(level) => level.get_min_disks(),
+            FilesystemType::Btrfs(level) => level.get_min_disks(),
+        }
     }
 }
 
-impl From<&BtrfsCompressOption> for String {
-    fn from(value: &BtrfsCompressOption) -> Self {
-        value.to_string()
-    }
-}
-
-pub const BTRFS_COMPRESS_OPTIONS: &[BtrfsCompressOption] = {
-    use BtrfsCompressOption::*;
-    &[On, Off, Zlib, Lzo, Zstd]
-};
-
 #[derive(Clone, Debug)]
 pub struct BtrfsBootdiskOptions {
     pub disk_size: f64,
@@ -171,54 +164,6 @@ impl BtrfsBootdiskOptions {
     }
 }
 
-#[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum ZfsCompressOption {
-    #[default]
-    On,
-    Off,
-    Lzjb,
-    Lz4,
-    Zle,
-    Gzip,
-    Zstd,
-}
-
-serde_plain::derive_display_from_serialize!(ZfsCompressOption);
-
-impl From<&ZfsCompressOption> for String {
-    fn from(value: &ZfsCompressOption) -> Self {
-        value.to_string()
-    }
-}
-
-pub const ZFS_COMPRESS_OPTIONS: &[ZfsCompressOption] = {
-    use ZfsCompressOption::*;
-    &[On, Off, Lzjb, Lz4, Zle, Gzip, Zstd]
-};
-
-#[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
-#[serde(rename_all = "kebab-case")]
-pub enum ZfsChecksumOption {
-    #[default]
-    On,
-    Fletcher4,
-    Sha256,
-}
-
-serde_plain::derive_display_from_serialize!(ZfsChecksumOption);
-
-impl From<&ZfsChecksumOption> for String {
-    fn from(value: &ZfsChecksumOption) -> Self {
-        value.to_string()
-    }
-}
-
-pub const ZFS_CHECKSUM_OPTIONS: &[ZfsChecksumOption] = {
-    use ZfsChecksumOption::*;
-    &[On, Fletcher4, Sha256]
-};
-
 #[derive(Clone, Debug)]
 pub struct ZfsBootdiskOptions {
     pub ashift: usize,
@@ -430,6 +375,24 @@ impl NetworkInterfacePinningOptions {
     }
 }
 
+impl From<&NetworkInterfacePinningOptionsAnswer> for NetworkInterfacePinningOptions {
+    fn from(answer: &NetworkInterfacePinningOptionsAnswer) -> Self {
+        if answer.enabled {
+            Self {
+                // convert all MAC addresses to lowercase before further usage,
+                // to enable easy comparison
+                mapping: answer
+                    .mapping
+                    .iter()
+                    .map(|(k, v)| (k.to_lowercase(), v.clone()))
+                    .collect(),
+            }
+        } else {
+            Self::default()
+        }
+    }
+}
+
 #[derive(Clone, Debug, PartialEq)]
 pub struct NetworkOptions {
     pub ifname: String,
@@ -453,11 +416,7 @@ impl NetworkOptions {
         // worse case nothing breaks down *completely*.
         let mut this = Self {
             ifname: String::new(),
-            fqdn: Self::construct_fqdn(
-                network,
-                setup.config.product.default_hostname(),
-                default_domain,
-            ),
+            fqdn: Self::construct_fqdn(network, &setup.config.product.to_string(), default_domain),
             // Safety: The provided IP address/mask is always valid.
             // These are the same as used in the GTK-based installer.
             address: Cidr::new_v4([192, 168, 100, 2], 24).unwrap(),
@@ -576,7 +535,7 @@ pub fn email_validate(email: &str) -> Result<()> {
 
     if !re.is_match(email) {
         bail!("Email does not look like a valid address (user@domain.tld)")
-    } else if email == crate::EMAIL_DEFAULT_PLACEHOLDER {
+    } else if email == EMAIL_DEFAULT_PLACEHOLDER {
         bail!("Invalid (default) email address")
     }
 
diff --git a/proxmox-installer-common/src/setup.rs b/proxmox-installer-common/src/setup.rs
index 91f1250..57f9cf3 100644
--- a/proxmox-installer-common/src/setup.rs
+++ b/proxmox-installer-common/src/setup.rs
@@ -1,3 +1,4 @@
+use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
 use std::{
     cmp,
     collections::{BTreeMap, HashMap},
@@ -10,81 +11,14 @@ use std::{
     process::{self, Command, Stdio},
 };
 
-use proxmox_network_types::Cidr;
-use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
-
 use crate::options::{
-    BtrfsBootdiskOptions, BtrfsCompressOption, Disk, NetworkInterfacePinningOptions,
-    ZfsBootdiskOptions, ZfsChecksumOption, ZfsCompressOption,
+    BtrfsBootdiskOptions, Disk, NetworkInterfacePinningOptions, ZfsBootdiskOptions,
 };
-use proxmox_installer_types::answer::FilesystemType;
-
-#[allow(clippy::upper_case_acronyms)]
-#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum ProxmoxProduct {
-    PVE,
-    PBS,
-    PMG,
-    PDM,
-}
-
-impl ProxmoxProduct {
-    pub fn default_hostname(self) -> &'static str {
-        match self {
-            Self::PVE => "pve",
-            Self::PMG => "pmg",
-            Self::PBS => "pbs",
-            Self::PDM => "pdm",
-        }
-    }
-}
-
-impl fmt::Display for ProxmoxProduct {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match self {
-            Self::PVE => "pve",
-            Self::PMG => "pmg",
-            Self::PBS => "pbs",
-            Self::PDM => "pdm",
-        })
-    }
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct ProductConfig {
-    pub fullname: String,
-    pub product: ProxmoxProduct,
-    #[serde(deserialize_with = "deserialize_bool_from_int")]
-    pub enable_btrfs: bool,
-}
-
-impl ProductConfig {
-    /// A mocked ProductConfig simulating a Proxmox VE environment.
-    pub fn mocked() -> Self {
-        Self {
-            fullname: String::from("Proxmox VE (mocked)"),
-            product: ProxmoxProduct::PVE,
-            enable_btrfs: true,
-        }
-    }
-}
-
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct IsoInfo {
-    pub release: String,
-    pub isorelease: String,
-}
-
-impl IsoInfo {
-    /// A mocked IsoInfo with some edge case to convey that this is not necessarily purely numeric.
-    pub fn mocked() -> Self {
-        Self {
-            release: String::from("42.1"),
-            isorelease: String::from("mocked-1"),
-        }
-    }
-}
+use proxmox_installer_types::{
+    BootType, IsoInfo, ProductConfig,
+    answer::{BtrfsCompressOption, FilesystemType, ZfsChecksumOption, ZfsCompressOption},
+};
+use proxmox_network_types::Cidr;
 
 /// Paths in the ISO environment containing installer data.
 #[derive(Clone, Deserialize)]
@@ -387,13 +321,6 @@ pub struct RuntimeInfo {
     pub default_zfs_arc_max: usize,
 }
 
-#[derive(Copy, Clone, Eq, Deserialize, PartialEq, Serialize)]
-#[serde(rename_all = "lowercase")]
-pub enum BootType {
-    Bios,
-    Efi,
-}
-
 #[derive(Clone, Deserialize)]
 pub struct NetworkInfo {
     pub dns: Dns,
diff --git a/proxmox-post-hook/src/main.rs b/proxmox-post-hook/src/main.rs
index 9025c01..9d7932a 100644
--- a/proxmox-post-hook/src/main.rs
+++ b/proxmox-post-hook/src/main.rs
@@ -36,12 +36,10 @@ mod detail {
 
     use proxmox_installer_common::{
         options::{Disk, NetworkOptions},
-        setup::{
-            InstallConfig, ProxmoxProduct, RuntimeInfo, SetupInfo, load_installer_setup_files,
-        },
+        setup::{InstallConfig, RuntimeInfo, SetupInfo, load_installer_setup_files},
     };
     use proxmox_installer_types::{
-        BootType, IsoInfo, UdevInfo,
+        ProxmoxProduct, UdevInfo,
         answer::{AutoInstallerConfig, FqdnConfig, FqdnFromDhcpConfig, FqdnSourceMode},
         post_hook::{
             BootInfo, CpuInfo, DiskInfo, KernelVersionInformation, NetworkInterfaceInfo,
@@ -119,16 +117,10 @@ mod detail {
             },
             debian_version: read_file("/etc/debian_version")?,
             product: gather_product_info(&setup_info, &run_cmd)?,
-            iso: IsoInfo {
-                release: setup_info.iso_info.release,
-                isorelease: setup_info.iso_info.isorelease,
-            },
+            iso: setup_info.iso_info,
             kernel_version: gather_kernel_version(&run_cmd, &open_file)?,
             boot_info: BootInfo {
-                mode: match run_env.boot_type {
-                    proxmox_installer_common::setup::BootType::Bios => BootType::Bios,
-                    proxmox_installer_common::setup::BootType::Efi => BootType::Efi,
-                },
+                mode: run_env.boot_type,
                 secureboot: run_env.secure_boot,
             },
             cpu_info: gather_cpu_info(&run_env)?,
@@ -271,10 +263,10 @@ mod detail {
         run_cmd: &dyn Fn(&[&str]) -> Result<String>,
     ) -> Result<ProductInfo> {
         let package = match setup_info.config.product {
-            ProxmoxProduct::PVE => "pve-manager",
-            ProxmoxProduct::PMG => "pmg-api",
-            ProxmoxProduct::PBS => "proxmox-backup-server",
-            ProxmoxProduct::PDM => "proxmox-datacenter-manager",
+            ProxmoxProduct::Pve => "pve-manager",
+            ProxmoxProduct::Pmg => "pmg-api",
+            ProxmoxProduct::Pbs => "proxmox-backup-server",
+            ProxmoxProduct::Pdm => "proxmox-datacenter-manager",
         };
 
         let version = run_cmd(&[
@@ -288,12 +280,7 @@ mod detail {
 
         Ok(ProductInfo {
             fullname: setup_info.config.fullname.clone(),
-            short: match setup_info.config.product {
-                ProxmoxProduct::PVE => proxmox_installer_types::ProxmoxProduct::Pve,
-                ProxmoxProduct::PBS => proxmox_installer_types::ProxmoxProduct::Pbs,
-                ProxmoxProduct::PMG => proxmox_installer_types::ProxmoxProduct::Pmg,
-                ProxmoxProduct::PDM => proxmox_installer_types::ProxmoxProduct::Pdm,
-            },
+            short: setup_info.config.product,
             version,
         })
     }
diff --git a/proxmox-tui-installer/src/main.rs b/proxmox-tui-installer/src/main.rs
index d2fd3d8..6c457aa 100644
--- a/proxmox-tui-installer/src/main.rs
+++ b/proxmox-tui-installer/src/main.rs
@@ -13,17 +13,19 @@ use cursive::{
     },
 };
 
-mod options;
-use options::{InstallerOptions, PasswordOptions};
-
 use proxmox_installer_common::{
     ROOT_PASSWORD_MIN_LENGTH,
     options::{
         BootdiskOptions, NetworkInterfacePinningOptions, NetworkOptions, TimezoneOptions,
         email_validate,
     },
-    setup::{LocaleInfo, ProxmoxProduct, RuntimeInfo, SetupInfo, installer_setup},
+    setup::{LocaleInfo, RuntimeInfo, SetupInfo, installer_setup},
 };
+use proxmox_installer_types::ProxmoxProduct;
+
+mod options;
+use options::{InstallerOptions, PasswordOptions};
+
 mod setup;
 
 mod system;
@@ -213,7 +215,7 @@ fn installer_setup_late(siv: &mut Cursive) {
         );
     }
 
-    if state.setup_info.config.product == ProxmoxProduct::PVE && !state.runtime_info.hvm_supported {
+    if state.setup_info.config.product == ProxmoxProduct::Pve && !state.runtime_info.hvm_supported {
         display_setup_warning(
             siv,
             concat!(
diff --git a/proxmox-tui-installer/src/options.rs b/proxmox-tui-installer/src/options.rs
index ff15fa0..2c156e8 100644
--- a/proxmox-tui-installer/src/options.rs
+++ b/proxmox-tui-installer/src/options.rs
@@ -1,10 +1,10 @@
 use crate::SummaryOption;
 
 use proxmox_installer_common::{
-    EMAIL_DEFAULT_PLACEHOLDER,
     options::{BootdiskOptions, NetworkOptions, TimezoneOptions},
     setup::LocaleInfo,
 };
+use proxmox_installer_types::EMAIL_DEFAULT_PLACEHOLDER;
 
 #[derive(Clone)]
 pub struct PasswordOptions {
diff --git a/proxmox-tui-installer/src/views/bootdisk.rs b/proxmox-tui-installer/src/views/bootdisk.rs
index ed3936f..a0267f1 100644
--- a/proxmox-tui-installer/src/views/bootdisk.rs
+++ b/proxmox-tui-installer/src/views/bootdisk.rs
@@ -22,13 +22,19 @@ use proxmox_installer_common::{
         check_disks_4kn_legacy_boot, check_for_duplicate_disks, check_lvm_bootdisk_opts,
     },
     options::{
-        AdvancedBootdiskOptions, BTRFS_COMPRESS_OPTIONS, BootdiskOptions, BtrfsBootdiskOptions,
-        Disk, LvmBootdiskOptions, RaidLevel, ZFS_CHECKSUM_OPTIONS, ZFS_COMPRESS_OPTIONS,
-        ZfsBootdiskOptions,
+        AdvancedBootdiskOptions, BootdiskOptions, BtrfsBootdiskOptions, Disk, LvmBootdiskOptions,
+        RaidLevel, ZfsBootdiskOptions,
+    },
+    setup::RuntimeInfo,
+};
+
+use proxmox_installer_types::{
+    BootType, ProductConfig, ProxmoxProduct,
+    answer::{
+        BTRFS_COMPRESS_OPTIONS, FILESYSTEM_TYPE_OPTIONS, FilesystemType, ZFS_CHECKSUM_OPTIONS,
+        ZFS_COMPRESS_OPTIONS,
     },
-    setup::{BootType, ProductConfig, ProxmoxProduct, RuntimeInfo},
 };
-use proxmox_installer_types::answer::{FILESYSTEM_TYPE_OPTIONS, FilesystemType};
 
 /// OpenZFS specifies 64 MiB as the absolute minimum:
 /// <https://openzfs.github.io/openzfs-docs/Performance%20and%20Tuning/Module%20Parameters.html#zfs-arc-max>
@@ -328,7 +334,7 @@ struct LvmBootdiskOptionsView {
 
 impl LvmBootdiskOptionsView {
     fn new(disk: &Disk, options: &LvmBootdiskOptions, product_conf: &ProductConfig) -> Self {
-        let show_extra_fields = product_conf.product == ProxmoxProduct::PVE;
+        let show_extra_fields = product_conf.product == ProxmoxProduct::Pve;
 
         let view = FormView::new()
             .child(
-- 
2.53.0





  parent reply	other threads:[~2026-04-03 16:58 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-03 16:53 [PATCH proxmox/yew-pwt/datacenter-manager/installer v3 00/38] add auto-installer integration Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 01/38] api-macro: allow $ in identifier name Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 02/38] schema: oneOf: allow single string variant Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 03/38] schema: implement UpdaterType for HashMap and BTreeMap Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 04/38] network-types: move `Fqdn` type from proxmox-installer-common Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 05/38] network-types: implement api type for Fqdn Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 06/38] network-types: add api wrapper type for std::net::IpAddr Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 07/38] network-types: cidr: implement generic `IpAddr::new` constructor Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 08/38] network-types: fqdn: implement standard library Error for Fqdn Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 09/38] node-status: make KernelVersionInformation Clone + PartialEq Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 10/38] installer-types: add common types used by the installer Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 11/38] installer-types: add types used by the auto-installer Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 12/38] installer-types: implement api type for all externally-used types Christoph Heiss
2026-04-03 16:53 ` [PATCH yew-widget-toolkit v3 13/38] widget: kvlist: add widget for user-modifiable data tables Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 14/38] api-types, cli: use ReturnType::new() instead of constructing it manually Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 15/38] api-types: add api types for auto-installer integration Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 16/38] config: add auto-installer configuration module Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 17/38] acl: wire up new /system/auto-installation acl path Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 18/38] server: api: add auto-installer integration module Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 19/38] server: api: auto-installer: add access token management endpoints Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 20/38] client: add bindings for auto-installer endpoints Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 21/38] ui: auto-installer: add installations overview panel Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 22/38] ui: auto-installer: add prepared answer configuration panel Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 23/38] ui: auto-installer: add access token " Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 24/38] docs: add documentation for auto-installer integration Christoph Heiss
2026-04-03 16:53 ` [PATCH installer v3 25/38] install: iso env: use JSON boolean literals for product config Christoph Heiss
2026-04-03 16:53 ` [PATCH installer v3 26/38] common: http: allow passing custom headers to post() Christoph Heiss
2026-04-03 16:53 ` [PATCH installer v3 27/38] common: options: move regex construction out of loop Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 28/38] assistant: support adding an authorization token for HTTP-based answers Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 29/38] tree-wide: used moved `Fqdn` type to proxmox-network-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 30/38] tree-wide: use `Cidr` type from proxmox-network-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 31/38] tree-wide: switch to filesystem types from proxmox-installer-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 32/38] post-hook: switch to types in proxmox-installer-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 33/38] auto: sysinfo: switch to types from proxmox-installer-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 34/38] fetch-answer: " Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 35/38] fetch-answer: http: prefer json over toml for answer format Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 36/38] fetch-answer: send auto-installer HTTP authorization token if set Christoph Heiss
2026-04-03 16:54 ` Christoph Heiss [this message]
2026-04-03 16:54 ` [PATCH installer v3 38/38] auto: drop now-dead answer file definitions Christoph Heiss

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=20260403165437.2166551-38-c.heiss@proxmox.com \
    --to=c.heiss@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal