]> git.proxmox.com Git - pve-installer.git/blobdiff - proxinstall
merge installer into single package
[pve-installer.git] / proxinstall
index dd06727b9bfd0934a2cb2a218f3300a6614901ff..7bd4892adf5f0821d47b878ab82c324eeeefe0b8 100755 (executable)
@@ -21,41 +21,26 @@ use Data::Dumper;
 use File::Basename;
 use File::Path;
 use Time::HiRes;
+use POSIX ":sys_wait_h";
 
 use ProxmoxInstallerSetup;
 
-my $setup = ProxmoxInstallerSetup::setup();
-
-my $opt_testmode;
-
 if (!$ENV{G_SLICE} ||  $ENV{G_SLICE} ne "always-malloc") {
     die "do not use slice allocator (run with 'G_SLICE=always-malloc ./proxinstall ...')\n";
 }
 
+my $opt_testmode;
 if (!GetOptions('testmode=s' => \$opt_testmode)) {
     die "usage error\n";
     exit (-1);
 }
 
+my ($setup, $cd_info) = ProxmoxInstallerSetup::setup();
+
 my $zfstestpool = "test_rpool";
 my $zfspoolname = $opt_testmode ? $zfstestpool : 'rpool';
 my $zfsrootvolname = "$setup->{product}-1";
 
-my $product_cfg = {
-    pve => {
-       fullname => 'Proxmox VE',
-       port => '8006',
-    },
-    pmg => {
-       fullname => 'Proxmox Mail Gateway',
-       port => '8006',
-    },
-    pbs => {
-       fullname => 'Proxmox Backup Server',
-       port => '8007',
-    },
-};
-
 my $storage_cfg_zfs = <<__EOD__;
 dir: local
        path /var/lib/vz
