]> git.proxmox.com Git - pve-installer.git/blobdiff - proxinstall
bump version to 5.0-2
[pve-installer.git] / proxinstall
index 3a474bec37e2a940198fa1ddadcd959bcb965641..e02eff1e7d3a5f77a5a998ba94bbb1cf6ff969f7 100755 (executable)
@@ -18,7 +18,7 @@ use Data::Dumper;
 use File::Basename;
 use Time::HiRes;
 
-my $release = '4.2';
+my $release = '4.4';
 
 my $kapi = `uname -r`;
 chomp $kapi;
@@ -144,6 +144,42 @@ my $ipv4_mask_hash = {
     '255.255.255.252' => 30
 };
 
+my $ipv4_reverse_mask = [
+    '0.0.0.0',
+    '128.0.0.0',
+    '192.0.0.0',
+    '224.0.0.0',
+    '240.0.0.0',
+    '248.0.0.0',
+    '252.0.0.0',
+    '254.0.0.0',
+    '255.0.0.0',
+    '255.128.0.0',
+    '255.192.0.0',
+    '255.224.0.0',
+    '255.240.0.0',
+    '255.248.0.0',
+    '255.252.0.0',
+    '255.254.0.0',
+    '255.255.0.0',
+    '255.255.128.0',
+    '255.255.192.0',
+    '255.255.224.0',
+    '255.255.240.0',
+    '255.255.248.0',
+    '255.255.252.0',
+    '255.255.254.0',
+    '255.255.255.0',
+    '255.255.255.128',
+    '255.255.255.192',
+    '255.255.255.224',
+    '255.255.255.240',
+    '255.255.255.248',
+    '255.255.255.252',
+    '255.255.255.254',
+    '255.255.255.255',
+];
+
 my ($window, $cmdbox, $inbox, $htmlview);
 my ($next, $next_fctn, $target_hd);
 my ($progress, $progress_status);
