[pve-devel] [PATCH v3 09/30] auto-installer: add answer file definition

Christoph Heiss c.heiss at proxmox.com
Fri Mar 29 12:43:08 CET 2024


Mostly just some comments regarding the struct (member) definitions, to
make them (and their accompanying) checks a bit simpler.

On Thu, Mar 28, 2024 at 02:50:07PM +0100, Aaron Lauterer wrote:
> Signed-off-by: Aaron Lauterer <a.lauterer at proxmox.com>
> ---
[..]
> diff --git a/proxmox-auto-installer/src/answer.rs b/proxmox-auto-installer/src/answer.rs
> new file mode 100644
> index 0000000..96e5608
> --- /dev/null
> +++ b/proxmox-auto-installer/src/answer.rs
> @@ -0,0 +1,256 @@
[..]
> +#[derive(Clone, Deserialize, Debug)]
> +pub struct Global {
> +    pub country: String,
> +    pub fqdn: Fqdn,
> +    pub keyboard: String,
> +    pub mailto: String,
> +    pub timezone: String,
> +    pub password: String,
> +    pub pre_command: Option<Vec<String>>,
> +    pub post_command: Option<Vec<String>>,
> +    pub reboot_on_error: Option<bool>,

How about using

    #[serde(default)]
    pub reboot_on_error: bool,

here? Would make checks using this a bit simpler as well.

> +}
> +
> +#[derive(Clone, Deserialize, Debug)]
> +struct NetworkInAnswer {
> +    pub use_dhcp: Option<bool>,

Same here as for `reboot_on_error`.

> +    pub cidr: Option<CidrAddress>,
> +    pub dns: Option<IpAddr>,
> +    pub gateway: Option<IpAddr>,
> +    // use BTreeMap to have keys sorted

Since this comment appears multiple times in this, how about moving this
into a module-level comment, explaining it there with a full sentence?

> +    pub filter: Option<BTreeMap<String, String>>,
> +}
> +
[..]
> +
> +#[derive(Clone, Debug)]
> +pub enum NetworkSettings {
> +    Dhcp(bool),

`Dhcp` as variant without the `bool` should work too. At least nothing
seems to exlicitly match on this variant from a quick grep.

> +    Manual(NetworkManual),
> +}
> +
> +#[derive(Clone, Debug)]
> +pub struct NetworkManual {
> +    pub cidr: CidrAddress,
> +    pub dns: IpAddr,
> +    pub gateway: IpAddr,
> +    // use BTreeMap to have keys sorted
> +    pub filter: BTreeMap<String, String>,
> +}
> +
> +#[derive(Clone, Deserialize, Debug)]
> +pub struct DiskSetup {
> +    pub filesystem: Filesystem,
> +    pub disk_list: Option<Vec<String>>,

Could this be a

  #[serde(default)]
  pub disk_list: Vec<String>,

as well? Both a missing & an empty list are invalid, right?

> +    // use BTreeMap to have keys sorted
> +    pub filter: Option<BTreeMap<String, String>>,
> +    pub filter_match: Option<FilterMatch>,
> +    pub zfs: Option<ZfsOptions>,
> +    pub lvm: Option<LvmOptions>,
> +    pub btrfs: Option<BtrfsOptions>,
> +}
> +
[..]
> +
> +impl TryFrom<DiskSetup> for Disks {
> +    type Error = &'static str;
> +
> +    fn try_from(source: DiskSetup) -> Result<Self, Self::Error> {
> +        if source.disk_list.is_none() && source.filter.is_none() {
> +            return Err("Need either 'disk_list' or 'filter' set");
> +        }
> +        if source.disk_list.clone().is_some_and(|v| v.is_empty()) {
                              ^^^^^^^^

nit: .as_ref() works here as well and would avoid a allocation.


> +            return Err("'disk_list' cannot be empty");
> +        }
> +        if source.disk_list.is_some() && source.filter.is_some() {
> +            return Err("Cannot use both, 'disk_list' and 'filter'");
> +        }
> +
> +        let disk_selection = match source.disk_list {
> +            Some(disk_list) => DiskSelection::Selection(disk_list),
> +            None => DiskSelection::Filter(source.filter.unwrap()),
> +        };
> +
> +        // TODO: improve checks for foreign FS options. E.g. less verbose and handling new FS types
> +        // automatically
> +        let fs_options;
> +        let fs = match source.filesystem {

This could be a

  let (fs, fs_options) = match source.filesystem {

..

> +            Filesystem::Xfs => {
> +                if source.zfs.is_some() || source.btrfs.is_some() {
> +                    return Err("make sure only 'lvm' options are set");
> +                }
> +                fs_options = FsOptions::LVM(source.lvm.unwrap_or(LvmOptions::default()));
> +                FsType::Xfs

.. and then here instead

  (FsType::Xfs, FsOptions::LVM(source.lvm.unwrap_or(LvmOptions::default())))

as well for all the below cases, of course.

> +            }
> +            Filesystem::Ext4 => {
> +                if source.zfs.is_some() || source.btrfs.is_some() {
> +                    return Err("make sure only 'lvm' options are set");
> +                }
> +                fs_options = FsOptions::LVM(source.lvm.unwrap_or(LvmOptions::default()));
> +                FsType::Ext4
> +            }
> +            Filesystem::Zfs => {
> +                if source.lvm.is_some() || source.btrfs.is_some() {
> +                    return Err("make sure only 'zfs' options are set");
> +                }
> +                if source.zfs.is_none() || source.zfs.is_some_and(|v| v.raid.is_none()) {
> +                    return Err("ZFS raid level 'zfs.raid' must be set");
> +                }
> +                fs_options = FsOptions::ZFS(source.zfs.unwrap());
> +                FsType::Zfs(source.zfs.unwrap().raid.unwrap())
> +            }
> +            Filesystem::Btrfs => {
> +                if source.zfs.is_some() || source.lvm.is_some() {
> +                    return Err("make sure only 'btrfs' options are set");
> +                }
> +                if source.btrfs.is_none() || source.btrfs.is_some_and(|v| v.raid.is_none()) {
> +                    return Err("BRFS raid level 'btrfs.raid' must be set");
> +                }
> +                fs_options = FsOptions::BRFS(source.btrfs.unwrap());
> +                FsType::Btrfs(source.btrfs.unwrap().raid.unwrap())

Maybe make it a bit more succinctly like

    match source.btrfs {
	None => return Err(".."),
	Some(BtrfsOptions { raid: None, .. }) => return Err(".."),
	Some(opts) => (FsType::Btrfs(opts.raid.unwrap()), FsOptions::BRFS(opts)),
    }

> +            }
> +        };
> +
> +        let res = Disks {
> +            fs_type: fs,
> +            disk_selection,
> +            filter_match: source.filter_match,
> +            fs_options,
> +        };
> +        Ok(res)
> +    }
> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum FsOptions {
> +    LVM(LvmOptions),
> +    ZFS(ZfsOptions),
> +    BRFS(BtrfsOptions),
       ^^^^

The 'T' seems to got lost somewhere along the way :^)

> +}
> +
> +#[derive(Clone, Debug)]
> +pub enum DiskSelection {
> +    Selection(Vec<String>),
> +    Filter(BTreeMap<String, String>),
> +}
> +#[derive(Clone, Deserialize, Debug, PartialEq)]
> +#[serde(rename_all = "lowercase")]
> +pub enum FilterMatch {
> +    Any,
> +    All,
> +}
> +
> +#[derive(Clone, IntoEnumIterator, Deserialize, Serialize, Debug, PartialEq)]
		   ^^^^^^^^^^^^^^^^

Is this trait actually used somewhere or just some dead leftover?
Not familiar with the crate, but removing this still compiles everything
(aka. `make deb`) fine.

If it's really just a leftover, the whole crate dependency could be
dropped.

> +#[serde(rename_all = "lowercase")]
> +pub enum Filesystem {
> +    Ext4,
> +    Xfs,
> +    Zfs,
> +    Btrfs,
> +}
> +
> +#[derive(Clone, Copy, Default, Deserialize, Debug)]
> +pub struct ZfsOptions {
> +    pub raid: Option<ZfsRaidLevel>,
> +    pub ashift: Option<usize>,
> +    pub arc_max: Option<usize>,
> +    pub checksum: Option<ZfsChecksumOption>,
> +    pub compress: Option<ZfsCompressOption>,
> +    pub copies: Option<usize>,
> +    pub hdsize: Option<f64>,
> +}
> +
> +impl ZfsOptions {
> +    pub fn new() -> ZfsOptions {
> +        ZfsOptions::default()
> +    }
> +}

Again, needed? Doesn't seem to be used anywhere.

> +
> +#[derive(Clone, Copy, Default, Deserialize, Serialize, Debug)]
> +pub struct LvmOptions {
> +    pub hdsize: Option<f64>,
> +    pub swapsize: Option<f64>,
> +    pub maxroot: Option<f64>,
> +    pub maxvz: Option<f64>,
> +    pub minfree: Option<f64>,
> +}
> +
> +impl LvmOptions {
> +    pub fn new() -> LvmOptions {
> +        LvmOptions::default()
> +    }
> +}

^ same as ZfsOptions::new()

> +
> +#[derive(Clone, Copy, Default, Deserialize, Debug)]
> +pub struct BtrfsOptions {
> +    pub hdsize: Option<f64>,
> +    pub raid: Option<BtrfsRaidLevel>,
> +}
> +
> +impl BtrfsOptions {
> +    pub fn new() -> BtrfsOptions {
> +        BtrfsOptions::default()
> +    }
> +}

^ same as ZfsOptions::new()

> diff --git a/proxmox-auto-installer/src/lib.rs b/proxmox-auto-installer/src/lib.rs
> index e69de29..7813b98 100644
> --- a/proxmox-auto-installer/src/lib.rs
> +++ b/proxmox-auto-installer/src/lib.rs
> @@ -0,0 +1 @@
> +pub mod answer;
> --
> 2.39.2
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel at lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>




More information about the pve-devel mailing list