@@ -108,8 +93,10 @@ sub file_read_firstline {
 
 my $logfd = IO::File->new(">/tmp/install.log");
 
-my $proxmox_libdir = $opt_testmode ?
-    Cwd::cwd() . "/testdir/var/lib/pve-installer" : "/var/lib/pve-installer";
+my $proxmox_libdir = $opt_testmode
+    ? Cwd::cwd() . "/testdir/var/lib/proxmox-installer"
+    : "/var/lib/proxmox-installer"
+    ;
 my $proxmox_cddir = $opt_testmode ? "../pve-cd-builder/tmp/data-gz/" : "/cdrom";
 my $proxmox_pkgdir = "${proxmox_cddir}/proxmox/packages/";
 
@@ -484,6 +471,23 @@ sub run_command {
     return $ostream;
 }
 
+# forks and runs the provided coderef in the child
+# do not use syscmd or run_command as both confuse the GTK mainloop if
+# run from a child process
+sub run_in_background {
+    my ($cmd) = @_;
+
+    my $pid = fork() // die "fork failed: $!\n";
+    if (!$pid) {
+       eval { $cmd->(); };
+       if (my $err = $@) {
+           warn "run_in_background error: $err\n";
+           POSIX::_exit(1);
+       }
+       POSIX::_exit(0);
+    }
+}
+
 sub detect_country {
 
     print "trying to detect country...\n";
@@ -1206,11 +1210,11 @@ my sub chroot_chmod {
        die "chroot: unable to change permission mode for '$path'\n";
 }
 
-sub prepare_systemd_boot_esp {
+sub prepare_proxmox_boot_esp {
     my ($espdev, $targetdir) = @_;
 
-    syscmd("chroot $targetdir pve-efiboot-tool init $espdev") == 0 ||
-       die "unable to init ESP and install systemd-boot loader on '$espdev'\n";
+    syscmd("chroot $targetdir proxmox-boot-tool init $espdev") == 0 ||
+       die "unable to init ESP and install proxmox-boot loader on '$espdev'\n";
 }
 
 sub prepare_grub_efi_boot_esp {
@@ -1344,20 +1348,21 @@ sub extract_data {
                $disksize = $size;
            }
 
-           &$udevadm_trigger_block();
+           $udevadm_trigger_block->();
 
            btrfs_create($btrfs_partitions, $btrfs_mode);
 
        } elsif ($use_zfs) {
 
-           my ($devlist, $bootdevlist, $vdev) = get_zfs_raid_setup();
+           my ($devlist, $vdev) = get_zfs_raid_setup();
 
            foreach my $hd (@$devlist) {
-               &$clean_disk(@$hd[1]);
+               $clean_disk->(@$hd[1]);
            }
 
+           # install esp/boot part on all, we can only win!
            my $disksize;
-           foreach my $hd (@$bootdevlist) {
+           for my $hd (@$devlist) {
                my $devname = @$hd[1];
                my $logical_bsize = @$hd[4];
 
@@ -1375,7 +1380,7 @@ sub extract_data {
                $disksize = $size;
            }
 
-           &$udevadm_trigger_block();
+           $udevadm_trigger_block->();
 
            foreach my $di (@$bootdevinfo) {
                my $devname = $di->{devname};
@@ -1802,19 +1807,19 @@ _EOD
 
                foreach my $di (@$bootdevinfo) {
                    my $dev = $di->{devname};
-                   if (!$native_4k_disk_bootable) {
-                       eval {
-                           syscmd("chroot $targetdir /usr/sbin/grub-install --target i386-pc --no-floppy --bootloader-id='proxmox' $dev") == 0 ||
-                                   die "unable to install the i386-pc boot loader on '$dev'\n";
-                       };
-                       push @$bootloader_err_list, $@ if $@;
-                   }
+                   if ($use_zfs) {
+                       prepare_proxmox_boot_esp($di->{esp}, $targetdir);
+                   } else {
+                       if (!$native_4k_disk_bootable) {
+                           eval {
+                               syscmd("chroot $targetdir /usr/sbin/grub-install --target i386-pc --no-floppy --bootloader-id='proxmox' $dev") == 0 ||
+                                       die "unable to install the i386-pc boot loader on '$dev'\n";
+                           };
+                           push @$bootloader_err_list, $@ if $@;
+                       }
 
                    eval {
                        if (my $esp = $di->{esp}) {
-                           if ($use_zfs) {
-                               prepare_systemd_boot_esp($esp, $targetdir);
-                           } else {
                                prepare_grub_efi_boot_esp($dev, $esp, $targetdir);
                            }
                        }
@@ -1973,14 +1978,18 @@ sub display_html {
 
     $filename = $steps[$step_number]->{html} if !$filename;
 
-    my $path = "${proxmox_libdir}/html/$filename";
-
-    my $url = "file://$path";
+    my $htmldir = "${proxmox_libdir}/html";
+    my $path;
+    if (-f "$htmldir/$setup->{product}/$filename") {
+       $path = "$htmldir/$setup->{product}/$filename";
+    } elsif (-f "$htmldir/common/$filename") {
+       $path = "$htmldir/common/$filename";
+    } else {
+       # FIXME: die now already?
+    }
 
     my $data = file_get_contents($path);
 
-    my $product = $product_cfg->{$setup->{product}};
-
     if ($filename eq 'license.htm') {
        my $license = eval { decode('utf8', file_get_contents("${proxmox_cddir}/EULA")) };
        if (my $err = $@) {
@@ -1993,16 +2002,18 @@ sub display_html {
     } elsif ($filename eq 'success.htm') {
        my $addr = $ipversion == 6 ? "[${ipaddress}]" : "$ipaddress";
        $data =~ s/__IPADDR__/$addr/g;
-       $data =~ s/__PORT__/$product->{port}/g;
+       $data =~ s/__PORT__/$setup->{port}/g;
 
        my $autoreboot_msg = $config_options->{autoreboot}
            ? "Automatic reboot scheduled in $autoreboot_seconds seconds."
            : '';
        $data =~ s/__AUTOREBOOT_MSG__/$autoreboot_msg/;
     }
-    $data =~ s/__FULL_PRODUCT_NAME__/$product->{fullname}/g;
+    $data =~ s/__FULL_PRODUCT_NAME__/$setup->{fullname}/g;
 
-    $htmlview->load_html($data, $url);
+    # HACK: always set base-path to common path, all resources are there.
+    # NOTE: we could also use an overlayfs with lower=common upper=$product & work=/run/$tmp
+    $htmlview->load_html($data,  "file://$htmldir/common/");
 
     $last_display_change = time();
 }
@@ -2491,8 +2502,8 @@ sub create_ack_view {
     });
     $vbox->pack_start($reboot_checkbox, 0, 0, 2);
 
-    my $ack_template = "${proxmox_libdir}/html/ack_template.htm";
-    my $ack_html = "${proxmox_libdir}/html/$steps[$step_number]->{html}";
+    my $ack_template = "${proxmox_libdir}/html/common/ack_template.htm";
+    my $ack_html = "${proxmox_libdir}/html/$setup->{product}/$steps[$step_number]->{html}";
     my $html_data = file_get_contents($ack_template);
 
     my %config_values = (
@@ -2536,9 +2547,14 @@ sub get_device_desc {
        my $text = "$devname (";
        if ($size >= 1024) {
            $size = int($size/1024); # size in GB
-           $text .= "${size}GB";
+           if ($size >= 1024) {
+               $size = int($size/1024); # size in GB
+               $text .= "${size}TiB";
+           } else {
+               $text .= "${size}GiB";
+           }
        } else {
-           $text .= "${size}MB";
+           $text .= "${size}MiB";
        }
 
        $text .= ", $model" if $model;
@@ -2549,6 +2565,8 @@ sub get_device_desc {
     }
 }
 
+my $last_layout;
+my $country_layout;
 sub update_layout {
     my ($cb, $kmap) = @_;
 
@@ -2562,7 +2580,14 @@ sub update_layout {
        $i++;
     }
 
-    $cb->set_active($ind || $def || 0);
+    my $val = $ind || $def || 0;
+
+    if (!defined($kmap)) {
+       $last_layout //= $val;
+    } elsif (!defined($country_layout) || $country_layout != $val) {
+       $last_layout = $country_layout = $val;
+    }
+    $cb->set_active($last_layout);
 }
 
 my $lastzonecb;
@@ -2639,7 +2664,7 @@ sub create_password_view {
     $hbox2->pack_start($pwe2, 0, 0, 0);
 
     my $hbox3 = Gtk3::HBox->new(0, 0);
-    $label = Gtk3::Label->new("E-Mail");
+    $label = Gtk3::Label->new("Email");
     $label->set_size_request(150, -1);
     $label->set_alignment(1, 0.5);
     $hbox3->pack_start($label, 0, 0, 10);
@@ -2676,14 +2701,14 @@ sub create_password_view {
 
        my $t3 = $eme->get_text;
        if ($t3 !~ m/^[\w\+\-\~]+(\.[\w\+\-\~]+)*@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*$/) {
-           display_message("E-Mail does not look like a valid address" .
+           display_message("Email does not look like a valid address" .
                             " (user\@domain.tld)");
            $eme->grab_focus();
            return;
        }
 
        if ($t3 eq 'mail@example.invalid') {
-           display_message("Please enter a valid E-Mail address");
+           display_message("Please enter a valid Email address");
            $eme->grab_focus();
            return;
        }
@@ -2699,6 +2724,7 @@ sub create_password_view {
 
 }
 
+my $installer_kmap;
 sub create_country_view {
 
     cleanup_view();
@@ -2744,21 +2770,30 @@ sub create_country_view {
 
     $kmapcb->signal_connect ('changed' => sub {
        my $sel = $kmapcb->get_active_text();
+       $last_layout = $kmapcb->get_active();
        if (my $kmap = $cmap->{kmaphash}->{$sel}) {
            my $xkmap = $cmap->{kmap}->{$kmap}->{x11};
            my $xvar = $cmap->{kmap}->{$kmap}->{x11var};
            $keymap = $kmap;
 
+           return if (defined($installer_kmap) && $installer_kmap eq $kmap);
+
+           $installer_kmap = $keymap;
+
            if (! $opt_testmode) {
                syscmd ("setxkbmap $xkmap $xvar");
+
                my $kbd_config = qq{
                    XKBLAYOUT="$xkmap"
                    XKBVARIANT="$xvar"
                    BACKSPACE="guess"
                };
                $kbd_config =~ s/^\s+//gm;
-               write_config($kbd_config, '/etc/default/keyboard');
-               syscmd ("setupcon");
+
+               run_in_background( sub {
+                   write_config($kbd_config, '/etc/default/keyboard');
+                   system("setupcon");
+               });
            }
        }
     });
@@ -2878,8 +2913,8 @@ my $create_basic_grid = sub {
     $grid->set_row_spacing(10);
     $grid->set_hexpand(1);
 
-    $grid->set_margin_start(5);
-    $grid->set_margin_end(5);
+    $grid->set_margin_start(10);
+    $grid->set_margin_end(20);
     $grid->set_margin_top(5);
     $grid->set_margin_bottom(5);
 
@@ -2907,8 +2942,9 @@ my $create_label_widget_grid = sub {
 };
 
 my $create_raid_disk_grid = sub {
+    my $hd_count = scalar(@$hds);
     my $disk_labeled_widgets = [];
-    for (my $i = 0; $i < @$hds; $i++) {
+    for (my $i = 0; $i < $hd_count; $i++) {
        my $disk_selector = Gtk3::ComboBoxText->new();
        $disk_selector->append_text("-- do not use --");
        $disk_selector->set_active(0);
@@ -2943,14 +2979,38 @@ my $create_raid_disk_grid = sub {
        push @$disk_labeled_widgets, "Harddisk $i", $disk_selector;
     }
 
+    my $clear_all_button = Gtk3::Button->new('_Deselect All');
+    if ($hd_count > 3) {
+       $clear_all_button->signal_connect('clicked', sub {
+           my $is_widget = 0;
+           for my $disk_selector (@$disk_labeled_widgets) {
+               $disk_selector->set_active(0) if $is_widget;
+               $is_widget ^= 1;
+           }
+       });
+       $clear_all_button->set_visible(1);
+    }
+
     my $scrolled_window = Gtk3::ScrolledWindow->new();
     $scrolled_window->set_hexpand(1);
-    $scrolled_window->set_propagate_natural_height(1) if @$hds > 4;
-    $scrolled_window->add(&$create_label_widget_grid($disk_labeled_widgets));
+    $scrolled_window->set_propagate_natural_height(1) if $hd_count > 4;
+
+    my $diskgrid = $create_label_widget_grid->($disk_labeled_widgets);
+
+    $scrolled_window->add($diskgrid);
     $scrolled_window->set_policy('never', 'automatic');
+    $scrolled_window->set_visible(1);
+    $scrolled_window->set_min_content_height(190);
+
+    my $vbox = Gtk3::Box->new('vertical', 0);
+    $vbox->pack_start($scrolled_window, 1, 1, 10);
 
-    return $scrolled_window;
-#    &$create_label_widget_grid($disk_labeled_widgets)
+    my $hbox = Gtk3::Box->new('horizontal', 0);
+    $hbox->pack_end($clear_all_button, 0, 0, 20);
+    $hbox->set_visible(1);
+    $vbox->pack_end($hbox, 0, 0, 0);
+
+    return $vbox;
 };
 
 # shared between different ui parts (e.g., ZFS and "normal" single disk FS)
@@ -2978,7 +3038,7 @@ my $get_hdsize_spinbtn = sub {
 
 my $create_raid_advanced_grid = sub {
     my $labeled_widgets = [];
-    my $spinbutton_ashift = Gtk3::SpinButton->new_with_range(9,13,1);
+    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)");
     $spinbutton_ashift->signal_connect ("value-changed" => sub {
        my $w = shift;
@@ -3031,7 +3091,7 @@ my $create_raid_advanced_grid = sub {
     push @$labeled_widgets, "copies", $spinbutton_copies;
 
     push @$labeled_widgets, "hdsize", $get_hdsize_spinbtn->();
-    return &$create_label_widget_grid($labeled_widgets);;
+    return $create_label_widget_grid->($labeled_widgets);;
 };
 
 sub create_hdoption_view {
@@ -3045,37 +3105,39 @@ sub create_hdoption_view {
     my $contarea = $dialog->get_content_area();
 
     my $hbox2 =  Gtk3::Box->new('horizontal', 0);
-    $contarea->pack_start($hbox2, 1, 1, 10);
+    $contarea->pack_start($hbox2, 1, 1, 5);
 
     my $grid =  Gtk3::Grid->new();
     $grid->set_column_spacing(10);
     $grid->set_row_spacing(10);
 
-    $hbox2->pack_start($grid, 1, 0, 10);
+    $hbox2->pack_start($grid, 1, 0, 5);
 
     my $row = 0;
 
     # Filesystem type
-
     my $label0 = Gtk3::Label->new("Filesystem");
     $label0->set_alignment (1, 0.5);
     $grid->attach($label0, 0, $row, 1, 1);
 
     my $fstypecb = Gtk3::ComboBoxText->new();
-
-    my $fstype = ['ext4', 'xfs',
-                 'zfs (RAID0)', 'zfs (RAID1)',
-                 'zfs (RAID10)', 'zfs (RAIDZ-1)',
-                 'zfs (RAIDZ-2)', 'zfs (RAIDZ-3)'];
-
+    my $fstype = [
+       'ext4',
+       'xfs',
+       'zfs (RAID0)',
+       'zfs (RAID1)',
+       'zfs (RAID10)',
+       'zfs (RAIDZ-1)',
+       'zfs (RAIDZ-2)',
+       'zfs (RAIDZ-3)',
+    ];
     push @$fstype, 'btrfs (RAID0)', 'btrfs (RAID1)', 'btrfs (RAID10)'
        if $setup->{enable_btrfs};
 
     my $tcount = 0;
     foreach my $tmp (@$fstype) {
        $fstypecb->append_text($tmp);
-       $fstypecb->set_active ($tcount)
-           if $config_options->{filesys} eq $tmp;
+       $fstypecb->set_active ($tcount) if $config_options->{filesys} eq $tmp;
        $tcount++;
     }
 
@@ -3090,7 +3152,9 @@ sub create_hdoption_view {
     $grid->attach($sep, 0, $row, 2, 1);
     $row++;
 
-    my $hw_raid_note = Gtk3::Label->new("Note: ZFS is not compatible with disks backed by a hardware RAID controller. For details see the reference documentation.");
+    my $hw_raid_note = Gtk3::Label->new(
+        "Note: ZFS is not compatible with hardware RAID controllers, for details see the documentation."
+    );
     $hw_raid_note->set_line_wrap(1);
     $hw_raid_note->set_max_width_chars(30);
     $hw_raid_note->set_visible(0);
@@ -3274,7 +3338,6 @@ sub legacy_bios_4k_check {
 }
 
 sub get_zfs_raid_setup {
-
     my $filesys = $config_options->{filesys};
 
     my $devlist = &$get_raid_devlist();
@@ -3282,11 +3345,8 @@ sub get_zfs_raid_setup {
     my $diskcount = scalar(@$devlist);
     die "$filesys needs at least one device\n" if $diskcount < 1;
 
-    my $bootdevlist = [];
-
     my $cmd= '';
     if ($filesys eq 'zfs (RAID0)') {
-       push @$bootdevlist, @$devlist[0];
        foreach my $hd (@$devlist) {
            legacy_bios_4k_check(@$hd[4]);
            $cmd .= " @$hd[1]";
@@ -3300,14 +3360,11 @@ sub get_zfs_raid_setup {
            zfs_mirror_size_check($expected_size, @$hd[2]);
            legacy_bios_4k_check(@$hd[4]);
            $cmd .= " @$hd[1]";
-           push @$bootdevlist, $hd;
        }
     } elsif ($filesys eq 'zfs (RAID10)') {
        die "zfs (RAID10) needs at least 4 device\n" if $diskcount < 4;
        die "zfs (RAID10) needs an even number of devices\n" if $diskcount & 1;
 
-       push @$bootdevlist, @$devlist[0], @$devlist[1];
-
        for (my $i = 0; $i < $diskcount; $i+=2) {
            my $hd1 = @$devlist[$i];
            my $hd2 = @$devlist[$i+1];
@@ -3328,13 +3385,12 @@ sub get_zfs_raid_setup {
            zfs_mirror_size_check($expected_size, @$hd[2]);
            legacy_bios_4k_check(@$hd[4]);
            $cmd .= " @$hd[1]";
-           push @$bootdevlist, $hd;
        }
     } else {
        die "unknown zfs mode '$filesys'\n";
     }
 
-    return ($devlist, $bootdevlist, $cmd);
+    return ($devlist, $cmd);
 }
 
 sub get_btrfs_raid_setup {
@@ -3514,10 +3570,8 @@ sub create_intro_view {
     cleanup_view();
 
     if (int($total_memory) < 1024) {
-       my $product = $product_cfg->{$setup->{product}};
-
        display_error("Less than 1 GiB of usable memory detected, installation will probably fail.\n\n".
-           "See 'System Requirements' in the $product->{fullname} documentation.");
+           "See 'System Requirements' in the $setup->{fullname} documentation.");
     }
 
     if ($setup->{product} eq 'pve') {
@@ -3576,4 +3630,9 @@ create_intro_view () if !$initial_error;
 
 Gtk3->main;
 
+# reap left over zombie processes
+while ((my $child = waitpid(-1, POSIX::WNOHANG)) > 0) {
+    print "reaped child $child\n";
+}
+
 exit 0;