@@ -762,19 +798,29 @@ sub zfs_create_rpool {
 sub zfs_create_swap {
     my ($swapsize) = @_;
 
-    syscmd ("zfs create -V ${swapsize}K -b 4K $zfspoolname/swap")  == 0 ||
-       die "unable to create zfs swap device\n";
+    my $cmd = "zfs create -V ${swapsize}K -b 4K";
 
-    syscmd ("zfs set com.sun:auto-snapshot=false $zfspoolname/swap") == 0 ||
-       die "unable to set zfs properties\n";
+    $cmd .= " -o com.sun:auto-snapshot=false";
+
+    # copies for swap does not make sense
+    $cmd .= " -o copies=1";
 
     # reduces memory pressure
-    syscmd ("zfs set sync=always $zfspoolname/swap") == 0 ||
-       die "unable to set zfs properties\n";
+    $cmd .= " -o sync=always";
 
-    # copies for swap does not make sense
-    syscmd ("zfs set copies=1 $zfspoolname/swap") == 0 ||
-       die "unable to set zfs properties\n";
+    # cheapest compression to drop zero pages
+    $cmd .= " -o compression=zle";
+
+    # skip log devices
+    $cmd .= " -o logbias=throughput";
+    # only cache metadata in RAM (caching swap content does not make sense)
+    $cmd .= " -o primarycache=metadata";
+    # don't cache anything in L2ARC
+    $cmd .= " -o secondarycache=none";
+
+    $cmd .= " $zfspoolname/swap";
+    syscmd ($cmd)  == 0 ||
+       die "unable to create zfs swap device\n";
 
     return "/dev/zvol/$zfspoolname/swap";
 }
@@ -800,7 +846,7 @@ sub partition_bootable_disk {
     die "hardisk '$target_dev' too small (${hdsize}GB)\n" if $hdgb < 8;
 
     # 1 - BIOS boot partition (Grub Stage2): first free 1M
-    # 2 - EFI ESP: next free 128M
+    # 2 - EFI ESP: next free 256M
     # 3 - OS/Data partition: rest, up to $maxhdsize in MB
 
     my $grubbootdev = get_partition_dev($target_dev, 1);
@@ -810,17 +856,17 @@ sub partition_bootable_disk {
     my $pcmd = ['sgdisk'];
 
     my $pnum = 1;
-    push @$pcmd, "-n${pnum}::+1M", "-t$pnum:EF02";
+    push @$pcmd, "-n${pnum}:1M:+1M", "-t$pnum:EF02";
 
     $pnum = 2;
-    push @$pcmd, "-n${pnum}::+128M", "-t$pnum:EF00";
+    push @$pcmd, "-n${pnum}:2M:+256M", "-t$pnum:EF00";
 
     $pnum = 3;
-    push @$pcmd, "-n${pnum}::${restricted_hdsize_mb}", "-t$pnum:$ptype";
+    push @$pcmd, "-n${pnum}:258M:${restricted_hdsize_mb}", "-t$pnum:$ptype";
 
     push @$pcmd, $target_dev;
 
-    my $os_size = $hdsize - 130*1024; # 128M + 1M + up to 1M alignment
+    my $os_size = $hdsize - 258*1024; # 256M + 1M + 1M alignment
 
     syscmd($pcmd) == 0 ||
        die "unable to partition harddisk '${target_dev}'\n";
@@ -951,6 +997,8 @@ sub compute_swapsize {
        $ss = 8 if $ss > 8;
        $swapsize = $ss*1024*1024;
     }
+
+    return $swapsize;
 }
 
 my $udevadm_trigger_block = sub {
@@ -1232,21 +1280,32 @@ sub extract_data {
 
        my $ntype = $ipversion == 4 ? 'inet' : 'inet6';
 
+       my $bridge_port = $ipconf->{ifaces}->{$ipconf->{selected}}->{name};
+
+       $ifaces .= "iface $bridge_port $ntype manual\n";
+
         $ifaces .=
-            "auto vmbr0\niface vmbr0 $ntype static\n" .
+            "\nauto vmbr0\niface vmbr0 $ntype static\n" .
             "\taddress $ipaddress\n" .
             "\tnetmask $netmask\n" .
             "\tgateway $gateway\n" .
-            "\tbridge_ports eth0\n" .
+            "\tbridge_ports $bridge_port\n" .
             "\tbridge_stp off\n" .
             "\tbridge_fd 0\n";
 
+       foreach my $iface (sort keys %{$ipconf->{ifaces}}) {
+           my $name = $ipconf->{ifaces}->{$iface}->{name};
+           next if $name eq $bridge_port;
+
+           $ifaces .= "\niface $name $ntype manual\n";
+       }
+
        write_config ($ifaces, "$targetdir/etc/network/interfaces");
 
        # configure dns
 
-       my $resolfconf = "search $domain\nnameserver $dnsserver\n";
-       write_config ($resolfconf, "$targetdir/etc/resolv.conf");
+       my $resolvconf = "search $domain\nnameserver $dnsserver\n";
+       write_config ($resolvconf, "$targetdir/etc/resolv.conf");
 
        # configure fstab
 
@@ -1438,8 +1497,14 @@ _EOD
                if ($di->{esp}) {
                    syscmd ("mount -n $di->{esp} $targetdir/boot/efi") == 0 ||
                        die "unable to mount $di->{esp}\n";
-                   syscmd ("chroot $targetdir /usr/sbin/grub-install --target x86_64-efi --no-floppy --bootloader-id='proxmox' $dev") == 0 ||
-                       die "unable to install the EFI boot loader on '$dev'\n";
+                   my $rc = syscmd ("chroot $targetdir /usr/sbin/grub-install --target x86_64-efi --no-floppy --bootloader-id='proxmox' $dev");
+                   if ($rc != 0) {
+                       if (-d '/sys/firmware/efi') {
+                           die "unable to install the EFI boot loader on '$dev'\n";
+                       } else {
+                           warn "unable to install the EFI boot loader on '$dev', ignoring (not booted using UEFI)\n";
+                       }
+                   }
                    # also install fallback boot file (OVMF does not boot without)
                    mkdir("$targetdir/boot/efi/EFI/BOOT");
                    syscmd("cp $targetdir/boot/efi/EFI/proxmox/grubx64.efi $targetdir/boot/efi/EFI/BOOT/BOOTx64.EFI") == 0 ||
@@ -1714,21 +1779,60 @@ sub create_text_input {
 
 sub get_ip_config {
 
-    my $ifconfig = `ifconfig eth0`;
+    my $ifaces = {};
+    my $default;
+
+    my $links = `ip -o l`;
+    foreach my $l (split /\n/,$links) {
+       my ($index, $name, $flags, $state, $mac) = $l =~ m/^(\d+):\s+(\S+):\s+<(\S+)>.*\s+state\s+(\S+)\s+.*\s+link\/ether\s+(\S+)\s+/;
+       next if !$name || $name eq 'lo';
+
+       my $driver = readlink "/sys/class/net/$name/device/driver" || 'unknown';
+       $driver =~ s!^.*/!!;
+
+       $ifaces->{"$index"} = {
+           name => $name,
+           driver => $driver,
+           flags => $flags,
+           state => $state,
+           mac => $mac,
+       };
+
+       my $addresses = `ip -o a s $name`;
+       foreach my $a (split /\n/,$addresses) {
+           my ($family, $ip, $prefix) = $a =~ m/^\Q$index\E:\s+\Q$name\E\s+(inet|inet6)\s+($IPRE)\/(\d+)\s+/;
+           next if !$ip;
+
+           my $mask = $prefix;
+
+           if ($family eq 'inet') {
+               next if !$ip =~ /$IPV4RE/;
+               next if $prefix < 8 || $prefix > 32;
+               $mask = @$ipv4_reverse_mask[$prefix];
+           } else {
+               next if !$ip =~ /$IPV6RE/;
+           }
+
+           $default = $index if !$default;
+
+           $ifaces->{"$index"}->{"$family"} = {
+               mask => $mask,
+               addr => $ip,
+           };
+       }
+    }
 
-    my ($addr) = $ifconfig =~ m/inet addr:(\S*)/m;
-    my ($mask) = $ifconfig =~ m/Mask:(\S*)/m;
 
-    my $route = `route -n`;
-    my ($gateway) = $route =~ m/^0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+)\s+/m;
+    my $route = `ip route`;
+    my ($gateway) = $route =~ m/^default\s+via\s+(\S+)\s+/m;
 
     my $resolvconf = `cat /etc/resolv.conf`;
     my ($dnsserver) = $resolvconf =~ m/^nameserver\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/m;
     my ($domain) = $resolvconf =~ m/^domain\s+(\S+)$/m;
 
     return {
-       addr => $addr,
-       mask => $mask,
+       default => $default,
+       ifaces => $ifaces,
        gateway => $gateway,
        dnsserver => $dnsserver,
        domain => $domain,
@@ -1753,6 +1857,8 @@ sub display_error {
     $dialog->destroy();
 }
 
+my $ipconf_first_view = 1;
+
 sub create_ipconf_view {
 
     cleanup_view ();
@@ -1765,8 +1871,59 @@ sub create_ipconf_view {
     my $vbox2 =  Gtk3::VBox->new (0, 0);
     $hbox->add ($vbox2);
 
-    my $addr = $ipconf->{addr} || '192.168.100.2';
-    my $mask = $ipconf->{mask} || '255.255.255.0';
+    my $ipbox;
+    ($ipbox, $ipconf_entry_addr) =
+       create_text_input ("192.168.100.2", 'IP Address:');
+
+    my $maskbox;
+    ($maskbox, $ipconf_entry_mask) =
+       create_text_input ("255.255.255.0", 'Netmask:');
+
+    my $device_cb = Gtk3::ComboBoxText->new();
+    $device_cb->set_active(0);
+    $device_cb->set_visible(1);
+
+    my $get_device_desc = sub {
+       my $iface = shift;
+       return "$iface->{name} - $iface->{mac} ($iface->{driver})";
+    };
+
+    my $device_active_map = {};
+
+    my $device_change_handler = sub {
+       my $current = shift;
+       $ipconf->{selected} = $device_active_map->{$current->get_active()};
+       my $iface = $ipconf->{ifaces}->{$ipconf->{selected}};
+       $ipconf_entry_addr->set_text($iface->{inet}->{addr} || $iface->{inet6}->{addr})
+           if $iface->{inet}->{addr} || $iface->{inet6}->{addr};
+       $ipconf_entry_mask->set_text($iface->{inet}->{mask} || $iface->{inet6}->{mask})
+           if $iface->{inet}->{mask} || $iface->{inet6}->{mask};
+    };
+
+    my $i = 0;
+    foreach my $index (sort keys %{$ipconf->{ifaces}}) {
+       $device_cb->append_text(&$get_device_desc($ipconf->{ifaces}->{$index}));
+        $device_active_map->{$i} = $index;
+       if ($ipconf_first_view && $index == $ipconf->{default}) {
+           $device_cb->set_active($i);
+           &$device_change_handler($device_cb);
+           $ipconf_first_view = 0;
+       }
+       $device_cb->signal_connect ('changed' => $device_change_handler);
+       $i++;
+    }
+
+    $device_cb->set_active(0)
+       if !($ipconf->{selected});
+
+    my $devicebox = Gtk3::HBox->new (0, 0);
+    my $label = Gtk3::Label->new ("Management Interface:");
+    $label->set_size_request (150, -1);
+    $label->set_alignment (1, 0.5);
+    $devicebox->pack_start ($label, 0, 0, 10);
+    $devicebox->pack_start ($device_cb, 0, 0, 0);
+
+    $vbox2->pack_start ($devicebox, 0, 0, 2);
 
     my $hn = $ipconf->{domain} ? "pve.$ipconf->{domain}" : 'pve.example.invalid';
    
@@ -1774,14 +1931,8 @@ sub create_ipconf_view {
        create_text_input ($hn, 'Hostname (FQDN):');
     $vbox2->pack_start ($hostbox, 0, 0, 2);
 
-    my $ipbox;
-    ($ipbox, $ipconf_entry_addr) =
-       create_text_input ($addr, 'IP Address:');
     $vbox2->pack_start ($ipbox, 0, 0, 2);
 
-    my $maskbox;
-    ($maskbox, $ipconf_entry_mask) =
-       create_text_input ($mask, 'Netmask:');
     $vbox2->pack_start ($maskbox, 0, 0, 2);
 
     $gateway = $ipconf->{gateway} || '192.168.100.1';
@@ -2040,7 +2191,7 @@ sub create_password_view {
 
        my $t3 = $eme->get_text;
        if ($t3 !~ m/^\S+\@\S+\.\S+$/) {
-           display_message ("E-Mail does not look like a vaild address" .
+           display_message ("E-Mail does not look like a valid address" .
                             " (user\@domain.tld)");
            $eme->grab_focus();
            return;
@@ -2305,22 +2456,16 @@ my $create_raid_disk_grid = sub {
 
 my $create_raid_advanced_grid = sub {
     my $labeled_widgets = [];
-    my $entry_ashift = Gtk3::Entry->new();
-    $entry_ashift->set_tooltip_text("zpool ashift property (pool sector size, default 2^12)");
-    $entry_ashift->signal_connect (key_press_event => \&check_int);
-    $entry_ashift->signal_connect (changed => sub {
-       my ($entry) = @_;
-
-       my $text = $entry->get_text();
-       delete $config_options->{ashift} if !defined($text);
-
-       $text =~ m/^\s*(\d+)\s*$/;
-       $config_options->{ashift} = $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;
+       $config_options->{ashift} = $w->get_value_as_int();
     });
     $config_options->{ashift} = 12 if ! defined($config_options->{ashift});
-    $entry_ashift->set_text($config_options->{ashift});
+    $spinbutton_ashift->set_value($config_options->{ashift});
     push @$labeled_widgets, "ashift";
-    push @$labeled_widgets, $entry_ashift;
+    push @$labeled_widgets, $spinbutton_ashift;
 
     my $combo_compress = Gtk3::ComboBoxText->new();
     $combo_compress->set_tooltip_text("zfs compression algorithm for rpool dataset");
@@ -2358,7 +2503,6 @@ my $create_raid_advanced_grid = sub {
     $spinbutton_copies->signal_connect ("value-changed" => sub {
        my $w = shift;
        $config_options->{copies} = $w->get_value_as_int();
-       warn "changed: '$config_options->{copies}'\n";
     });
     $config_options->{copies} = 1 if !defined($config_options->{copies});
     $spinbutton_copies->set_value($config_options->{copies});
@@ -2451,7 +2595,7 @@ sub create_hdoption_view {
     push @$hdsize_labeled_widgets, "maxroot", $entry_maxroot;
 
     my $entry_minfree = Gtk3::Entry->new();
-    $entry_minfree->set_tooltip_text("minumum free LVM space (GB, required for LVM snapshots)");
+    $entry_minfree->set_tooltip_text("minimum free LVM space (GB, required for LVM snapshots)");
     $entry_minfree->signal_connect (key_press_event => \&check_float);
     $entry_minfree->set_text($config_options->{minfree}) if $config_options->{minfree};
     push @$hdsize_labeled_widgets, "minfree", $entry_minfree;
@@ -2565,7 +2709,7 @@ my $get_raid_devlist = sub {
     my $dev_name_hash = {};
 
     my $devlist = [];
-    for (my $i = 0; $i < 8; $i++) {
+    for (my $i = 0; $i < @$hds; $i++) {
        if (my $hd = $config_options->{"disksel$i"}) {
            my ($disk, $devname, $size, $model) = @$hd;
            die "device '$devname' is used more than once\n" 
@@ -2795,7 +2939,7 @@ sub create_intro_view {
 
 $ipconf = get_ip_config ();
 
-$country = detect_country() if $ipconf->{addr} || $opt_testmode;;
+$country = detect_country() if $ipconf->{default} || $opt_testmode;;
 
 # read country, kmap and timezone infos
 $cmap = read_cmap ();