1 use std
::{cell::RefCell, collections::HashSet, marker::PhantomData, rc::Rc}
;
4 view
::{Nameable, Resizable, ViewWrapper}
,
6 Button
, Dialog
, DummyView
, LinearLayout
, NamedView
, PaddedView
, Panel
, ScrollView
,
12 use super::{DiskSizeEditView, FormView, IntegerEditView}
;
15 AdvancedBootdiskOptions
, BootdiskOptions
, BtrfsBootdiskOptions
, BtrfsRaidLevel
, Disk
,
16 FsType
, LvmBootdiskOptions
, ZfsBootdiskOptions
, ZfsRaidLevel
, FS_TYPES
,
17 ZFS_CHECKSUM_OPTIONS
, ZFS_COMPRESS_OPTIONS
,
19 setup
::{BootType, RuntimeInfo}
,
21 use crate::{setup::ProxmoxProduct, InstallerState}
;
23 pub struct BootdiskOptionsView
{
25 advanced_options
: Rc
<RefCell
<BootdiskOptions
>>,
28 impl BootdiskOptionsView
{
29 pub fn new(disks
: &[Disk
], options
: &BootdiskOptions
) -> Self {
30 let bootdisk_form
= FormView
::new()
35 .with_all(disks
.iter().map(|d
| (d
.to_string(), d
.clone()))),
37 .with_name("bootdisk-options-target-disk");
39 let advanced_options
= Rc
::new(RefCell
::new(options
.clone()));
41 let advanced_button
= LinearLayout
::horizontal()
42 .child(DummyView
.full_width())
43 .child(Button
::new("Advanced options", {
44 let disks
= disks
.to_owned();
45 let options
= advanced_options
.clone();
47 siv
.add_layer(advanced_options_view(&disks
, options
.clone()));
51 let view
= LinearLayout
::vertical()
54 .child(advanced_button
);
62 pub fn get_values(&mut self) -> Result
<BootdiskOptions
, String
> {
63 let mut options
= (*self.advanced_options
).clone().into_inner();
65 if [FsType
::Ext4
, FsType
::Xfs
].contains(&options
.fstype
) {
69 .and_then(|v
| v
.downcast_mut
::<NamedView
<FormView
>>())
70 .map(NamedView
::<FormView
>::get_mut
)
71 .and_then(|v
| v
.get_value
::<SelectView
<Disk
>, _
>(0))
72 .ok_or("failed to retrieve bootdisk")?
;
74 options
.disks
= vec
![disk
];
81 impl ViewWrapper
for BootdiskOptionsView
{
82 cursive
::wrap_impl
!(self.view
: LinearLayout
);
85 struct AdvancedBootdiskOptionsView
{
89 impl AdvancedBootdiskOptionsView
{
90 fn new(disks
: &[Disk
], options
: &BootdiskOptions
) -> Self {
91 let enable_btrfs
= crate::setup_info().config
.enable_btrfs
;
93 let filter_btrfs
= |fstype
: &&FsType
| -> bool { enable_btrfs || !fstype.is_btrfs() }
;
95 let fstype_select
= SelectView
::new()
100 .filter(filter_btrfs
)
101 .map(|t
| (t
.to_string(), *t
)),
106 .filter(filter_btrfs
)
107 .position(|t
| *t
== options
.fstype
)
108 .unwrap_or_default(),
111 let disks
= disks
.to_owned();
112 move |siv
, fstype
| Self::fstype_on_submit(siv
, &disks
, fstype
)
115 let mut view
= LinearLayout
::vertical()
116 .child(DummyView
.full_width())
117 .child(FormView
::new().child("Filesystem", fstype_select
))
118 .child(DummyView
.full_width());
120 match &options
.advanced
{
121 AdvancedBootdiskOptions
::Lvm(lvm
) => view
.add_child(LvmBootdiskOptionsView
::new(lvm
)),
122 AdvancedBootdiskOptions
::Zfs(zfs
) => {
123 view
.add_child(ZfsBootdiskOptionsView
::new(disks
, zfs
))
125 AdvancedBootdiskOptions
::Btrfs(btrfs
) => {
126 view
.add_child(BtrfsBootdiskOptionsView
::new(disks
, btrfs
))
133 fn fstype_on_submit(siv
: &mut Cursive
, disks
: &[Disk
], fstype
: &FsType
) {
134 siv
.call_on_name("advanced-bootdisk-options-dialog", |view
: &mut Dialog
| {
135 if let Some(AdvancedBootdiskOptionsView { view }
) =
136 view
.get_content_mut().downcast_mut()
138 view
.remove_child(3);
140 FsType
::Ext4
| FsType
::Xfs
=> view
.add_child(LvmBootdiskOptionsView
::new(
141 &LvmBootdiskOptions
::defaults_from(&disks
[0]),
143 FsType
::Zfs(_
) => view
.add_child(ZfsBootdiskOptionsView
::new(
145 &ZfsBootdiskOptions
::defaults_from(disks
),
147 FsType
::Btrfs(_
) => view
.add_child(BtrfsBootdiskOptionsView
::new(
149 &BtrfsBootdiskOptions
::defaults_from(disks
),
156 "bootdisk-options-target-disk",
157 |view
: &mut FormView
| match fstype
{
158 FsType
::Ext4
| FsType
::Xfs
=> {
163 .with_all(disks
.iter().map(|d
| (d
.to_string(), d
.clone()))),
166 other
=> view
.replace_child(0, TextView
::new(other
.to_string())),
171 fn get_values(&mut self, runinfo
: &RuntimeInfo
) -> Result
<BootdiskOptions
, String
> {
175 .and_then(|v
| v
.downcast_ref
::<FormView
>())
176 .and_then(|v
| v
.get_value
::<SelectView
<FsType
>, _
>(0))
177 .ok_or("Failed to retrieve filesystem type".to_owned())?
;
182 .ok_or("Failed to retrieve advanced bootdisk options view".to_owned())?
;
184 if let Some(view
) = advanced
.downcast_mut
::<LvmBootdiskOptionsView
>() {
187 .map(AdvancedBootdiskOptions
::Lvm
)
188 .ok_or("Failed to retrieve advanced bootdisk options")?
;
195 } else if let Some(view
) = advanced
.downcast_mut
::<ZfsBootdiskOptionsView
>() {
196 let (disks
, advanced
) = view
198 .ok_or("Failed to retrieve advanced bootdisk options")?
;
200 if let FsType
::Zfs(level
) = fstype
{
201 check_zfs_raid_config(runinfo
, level
, &disks
)
202 .map_err(|err
| format
!("{fstype}: {err}"))?
;
208 advanced
: AdvancedBootdiskOptions
::Zfs(advanced
),
210 } else if let Some(view
) = advanced
.downcast_mut
::<BtrfsBootdiskOptionsView
>() {
211 let (disks
, advanced
) = view
213 .ok_or("Failed to retrieve advanced bootdisk options")?
;
215 if let FsType
::Btrfs(level
) = fstype
{
216 check_btrfs_raid_config(level
, &disks
).map_err(|err
| format
!("{fstype}: {err}"))?
;
222 advanced
: AdvancedBootdiskOptions
::Btrfs(advanced
),
225 Err("Invalid bootdisk view state".to_owned())
230 impl ViewWrapper
for AdvancedBootdiskOptionsView
{
231 cursive
::wrap_impl
!(self.view
: LinearLayout
);
234 struct LvmBootdiskOptionsView
{
238 impl LvmBootdiskOptionsView
{
239 fn new(options
: &LvmBootdiskOptions
) -> Self {
240 let is_pve
= crate::setup_info().config
.product
== ProxmoxProduct
::PVE
;
241 // TODO: Set maximum accordingly to disk size
242 let view
= FormView
::new()
245 DiskSizeEditView
::new()
246 .content(options
.total_size
)
247 .max_value(options
.total_size
),
251 DiskSizeEditView
::new_emptyable().content_maybe(options
.swap_size
),
255 "Maximum root volume size",
256 DiskSizeEditView
::new_emptyable().content_maybe(options
.max_root_size
),
260 "Maximum data volume size",
261 DiskSizeEditView
::new_emptyable().content_maybe(options
.max_data_size
),
264 "Minimum free LVM space",
265 DiskSizeEditView
::new_emptyable().content_maybe(options
.min_lvm_free
),
271 fn get_values(&mut self) -> Option
<LvmBootdiskOptions
> {
272 let is_pve
= crate::setup_info().config
.product
== ProxmoxProduct
::PVE
;
273 let min_lvm_free_id
= if is_pve { 4 }
else { 2 }
;
274 let max_root_size
= if is_pve
{
275 self.view
.get_value
::<DiskSizeEditView
, _
>(2)
279 let max_data_size
= if is_pve
{
280 self.view
.get_value
::<DiskSizeEditView
, _
>(3)
284 Some(LvmBootdiskOptions
{
285 total_size
: self.view
.get_value
::<DiskSizeEditView
, _
>(0)?
,
286 swap_size
: self.view
.get_value
::<DiskSizeEditView
, _
>(1),
289 min_lvm_free
: self.view
.get_value
::<DiskSizeEditView
, _
>(min_lvm_free_id
),
294 impl ViewWrapper
for LvmBootdiskOptionsView
{
295 cursive
::wrap_impl
!(self.view
: FormView
);
298 struct MultiDiskOptionsView
<T
> {
300 phantom
: PhantomData
<T
>,
303 impl<T
: View
> MultiDiskOptionsView
<T
> {
304 fn new(avail_disks
: &[Disk
], selected_disks
: &[usize], options_view
: T
) -> Self {
305 let mut selectable_disks
= avail_disks
307 .map(|d
| (d
.to_string(), Some(d
.clone())))
308 .collect
::<Vec
<(String
, Option
<Disk
>)>>();
310 selectable_disks
.push(("-- do not use --".to_owned(), None
));
312 let mut disk_form
= FormView
::new();
313 for (i
, _
) in avail_disks
.iter().enumerate() {
315 &format
!("Harddisk {i}"),
318 .with_all(selectable_disks
.clone())
319 .selected(selected_disks
[i
]),
323 let mut disk_select_view
= LinearLayout
::vertical()
324 .child(TextView
::new("Disk setup").center())
326 .child(ScrollView
::new(disk_form
.with_name("multidisk-disk-form")));
328 if avail_disks
.len() > 3 {
329 let do_not_use_index
= selectable_disks
.len() - 1;
330 let deselect_all_button
= Button
::new("Deselect all", move |siv
| {
331 siv
.call_on_name("multidisk-disk-form", |view
: &mut FormView
| {
332 view
.call_on_childs(&|v
: &mut SelectView
<Option
<Disk
>>| {
333 // As there is no .on_select() callback defined on the
334 // SelectView's, the returned callback here can be safely
336 v
.set_selection(do_not_use_index
);
341 disk_select_view
.add_child(PaddedView
::lrtb(
346 LinearLayout
::horizontal()
347 .child(DummyView
.full_width())
348 .child(deselect_all_button
),
352 let options_view
= LinearLayout
::vertical()
353 .child(TextView
::new("Advanced options").center())
355 .child(options_view
);
357 let view
= LinearLayout
::horizontal()
358 .child(disk_select_view
)
359 .child(DummyView
.fixed_width(3))
360 .child(options_view
);
363 view
: LinearLayout
::vertical().child(view
),
364 phantom
: PhantomData
,
368 fn top_panel(mut self, view
: impl View
) -> Self {
369 if self.has_top_panel() {
370 self.view
.remove_child(0);
373 self.view
.insert_child(0, Panel
::new(view
));
378 /// This function returns a tuple of vectors. The first vector contains the currently selected
379 /// disks in order of their selection slot. Empty slots are filtered out. The second vector
380 /// contains indices of each slot's selection, which enables us to restore the selection even
383 fn get_disks_and_selection(&mut self) -> Option
<(Vec
<Disk
>, Vec
<usize>)> {
384 let mut disks
= vec
![];
385 let view_top_index
= usize::from(self.has_top_panel());
389 .get_child_mut(view_top_index
)?
390 .downcast_mut
::<LinearLayout
>()?
392 .downcast_mut
::<LinearLayout
>()?
394 .downcast_mut
::<ScrollView
<NamedView
<FormView
>>>()?
398 let mut selected_disks
= Vec
::new();
400 for i
in 0..disk_form
.len() {
401 let disk
= disk_form
.get_value
::<SelectView
<Option
<Disk
>>, _
>(i
)?
;
403 // `None` means no disk was selected for this slot
404 if let Some(disk
) = disk
{
410 .get_child
::<SelectView
<Option
<Disk
>>>(i
)?
415 Some((disks
, selected_disks
))
418 fn inner_mut(&mut self) -> Option
<&mut T
> {
419 let view_top_index
= usize::from(self.has_top_panel());
422 .get_child_mut(view_top_index
)?
423 .downcast_mut
::<LinearLayout
>()?
425 .downcast_mut
::<LinearLayout
>()?
430 fn has_top_panel(&self) -> bool
{
431 // The root view should only ever have one or two children
432 assert
!([1, 2].contains(&self.view
.len()));
438 impl<T
: '
static> ViewWrapper
for MultiDiskOptionsView
<T
> {
439 cursive
::wrap_impl
!(self.view
: LinearLayout
);
442 struct BtrfsBootdiskOptionsView
{
443 view
: MultiDiskOptionsView
<FormView
>,
446 impl BtrfsBootdiskOptionsView
{
447 fn new(disks
: &[Disk
], options
: &BtrfsBootdiskOptions
) -> Self {
448 let view
= MultiDiskOptionsView
::new(
450 &options
.selected_disks
,
451 FormView
::new().child("hdsize", DiskSizeEditView
::new().content(options
.disk_size
)),
453 .top_panel(TextView
::new("Btrfs integration is a technology preview!").center());
458 fn get_values(&mut self) -> Option
<(Vec
<Disk
>, BtrfsBootdiskOptions
)> {
459 let (disks
, selected_disks
) = self.view
.get_disks_and_selection()?
;
460 let disk_size
= self.view
.inner_mut()?
.get_value
::<DiskSizeEditView
, _
>(0)?
;
464 BtrfsBootdiskOptions
{
472 impl ViewWrapper
for BtrfsBootdiskOptionsView
{
473 cursive
::wrap_impl
!(self.view
: MultiDiskOptionsView
<FormView
>);
476 struct ZfsBootdiskOptionsView
{
477 view
: MultiDiskOptionsView
<FormView
>,
480 impl ZfsBootdiskOptionsView
{
481 // TODO: Re-apply previous disk selection from `options` correctly
482 fn new(disks
: &[Disk
], options
: &ZfsBootdiskOptions
) -> Self {
483 let inner
= FormView
::new()
484 .child("ashift", IntegerEditView
::new().content(options
.ashift
))
489 .with_all(ZFS_COMPRESS_OPTIONS
.iter().map(|o
| (o
.to_string(), *o
)))
493 .position(|o
| *o
== options
.compress
)
494 .unwrap_or_default(),
501 .with_all(ZFS_CHECKSUM_OPTIONS
.iter().map(|o
| (o
.to_string(), *o
)))
505 .position(|o
| *o
== options
.checksum
)
506 .unwrap_or_default(),
509 .child("copies", IntegerEditView
::new().content(options
.copies
))
510 .child("hdsize", DiskSizeEditView
::new().content(options
.disk_size
));
512 let view
= MultiDiskOptionsView
::new(disks
, &options
.selected_disks
, inner
)
513 .top_panel(TextView
::new(
514 "ZFS is not compatible with hardware RAID controllers, for details see the documentation."
520 fn get_values(&mut self) -> Option
<(Vec
<Disk
>, ZfsBootdiskOptions
)> {
521 let (disks
, selected_disks
) = self.view
.get_disks_and_selection()?
;
522 let view
= self.view
.inner_mut()?
;
524 let ashift
= view
.get_value
::<IntegerEditView
, _
>(0)?
;
525 let compress
= view
.get_value
::<SelectView
<_
>, _
>(1)?
;
526 let checksum
= view
.get_value
::<SelectView
<_
>, _
>(2)?
;
527 let copies
= view
.get_value
::<IntegerEditView
, _
>(3)?
;
528 let disk_size
= view
.get_value
::<DiskSizeEditView
, _
>(4)?
;
544 impl ViewWrapper
for ZfsBootdiskOptionsView
{
545 cursive
::wrap_impl
!(self.view
: MultiDiskOptionsView
<FormView
>);
548 fn advanced_options_view(disks
: &[Disk
], options
: Rc
<RefCell
<BootdiskOptions
>>) -> impl View
{
549 Dialog
::around(AdvancedBootdiskOptionsView
::new(
551 &(*options
).borrow(),
553 .title("Advanced bootdisk options")
555 let options_ref
= options
.clone();
558 .user_data
::<InstallerState
>()
564 .call_on_name("advanced-bootdisk-options-dialog", |view
: &mut Dialog
| {
565 view
.get_content_mut()
566 .downcast_mut
::<AdvancedBootdiskOptionsView
>()
567 .map(|v
| v
.get_values(&runinfo
))
571 let options
= match options
{
572 Some(Ok(options
)) => options
,
574 siv
.add_layer(Dialog
::info(err
));
578 siv
.add_layer(Dialog
::info("Failed to retrieve bootdisk options view"));
583 if let Err(duplicate
) = check_for_duplicate_disks(&options
.disks
) {
584 siv
.add_layer(Dialog
::info(format
!(
585 "Cannot select same disk twice: {duplicate}"
591 *(*options_ref
).borrow_mut() = options
;
594 .with_name("advanced-bootdisk-options-dialog")
598 /// Checks a list of disks for duplicate entries, using their index as key.
602 /// * `disks` - A list of disks to check for duplicates.
603 fn check_for_duplicate_disks(disks
: &[Disk
]) -> Result
<(), &Disk
> {
604 let mut set
= HashSet
::new();
607 if !set
.insert(&disk
.index
) {
615 /// Simple wrapper which returns an descriptive error if the list of disks is too short.
619 /// * `disks` - A list of disks to check the lenght of.
620 /// * `min` - Minimum number of disks
621 fn check_raid_min_disks(disks
: &[Disk
], min
: usize) -> Result
<(), String
> {
622 if disks
.len() < min
{
623 Err(format
!("Need at least {min} disks"))
629 /// Checks whether a user-supplied ZFS RAID setup is valid or not, such as disk sizes, minimum
630 /// number of disks and legacy BIOS compatibility.
634 /// * `runinfo` - `RuntimeInfo` instance of currently running system
635 /// * `level` - The targeted ZFS RAID level by the user.
636 /// * `disks` - List of disks designated as RAID targets.
637 fn check_zfs_raid_config(
638 runinfo
: &RuntimeInfo
,
641 ) -> Result
<(), String
> {
642 // See also Proxmox/Install.pm:get_zfs_raid_setup()
645 if runinfo
.boot_type
!= BootType
::Efi
646 && disk
.block_size
.map(|v
| v
== 4096).unwrap_or_default()
648 return Err("Booting from 4Kn drive in legacy BIOS mode is not supported.".to_owned());
652 let check_mirror_size
= |disk1
: &Disk
, disk2
: &Disk
| {
653 if (disk1
.size
- disk2
.size
).abs() > disk1
.size
/ 10. {
655 "Mirrored disks must have same size:\n\n * {disk1}\n * {disk2}"
663 ZfsRaidLevel
::Raid0
=> check_raid_min_disks(disks
, 1)?
,
664 ZfsRaidLevel
::Raid1
=> {
665 check_raid_min_disks(disks
, 2)?
;
667 check_mirror_size(&disks
[0], disk
)?
;
670 ZfsRaidLevel
::Raid10
=> {
671 check_raid_min_disks(disks
, 4)?
;
672 // Pairs need to have the same size
673 for i
in (0..disks
.len()).step_by(2) {
674 check_mirror_size(&disks
[i
], &disks
[i
+ 1])?
;
677 // For RAID-Z: minimum disks number is level + 2
678 ZfsRaidLevel
::RaidZ
=> {
679 check_raid_min_disks(disks
, 3)?
;
681 check_mirror_size(&disks
[0], disk
)?
;
684 ZfsRaidLevel
::RaidZ2
=> {
685 check_raid_min_disks(disks
, 4)?
;
687 check_mirror_size(&disks
[0], disk
)?
;
690 ZfsRaidLevel
::RaidZ3
=> {
691 check_raid_min_disks(disks
, 5)?
;
693 check_mirror_size(&disks
[0], disk
)?
;
701 /// Checks whether a user-supplied Btrfs RAID setup is valid or not, such as minimum
706 /// * `level` - The targeted Btrfs RAID level by the user.
707 /// * `disks` - List of disks designated as RAID targets.
708 fn check_btrfs_raid_config(level
: BtrfsRaidLevel
, disks
: &[Disk
]) -> Result
<(), String
> {
709 // See also Proxmox/Install.pm:get_btrfs_raid_setup()
712 BtrfsRaidLevel
::Raid0
=> check_raid_min_disks(disks
, 1)?
,
713 BtrfsRaidLevel
::Raid1
=> check_raid_min_disks(disks
, 2)?
,
714 BtrfsRaidLevel
::Raid10
=> check_raid_min_disks(disks
, 4)?
,
722 use std
::collections
::HashMap
;
725 use crate::setup
::{Dns, NetworkInfo}
;
727 fn dummy_disk(index
: usize) -> Disk
{
729 index
: index
.to_string(),
730 path
: format
!("/dev/dummy{index}"),
731 model
: Some("Dummy disk".to_owned()),
732 size
: 1024. * 1024. * 1024. * 8.,
733 block_size
: Some(512),
737 fn dummy_disks(num
: usize) -> Vec
<Disk
> {
738 (0..num
).map(dummy_disk
).collect()
741 fn dummy_runinfo(boot_type
: BootType
) -> RuntimeInfo
{
744 country
: Some("at".to_owned()),
745 disks
: dummy_disks(4),
746 network
: NetworkInfo
{
752 interfaces
: HashMap
::new(),
754 total_memory
: 1024 * 1024 * 1024 * 64,
760 fn duplicate_disks() {
761 assert
!(check_for_duplicate_disks(&dummy_disks(2)).is_ok());
763 check_for_duplicate_disks(&[
775 fn raid_min_disks() {
776 let disks
= dummy_disks(10);
778 assert
!(check_raid_min_disks(&disks
[..1], 2).is_err());
779 assert
!(check_raid_min_disks(&disks
[..1], 1).is_ok());
780 assert
!(check_raid_min_disks(&disks
, 1).is_ok());
785 let disks
= dummy_disks(10);
787 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid0
, &[]).is_err());
788 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid0
, &disks
[..1]).is_ok());
789 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid0
, &disks
).is_ok());
791 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &[]).is_err());
792 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &disks
[..1]).is_err());
793 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &disks
[..2]).is_ok());
794 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &disks
).is_ok());
796 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &[]).is_err());
797 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &disks
[..3]).is_err());
798 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &disks
[..4]).is_ok());
799 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &disks
).is_ok());
804 let runinfo
= dummy_runinfo(BootType
::Bios
);
806 let mut disks
= dummy_disks(10);
807 zfs_common_tests(&disks
, &runinfo
);
809 for disk
in &mut disks
{
810 disk
.block_size
= None
;
812 // Should behave the same as if an explicit block size of 512 was set
813 zfs_common_tests(&disks
, &runinfo
);
816 let mut disks
= dummy_disks(10);
817 disks
[i
].block_size
= Some(4096);
819 // Must fail if /any/ of the disks are 4Kn
820 assert
!(check_zfs_raid_config(&runinfo
, ZfsRaidLevel
::Raid0
, &disks
).is_err());
821 assert
!(check_zfs_raid_config(&runinfo
, ZfsRaidLevel
::Raid1
, &disks
).is_err());
822 assert
!(check_zfs_raid_config(&runinfo
, ZfsRaidLevel
::Raid10
, &disks
).is_err());
823 assert
!(check_zfs_raid_config(&runinfo
, ZfsRaidLevel
::RaidZ
, &disks
).is_err());
824 assert
!(check_zfs_raid_config(&runinfo
, ZfsRaidLevel
::RaidZ2
, &disks
).is_err());
825 assert
!(check_zfs_raid_config(&runinfo
, ZfsRaidLevel
::RaidZ3
, &disks
).is_err());
831 let disks
= dummy_disks(10);
832 let runinfo
= dummy_runinfo(BootType
::Efi
);
834 zfs_common_tests(&disks
, &runinfo
);
837 fn zfs_common_tests(disks
: &[Disk
], runinfo
: &RuntimeInfo
) {
838 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid0
, &[]).is_err());
839 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid0
, &disks
[..1]).is_ok());
840 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid0
, disks
).is_ok());
842 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid1
, &[]).is_err());
843 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid1
, &disks
[..2]).is_ok());
844 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid1
, disks
).is_ok());
846 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid10
, &[]).is_err());
847 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid10
, &dummy_disks(4)).is_ok());
848 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::Raid10
, disks
).is_ok());
850 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ
, &[]).is_err());
851 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ
, &disks
[..2]).is_err());
852 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ
, &disks
[..3]).is_ok());
853 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ
, disks
).is_ok());
855 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ2
, &[]).is_err());
856 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ2
, &disks
[..3]).is_err());
857 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ2
, &disks
[..4]).is_ok());
858 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ2
, disks
).is_ok());
860 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ3
, &[]).is_err());
861 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ3
, &disks
[..4]).is_err());
862 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ3
, &disks
[..5]).is_ok());
863 assert
!(check_zfs_raid_config(runinfo
, ZfsRaidLevel
::RaidZ3
, disks
).is_ok());