all lists on 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 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