]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC/Setup/Debian.pm
remove Data::Dumper usages
[pve-container.git] / src / PVE / LXC / Setup / Debian.pm
index 2db806620fc825b68361e758372916e1fc10d4ee..50398892e512f695c79df4245c303caac618fe2b 100644 (file)
@@ -2,7 +2,7 @@ package PVE::LXC::Setup::Debian;
 
 use strict;
 use warnings;
-use Data::Dumper;
+
 use PVE::Tools qw($IPV6RE);
 use PVE::LXC;
 use PVE::Network;
@@ -19,13 +19,17 @@ sub new {
 
     die "unable to read version info\n" if !defined($version);
 
-    die "unable to parse version info\n"
+    # translate testing version names
+    $version = 9.1 if $version eq 'stretch/sid';
+    $version = 10 if $version eq 'buster/sid';
+
+    die "unable to parse version info '$version'\n"
        if $version !~ m/^(\d+(\.\d+)?)(\.\d+)?/;
 
     $version = $1;
 
     die "unsupported debian version '$version'\n"
-       if !($version >= 4 && $version < 9);
+       if !($version >= 4 && $version <= 10);
 
     my $self = { conf => $conf, rootdir => $rootdir, version => $version };
 
@@ -34,18 +38,28 @@ sub new {
     return bless $self, $class;
 }
 
+# Debian doesn't support the /dev/lxc/ subdirectory.
+sub devttydir {
+    return '';
+}
+
 sub setup_init {
     my ($self, $conf) = @_;
 
+    my $systemd = $self->ct_readlink('/sbin/init');
+    if (defined($systemd) && $systemd =~ m@/systemd$@) {
+       $self->setup_container_getty_service($conf);
+    }
+
     my $filename = "/etc/inittab";
     return if !$self->ct_file_exists($filename);
 
-    my $ttycount =  PVE::LXC::get_tty_count($conf);
+    my $ttycount =  PVE::LXC::Config->get_tty_count($conf);
     my $inittab = $self->ct_file_get_contents($filename);
 
     my @lines = grep {
            # remove getty lines
-           !/^\s*\d+:\d+:[^:]*:.*getty/ &&
+           !/^\s*\d+:\d*:[^:]*:.*getty/ &&
            # remove power lines
            !/^\s*p[fno0]:/
        } split(/\n/, $inittab);
@@ -71,32 +85,43 @@ sub setup_init {
 sub remove_gateway_scripts {
     my ($attr) = @_;
     my $length = scalar(@$attr);
-    for (my $i = 0; $i < $length; ++$i) {
-       my $a = $attr->[$i];
-       if ($a =~ m@^\s*post-up\s+.*route.*add.*default.*(?:gw|via)\s+(\S+)@) {
-           my $gw = $1;
-           if ($i > 0 && $attr->[$i-1] =~ m@^\s*post-up\s+.*route.*add.*\Q$1\E@) {
-               --$i;
-               splice @$attr, $i, 2;
-               $length -= 2;
-           } else {
-               splice @$attr, $i, 1;
-               $length -= 1;
-           }
-           --$i;
-           next;
+
+    my $found_section = 0;
+    my $keep = 1;
+    @$attr = grep {
+       if ($_ eq '# --- BEGIN PVE ---') {
+           $found_section = 1;
+           $keep = 0;
+           0; # remove this line
+       } elsif ($_ eq '# --- END PVE ---') {
+           $found_section = 1;
+           $keep = 1;
+           0; # remove this line
+       } else {
+           $keep;
        }
-       if ($a =~ m@^\s*pre-down\s+.*route.*del.*default.*(?:gw|via)\s+(\S+)@) {
-           my $gw = $1;
-           if ($attr->[$i+1] =~ m@^\s*pre-down\s+.*route.*del.*\Q$1\E@) {
-               splice @$attr, $i, 2;
-               $length -= 2;
-           } else {
-               splice @$attr, $i, 1;
-               $length -= 1;
-           }
+    } @$attr;
+
+    return if $found_section;
+    # XXX: To deal with existing setups we perform two types of removal for
+    # now. Newly started containers have their routing sections marked with
+    # begin/end comments. For older containers we perform a strict matching on
+    # the routing rules we added. We can probably remove this part at some point
+    # when it is unlikely that old debian setups are still around.
+
+    for (my $i = 0; $i < $length-3; ++$i) {
+       next if $attr->[$i+0] !~ m@^\s*post-up\s+ip\s+route\s+add\s+(\S+)\s+dev\s+(\S+)$@;
+       my ($ip, $dev) = ($1, $2);
+       if ($attr->[$i+1] =~ m@^\s*post-up\s+ip\s+route\s+add\s+default\s+via\s+(\S+)\s+dev\s+(\S+)$@ &&
+           ($ip eq $1 && $dev eq $2) &&
+           $attr->[$i+2] =~ m@^\s*pre-down\s+ip\s+route\s+del\s+default\s+via\s+(\S+)\s+dev\s+(\S+)$@ &&
+           ($ip eq $1 && $dev eq $2) &&
+           $attr->[$i+3] =~ m@^\s*pre-down\s+ip\s+route\s+del\s+(\S+)\s+dev\s+(\S+)$@ &&
+           ($ip eq $1 && $dev eq $2))
+       {
+           splice @$attr, $i, 4;
+           $length -= 4;
            --$i;
-           next;
        }
     }
 }
@@ -104,10 +129,12 @@ sub remove_gateway_scripts {
 sub make_gateway_scripts {
     my ($ifname, $gw) = @_;
     return <<"SCRIPTS";
+# --- BEGIN PVE ---
 \tpost-up ip route add $gw dev $ifname
-\tpost-up ip route add default via $gw
-\tpre-down ip route del default via $gw
+\tpost-up ip route add default via $gw dev $ifname
+\tpre-down ip route del default via $gw dev $ifname
 \tpre-down ip route del $gw dev $ifname
+# --- END PVE ---
 SCRIPTS
 }
 
@@ -118,7 +145,7 @@ sub setup_network {
     foreach my $k (keys %$conf) {
        next if $k !~ m/^net(\d+)$/;
        my $ind = $1;
-       my $d = PVE::LXC::parse_lxc_network($conf->{$k});
+       my $d = PVE::LXC::Config->parse_lxc_network($conf->{$k});
        if ($d->{name}) {
            my $net = {};
            my $cidr;
@@ -153,7 +180,8 @@ sub setup_network {
            }
            if (defined($d->{'gw6'})) {
                $net->{gateway6} = $d->{'gw6'};
-               if (defined($cidr) && !PVE::Network::is_ip_in_cidr($d->{gw6}, $cidr, 6)) {
+               if (defined($cidr) && !PVE::Network::is_ip_in_cidr($d->{gw6}, $cidr, 6) &&
+                   !PVE::Network::is_ip_in_cidr($d->{gw6}, 'fe80::/10', 6)) {
                    # gateway is not reachable, need an extra route
                    $net->{needsroute6} = 1;
                }
@@ -187,14 +215,17 @@ sub setup_network {
        if ($section->{type} eq 'ipv4') {
            $done_v4_hash->{$ifname} = 1;
 
-           if ($net->{address} =~ /^(dhcp|manual)$/) {
-               $interfaces .= "iface $ifname inet $1\n";
+           if (!defined($net->{address})) {
+               # no address => no iface line
+           } elsif ($net->{address} =~ /^(dhcp|manual)$/) {
+               $interfaces .= "iface $ifname inet $1\n\n";
            } else {
                $interfaces .= "iface $ifname inet static\n";
                $interfaces .= "\taddress $net->{address}\n" if defined($net->{address});
                $interfaces .= "\tnetmask $net->{netmask}\n" if defined($net->{netmask});
+
+               remove_gateway_scripts($section->{attr});
                if (defined(my $gw = $net->{gateway})) {
-                   remove_gateway_scripts($section->{attr});
                    if ($net->{needsroute}) {
                        $interfaces .= make_gateway_scripts($ifname, $gw);
                    } else {
@@ -204,21 +235,21 @@ sub setup_network {
                foreach my $attr (@{$section->{attr}}) {
                    $interfaces .= "\t$attr\n";
                }
+               $interfaces .= "\n";
            }
-
-           $interfaces .= "\n";
-
        } elsif ($section->{type} eq 'ipv6') {
            $done_v6_hash->{$ifname} = 1;
 
-           if ($net->{address6} =~ /^(auto|dhcp|manual)$/) {
-               $interfaces .= "iface $ifname inet6 $1\n";
+           if (!defined($net->{address6})) {
+               # no address => no iface line
+           } elsif ($net->{address6} =~ /^(auto|dhcp|manual)$/) {
+               $interfaces .= "iface $ifname inet6 $1\n\n";
            } else {
                $interfaces .= "iface $ifname inet6 static\n";
                $interfaces .= "\taddress $net->{address6}\n" if defined($net->{address6});
                $interfaces .= "\tnetmask $net->{netmask6}\n" if defined($net->{netmask6});
+               remove_gateway_scripts($section->{attr});
                if (defined(my $gw = $net->{gateway6})) {
-                   remove_gateway_scripts($section->{attr});
                    if ($net->{needsroute6}) {
                        $interfaces .= make_gateway_scripts($ifname, $gw);
                    } else {
@@ -228,9 +259,8 @@ sub setup_network {
                foreach my $attr (@{$section->{attr}}) {
                    $interfaces .= "\t$attr\n";
                }
+               $interfaces .= "\n";
            }
-
-           $interfaces .= "\n";
        } else {
            die "unknown section type '$section->{type}'";
        }
@@ -238,9 +268,15 @@ sub setup_network {
        $section = undef;
     };
 
-    if (my $fh = $self->ct_open_file($filename, "r")) {
+    if (my $fh = $self->ct_open_file_read($filename)) {
        while (defined (my $line = <$fh>)) {
            chomp $line;
+           if ($line =~ m/^# --- (?:BEGIN|END) PVE ---/) {
+               # Include markers in the attribute section so
+               # remove_gateway_scripts() can find them.
+               push @{$section->{attr}}, $line if $section;
+               next;
+           }
            if ($line =~ m/^#/) {
                $interfaces .= "$line\n";
                next;
@@ -324,6 +360,14 @@ sub setup_network {
        }
     }
 
+    # older templates (< Debian 8) do not configure the loopback interface
+    # if not explicitly told to do so
+    if (!$done_auto->{lo}) {
+       $interfaces = "auto lo\niface lo inet loopback\n" .
+                     "iface lo inet6 loopback\n\n" .
+                     $interfaces;
+    }
+
     $self->ct_file_set_contents($filename, $interfaces);
 }