X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=proxinstall;h=79abc34808cd3db0ea3441d5a9a80c3ce90fe685;hb=9fda294e9b349c14f67848b52379fe1bae22f06f;hp=bd5e5dba548243bd8c5d401a9f89bd269364bf24;hpb=f9b3baffc11994824ec3b6b100eb822705e9e680;p=pve-installer.git diff --git a/proxinstall b/proxinstall index bd5e5db..79abc34 100755 --- a/proxinstall +++ b/proxinstall @@ -900,8 +900,8 @@ sub zfs_create_rpool { syscmd("zfs create $zfspoolname/ROOT/$zfsrootvolname") == 0 || die "unable to create zfs $zfspoolname/ROOT/$zfsrootvolname volume\n"; - # disable atime during install - syscmd("zfs set atime=off $zfspoolname") == 0 || + # default to `relatime` on, fast enough for the installer and production + syscmd("zfs set atime=on relatime=on $zfspoolname") == 0 || die "unable to set zfs properties\n"; my $value = $config_options->{compress}; @@ -965,7 +965,19 @@ sub partition_bootable_disk { } my $hdgb = int($hdsize/(1024*1024)); - die "hardisk '$target_dev' too small (${hdgb}GB)\n" if $hdgb < 8; + + my ($hard_limit, $soft_limit) = (2, 8); + + die "root disk '$target_dev' too small (${hdgb} GB < $hard_limit GB)\n" if $hdgb < $hard_limit; + if ($hdgb < $soft_limit) { + my $response = display_prompt( + "Root disk space ${hdgb} GB is below recommended minimum space of $soft_limit GB," + ." installation might not be successful! Continue?" + ); + die "root disk '$target_dev' too small (${hdgb} GB < $soft_limit GB), and warning not accepted.\n" + if $response ne 'ok'; + } + syscmd("sgdisk -Z ${target_dev}"); @@ -1057,9 +1069,7 @@ sub ask_existing_vg_rename_or_abort { } $message .= "or cancel the installation?"; - my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'question', 'ok-cancel', $message); - my $response = $dialog->run(); - $dialog->destroy(); + my $response = display_prompt($message); if ($response eq 'ok') { for my $vg_uuid (keys %$duplicate_vgs) { @@ -1094,45 +1104,60 @@ sub create_lvm_volumes { syscmd("/sbin/vgcreate $vgname $lvmdev") == 0 || die "unable to create volume group '$vgname'\n"; - my $hdgb = int($os_size/(1024*1024)); - my $space = (($hdgb > 128) ? 16 : ($hdgb/8))*1024*1024; + my $hdgb = int($os_size / (1024 * 1024)); + + # always leave some space at the end to avoid roudning issues with LVM's physical extent (PE) + # size of 4 MB. + my $space = $hdgb <= 32 ? 4 * 1024 : (($hdgb > 128 ? 16 : $hdgb / 8) * 1024 * 1024); my $rootsize; - my $datasize; + my $datasize = 0; if ($setup->{product} eq 'pve') { - my $maxroot; + my $maxroot_mb; if ($config_options->{maxroot}) { - $maxroot = $config_options->{maxroot}; + $maxroot_mb = $config_options->{maxroot} * 1024; } else { - $maxroot = 96; + $maxroot_mb = 96 * 1024; } - $rootsize = (($hdgb > ($maxroot*4)) ? $maxroot : $hdgb/4)*1024*1024; - - my $rest = $os_size - $swap_size - $rootsize; # in KB + my $rest = $os_size - $swap_size; + my $rest_mb = int($rest / 1024); - my $minfree; - if (defined($config_options->{minfree})) { - $minfree = (($config_options->{minfree}*1024*1024) >= $rest ) ? $space : - $config_options->{minfree}*1024*1024 ; + my $rootsize_mb; + if ($rest_mb < 12 * 1024) { + # no point in wasting space, try to get us actually installed and align down to 4 MB + $rootsize_mb = ($rest_mb - 0.1) & ~3; + } elsif ($rest_mb < 48 * 1024) { + my $masked = int($rest_mb / 2) & ~3; # align down to 4 MB + $rootsize_mb = $masked; } else { - $minfree = $space; + $rootsize_mb = $rest_mb / 4 + 12 * 1024; + } + + $rootsize_mb = $maxroot_mb if $rootsize_mb > $maxroot_mb; + $rootsize = int($rootsize_mb * 1024); + + $rest -= $rootsize; # in KB + + my $minfree = $space; + if (defined(my $cfg_minfree = $config_options->{minfree})) { + $minfree = $cfg_minfree * 1024 * 1024 >= $rest ? $space : $cfg_minfree * 1024 * 1024; } - $rest = $rest - $minfree; + $rest = int($rest - $minfree) & ~0xFFF; # align down to 4 MB boundaries - if (defined($config_options->{maxvz})) { - $rest = (($config_options->{maxvz}*1024*1024) <= $rest) ? - $config_options->{maxvz}*1024*1024 : $rest; + if (defined(my $maxvz = $config_options->{maxvz})) { + $rest = $maxvz * 1024 * 1024 <= $rest ? $maxvz * 1024 * 1024 : $rest; } $datasize = $rest; } else { my $minfree = defined($config_options->{minfree}) ? $config_options->{minfree}*1024*1024 : $space; - $rootsize = $os_size - $minfree - $swap_size; # in KB + $rootsize = int($os_size - $minfree - $swap_size); # in KB + $rootsize &= ~0xFFF; # align down to 4 MB boundaries } if ($swap_size) { @@ -1145,16 +1170,16 @@ sub create_lvm_volumes { syscmd("/sbin/lvcreate -Wy --yes -L${rootsize}K -nroot $vgname") == 0 || die "unable to create root volume\n"; - if ($datasize > 4*1024*1024) { + if ($datasize > 4 * 1024 * 1024) { my $metadatasize = $datasize/100; # default 1% of data $metadatasize = 1024*1024 if $metadatasize < 1024*1024; # but at least 1G $metadatasize = 16*1024*1024 if $metadatasize > 16*1024*1024; # but at most 16G # otherwise the metadata is taken out of $minfree - $datasize -= 2*$metadatasize; + $datasize -= 2 * $metadatasize; # 1 4MB PE to allow for rounding - $datasize -= 4*1024; + $datasize -= 4 * 1024; syscmd("/sbin/lvcreate -Wy --yes -L${datasize}K -ndata $vgname") == 0 || die "unable to create data volume\n"; @@ -1162,6 +1187,9 @@ sub create_lvm_volumes { syscmd("/sbin/lvconvert --yes --type thin-pool --poolmetadatasize ${metadatasize}K $vgname/data") == 0 || die "unable to create data thin-pool\n"; } else { + if ($setup->{product} eq 'pve' && !defined($config_options->{maxvz})) { + display_message("Skipping auto-creation of LVM thinpool for guest data due to low space."); + } $datadev = undef; } @@ -1176,18 +1204,21 @@ sub compute_swapsize { my $hdgb = int($hdsize/(1024*1024)); - my $swapsize; + my $swapsize_kb; if (defined($config_options->{swapsize})) { - $swapsize = $config_options->{swapsize}*1024*1024; + $swapsize_kb = $config_options->{swapsize} * 1024 * 1024; } else { - my $ss = int ($total_memory / 1024); - $ss = 4 if $ss < 4; - $ss = ($hdgb/8) if $ss > ($hdgb/8); - $ss = 8 if $ss > 8; - $swapsize = $ss*1024*1024; + my $ss = int($total_memory); + $ss = 4096 if $ss < 4096 && $hdgb >= 64; + $ss = 2048 if $ss < 2048 && $hdgb >= 32; + $ss = 1024 if $ss >= 2048 && $hdgb <= 16; + $ss = 512 if $ss < 512; + $ss = int($hdgb * 128) if $ss > $hdgb * 128; + $ss = 8192 if $ss > 8192; + $swapsize_kb = int($ss * 1024) & ~0xFFF; # align to 4 MB to avoid all to odd SWAP size } - return $swapsize; + return $swapsize_kb; } my sub chroot_chown { @@ -1341,7 +1372,7 @@ sub extract_data { my $logical_bsize = @$hd[4]; my ($size, $osdev, $efidev) = - partition_bootable_disk($devname, undef, '8300'); + partition_bootable_disk($devname, $config_options->{hdsize}, '8300'); $rootdev = $osdev if !defined($rootdev); # simply point to first disk my $by_id = find_stable_path("/dev/disk/by-id", $devname); push @$bootdevinfo, { @@ -1380,8 +1411,6 @@ sub extract_data { my ($size, $osdev, $efidev) = partition_bootable_disk($devname, $config_options->{hdsize}, 'BF01'); - zfs_mirror_size_check($disksize, $size) if $disksize; - push @$bootdevinfo, { esp => $efidev, devname => $devname, @@ -1576,29 +1605,28 @@ sub extract_data { my $ntype = $ipversion == 4 ? 'inet' : 'inet6'; - my $ethdev = $ipconf->{ifaces}->{$ipconf->{selected}}; + my $ethdev = $ipconf->{ifaces}->{$ipconf->{selected}}->{name}; if ($setup->{bridged_network}) { - $ifaces .= "iface $ethdev->{name} $ntype manual\n"; + $ifaces .= "iface $ethdev $ntype manual\n"; $ifaces .= "\nauto vmbr0\niface vmbr0 $ntype static\n" . "\taddress $cidr\n" . "\tgateway $gateway\n" . - "\thwaddress $ethdev->{mac}\n" . - "\tbridge-ports $ethdev->{name}\n" . + "\tbridge-ports $ethdev\n" . "\tbridge-stp off\n" . "\tbridge-fd 0\n"; } else { - $ifaces .= "auto $ethdev->{name}\n" . - "iface $ethdev->{name} $ntype static\n" . + $ifaces .= "auto $ethdev\n" . + "iface $ethdev $ntype static\n" . "\taddress $cidr\n" . "\tgateway $gateway\n"; } foreach my $iface (sort keys %{$ipconf->{ifaces}}) { my $name = $ipconf->{ifaces}->{$iface}->{name}; - next if $name eq $ethdev->{name}; + next if $name eq $ethdev; $ifaces .= "\niface $name $ntype manual\n"; } @@ -1743,9 +1771,6 @@ _EOD # create /etc/aliases.db (/etc/aliases is shipped in the base squashfs) syscmd("chroot $targetdir /usr/bin/newaliases"); - # enable NTP (timedatectl set-ntp true does not work without DBUS) - syscmd("chroot $targetdir /bin/systemctl enable systemd-timesyncd.service"); - unlink "$targetdir/proxmox_install_mode"; # set timezone @@ -1790,7 +1815,7 @@ _EOD my $zfs_snippet = "GRUB_CMDLINE_LINUX=\"\$GRUB_CMDLINE_LINUX root=ZFS=$zfspoolname/ROOT/$zfsrootvolname boot=zfs\""; write_config($zfs_snippet, "$targetdir/etc/default/grub.d/zfs.cfg"); - write_config("root=ZFS=$zfspoolname/ROOT/$zfsrootvolname boot=zfs", "$targetdir/etc/kernel/cmdline"); + write_config("root=ZFS=$zfspoolname/ROOT/$zfsrootvolname boot=zfs\n", "$targetdir/etc/kernel/cmdline"); } @@ -1938,6 +1963,7 @@ _EOD syscmd("umount $targetdir/proc"); syscmd("umount $targetdir/sys/firmware/efi/efivars"); syscmd("umount $targetdir/sys"); + rmdir("$targetdir/mnt/hostrun"); if ($use_zfs) { syscmd("zfs umount -a") == 0 || @@ -1953,8 +1979,8 @@ _EOD syscmd("zfs set mountpoint=/ $zfspoolname/ROOT/$zfsrootvolname") == 0 || die "zfs set mountpoint failed\n"; - syscmd("zpool set bootfs=$zfspoolname/ROOT/$zfsrootvolname $zfspoolname") == 0 || - die "zfs set bootfs failed\n"; + syscmd("zpool set bootfs=$zfspoolname/ROOT/$zfsrootvolname $zfspoolname") == 0 || + die "zpool set bootfs failed\n"; syscmd("zpool export $zfspoolname"); } @@ -2282,8 +2308,7 @@ sub get_ip_config { sub display_message { my ($msg) = @_; - my $dialog = Gtk3::MessageDialog->new($window, 'modal', - 'info', 'ok', $msg); + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'info', 'ok', $msg); $dialog->run(); $dialog->destroy(); } @@ -2291,12 +2316,21 @@ sub display_message { sub display_error { my ($msg) = @_; - my $dialog = Gtk3::MessageDialog->new($window, 'modal', - 'error', 'ok', $msg); + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'error', 'ok', $msg); $dialog->run(); $dialog->destroy(); } +sub display_prompt { + my ($query) = @_; + + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'question', 'ok-cancel', $query); + my $response = $dialog->run(); + $dialog->destroy(); + + return $response; +} + my $ipconf_first_view = 1; sub create_ipconf_view { @@ -2555,16 +2589,16 @@ sub get_device_desc { my ($devname, $size, $model) = @_; if ($size && ($size > 0)) { - $size = int($size/2048); # size in MB, from 512B "sectors" + $size = int($size/2048); # size in MiB, from 512B "sectors" my $text = "$devname ("; if ($size >= 1024) { - $size = int($size/1024); # size in GB + $size = $size/1024; # size in GiB if ($size >= 1024) { - $size = int($size/1024); # size in GB - $text .= "${size}TiB"; + $size = $size/1024; # size in TiB + $text .= sprintf("%.2f", $size) . "TiB"; } else { - $text .= "${size}GiB"; + $text .= sprintf("%.2f", $size) . "GiB"; } } else { $text .= "${size}MiB"; @@ -2572,6 +2606,7 @@ sub get_device_desc { $text .= ", $model" if $model; $text .= ")"; + return $text; } else { return $devname; @@ -2954,7 +2989,59 @@ my $create_label_widget_grid = sub { return $grid; }; +# only relevant for raid with its multipl diskX to diskY mappings. +my $get_selected_hdsize = sub { + my $hdsize = shift; + return $hdsize if defined($hdsize); + + # compute the smallest disk size of the actually selected disks + my $hd_count = scalar(@$hds); + for (my $i = 0; $i < $hd_count; $i++) { + my $cur_hd = $config_options->{"disksel$i"} // next; + my $disksize = int(@$cur_hd[2] / (2 * 1024 * 1024.0)); # size in GB + $hdsize //= $disksize; + $hdsize = $disksize if $disksize < $hdsize; + } + + if (my $cfg_hdsize = $config_options->{hdsize}) { + # had the dialog open previously and set an even lower size than the disk selection allows + $hdsize = $cfg_hdsize if $cfg_hdsize < $hdsize; + } + return $hdsize // 0; # fall back to zero, e.g., if none is selected hdsize cannot be any size +}; + +my sub update_hdsize_adjustment { + my ($adjustment, $hdsize) = @_; + + $hdsize = $get_selected_hdsize->($hdsize); + # expect that lower = 0 and step increments = 1 still are valid + $adjustment->set_upper($hdsize + 1); + $adjustment->set_value($hdsize); +} + +my sub create_hdsize_adjustment { + my ($hdsize) = @_; + $hdsize = $get_selected_hdsize->($hdsize); + # params are: initial value, lower, upper, step increment, page increment, page size + return Gtk3::Adjustment->new($config_options->{hdsize} || $hdsize, 0, $hdsize+1, 1, 1, 1); +} + +my sub get_hdsize_spin_button { + my $hdsize = shift; + + my $hdsize_entry_buffer = Gtk3::EntryBuffer->new(undef, 1); + my $hdsize_size_adj = create_hdsize_adjustment($hdsize); + + my $spinbutton_hdsize = Gtk3::SpinButton->new($hdsize_size_adj, 1, 1); + $spinbutton_hdsize->set_buffer($hdsize_entry_buffer); + $spinbutton_hdsize->set_adjustment($hdsize_size_adj); + $spinbutton_hdsize->set_tooltip_text("only use specified size (GB) of the harddisk (rest left unpartitioned)"); + return $spinbutton_hdsize; +}; + my $create_raid_disk_grid = sub { + my ($hdsize_buttons) = @_; + my $hd_count = scalar(@$hds); my $disk_labeled_widgets = []; for (my $i = 0; $i < $hd_count; $i++) { @@ -2962,18 +3049,23 @@ my $create_raid_disk_grid = sub { $disk_selector->append_text("-- do not use --"); $disk_selector->set_active(0); $disk_selector->set_visible(1); + foreach my $hd (@$hds) { my ($disk, $devname, $size, $model, $logical_bsize) = @$hd; $disk_selector->append_text(get_device_desc ($devname, $size, $model)); - $disk_selector->{pve_disk_id} = $i; - $disk_selector->signal_connect (changed => sub { - my $w = shift; - my $diskid = $w->{pve_disk_id}; - my $a = $w->get_active - 1; - $config_options->{"disksel${diskid}"} = ($a >= 0) ? $hds->[$a] : undef; - }); } + $disk_selector->{pve_disk_id} = $i; + $disk_selector->signal_connect(changed => sub { + my $w = shift; + my $diskid = $w->{pve_disk_id}; + my $a = $w->get_active - 1; + $config_options->{"disksel${diskid}"} = ($a >= 0) ? $hds->[$a] : undef; + for my $btn (@$hdsize_buttons) { + update_hdsize_adjustment($btn->get_adjustment()); + } + }); + if ($hdoption_first_setup) { $disk_selector->set_active ($i+1) if $hds->[$i]; } else { @@ -3026,30 +3118,8 @@ my $create_raid_disk_grid = sub { return $vbox; }; -# shared between different ui parts (e.g., ZFS and "normal" single disk FS) -my $hdsize_size_adj; -my $hdsize_entry_buffer; - -my $get_hdsize_spinbtn = sub { - my $hdsize = shift; - - $hdsize_entry_buffer //= Gtk3::EntryBuffer->new(undef, 1); - - if (defined($hdsize)) { - $hdsize_size_adj = Gtk3::Adjustment->new($config_options->{hdsize} || $hdsize, 0, $hdsize+1, 1, 1, 1); - } else { - die "called get_hdsize_spinbtn with \$hdsize_size_adj not defined but did not pass hdsize!\n" - if !defined($hdsize_size_adj); - } - - my $spinbutton_hdsize = Gtk3::SpinButton->new($hdsize_size_adj, 1, 1); - $spinbutton_hdsize->set_buffer($hdsize_entry_buffer); - $spinbutton_hdsize->set_adjustment($hdsize_size_adj); - $spinbutton_hdsize->set_tooltip_text("only use specified size (GB) of the harddisk (rest left unpartitioned)"); - return $spinbutton_hdsize; -}; - my $create_raid_advanced_grid = sub { + my ($hdsize_btn) = @_; my $labeled_widgets = []; my $spinbutton_ashift = Gtk3::SpinButton->new_with_range(9, 13, 1); $spinbutton_ashift->set_tooltip_text("zpool ashift property (pool sector size, default 2^12)"); @@ -3064,8 +3134,7 @@ my $create_raid_advanced_grid = sub { my $combo_compress = Gtk3::ComboBoxText->new(); $combo_compress->set_tooltip_text("zfs compression algorithm for rpool dataset"); - # note: gzip / lze not allowed for bootfs vdevs - my $comp_opts = ["on","off","lzjb","lz4"]; + my $comp_opts = ["on","off","lzjb","lz4", "zle", "gzip", "zstd"]; foreach my $opt (@$comp_opts) { $combo_compress->append($opt, $opt); } @@ -3103,12 +3172,18 @@ my $create_raid_advanced_grid = sub { $spinbutton_copies->set_value($config_options->{copies}); push @$labeled_widgets, "copies", $spinbutton_copies; - push @$labeled_widgets, "hdsize", $get_hdsize_spinbtn->(); + push @$labeled_widgets, "hdsize", $hdsize_btn; return $create_label_widget_grid->($labeled_widgets);; }; -sub create_hdoption_view { +my $create_btrfs_raid_advanced_grid = sub { + my ($hdsize_btn) = @_; + my $labeled_widgets = []; + push @$labeled_widgets, "hdsize", $hdsize_btn; + return $create_label_widget_grid->($labeled_widgets);; +}; +sub create_hdoption_view { my $dialog = Gtk3::Dialog->new(); $dialog->set_title("Harddisk options"); @@ -3176,13 +3251,14 @@ sub create_hdoption_view { # size compute my $hdsize = 0; if ( -b $target_hd) { - $hdsize = int(hd_size ($target_hd) / (1024*1024.0)); # size in GB + $hdsize = int(hd_size ($target_hd) / (1024 * 1024.0)); # size in GB } elsif ($target_hd) { - $hdsize = int((-s $target_hd) / (1024*1024*1024.0)); + $hdsize = int((-s $target_hd) / (1024 * 1024 * 1024.0)); } - my $spinbutton_hdsize = $get_hdsize_spinbtn->($hdsize); - push @$hdsize_labeled_widgets, "hdsize", $spinbutton_hdsize; + my $spinbutton_hdsize_nonraid = get_hdsize_spin_button($hdsize); + push @$hdsize_labeled_widgets, "hdsize", $spinbutton_hdsize_nonraid; + my $spinbutton_hdsize = $spinbutton_hdsize_nonraid; my $entry_swapsize = Gtk3::Entry->new(); $entry_swapsize->set_tooltip_text("maximum SWAP size (GB)"); @@ -3213,13 +3289,17 @@ sub create_hdoption_view { push @$hdsize_labeled_widgets, "maxvz", $entry_maxvz; } + my $spinbutton_hdsize_zfs = get_hdsize_spin_button($hdsize); + my $spinbutton_hdsize_btrfs = get_hdsize_spin_button($hdsize); + my $hdsize_buttons = [ $spinbutton_hdsize_zfs, $spinbutton_hdsize_btrfs ]; my $options_stack = Gtk3::Stack->new(); $options_stack->set_visible(1); $options_stack->set_hexpand(1); $options_stack->set_vexpand(1); - $options_stack->add_titled(&$create_raid_disk_grid(), "raiddisk", "Disk Setup"); + $options_stack->add_titled(&$create_raid_disk_grid($hdsize_buttons), "raiddisk", "Disk Setup"); $options_stack->add_titled(&$create_label_widget_grid($hdsize_labeled_widgets), "hdsize", "Size Options"); - $options_stack->add_titled(&$create_raid_advanced_grid("zfs"), "raidzfsadvanced", "Advanced Options"); + $options_stack->add_titled(&$create_raid_advanced_grid($spinbutton_hdsize_zfs), "raidzfsadvanced", "Advanced Options"); + $options_stack->add_titled(&$create_btrfs_raid_advanced_grid($spinbutton_hdsize_btrfs), "raidbtrfsadvanced", "Advanced Options"); $options_stack->set_visible_child_name("raiddisk"); my $options_stack_switcher = Gtk3::StackSwitcher->new(); $options_stack_switcher->set_halign('center'); @@ -3247,14 +3327,22 @@ sub create_hdoption_view { $hw_raid_note->set_markup($msg); } $hw_raid_note->set_visible($raid); - $options_stack_switcher->set_visible($is_zfs); + $options_stack_switcher->set_visible($raid); $options_stack->get_child_by_name("raidzfsadvanced")->set_visible($is_zfs); + $options_stack->get_child_by_name("raidbtrfsadvanced")->set_visible(!$is_zfs); if ($raid) { $target_hd_label->set_text("Target: $config_options->{filesys} "); $options_stack->set_visible_child_name("raiddisk"); } else { $target_hd_label->set_text("Target Harddisk: "); } + + if ($raid) { + $spinbutton_hdsize = $is_zfs ? $spinbutton_hdsize_zfs : $spinbutton_hdsize_btrfs; + } else { + $spinbutton_hdsize = $spinbutton_hdsize_nonraid; + } + my (undef, $pref_width) = $dialog->get_preferred_width(); my (undef, $pref_height) = $dialog->get_preferred_height(); $pref_height = 750 if $pref_height > 750; @@ -3464,7 +3552,7 @@ sub create_hdsel_view { foreach my $hd (@$hds) { ($disk, $devname, $size, $model, $logical_bsize) = @$hd; - $target_hd_combo->append_text (get_device_desc($devname, $size, $model)); + $target_hd_combo->append_text(get_device_desc($devname, $size, $model)); } my $raid = $config_options->{filesys} =~ m/zfs|btrfs/;