]>
git.proxmox.com Git - pve-container.git/blob - src/PVE/LXC/Setup/Debian.pm
1 package PVE
::LXC
::Setup
::Debian
;
6 use PVE
::Tools
qw($IPV6RE);
11 use PVE
::LXC
::Setup
::Base
;
13 use base
qw(PVE::LXC::Setup::Base);
16 my ($class, $conf, $rootdir) = @_;
18 my $version = PVE
::Tools
::file_read_firstline
("$rootdir/etc/debian_version");
20 die "unable to read version info\n" if !defined($version);
22 # translate stretch/sid => 9.0 (used on debian testing repository)
23 $version = 9.0 if $version eq 'stretch/sid';
25 die "unable to parse version info '$version'\n"
26 if $version !~ m/^(\d+(\.\d+)?)(\.\d+)?/;
30 die "unsupported debian version '$version'\n"
31 if !($version >= 4 && $version <= 9);
33 my $self = { conf
=> $conf, rootdir
=> $rootdir, version
=> $version };
35 $conf->{ostype
} = "debian";
37 return bless $self, $class;
41 my ($self, $conf) = @_;
43 my $filename = "/etc/inittab";
44 return if !$self->ct_file_exists($filename);
46 my $ttycount = PVE
::LXC
::Config-
>get_tty_count($conf);
47 my $inittab = $self->ct_file_get_contents($filename);
51 !/^\s*\d+:\d+:[^:]*:.*getty/ &&
54 } split(/\n/, $inittab);
56 $inittab = join("\n", @lines) . "\n";
58 $inittab .= "p0::powerfail:/sbin/init 0\n";
60 my $version = $self->{version
};
61 for (my $id = 1; $id <= $ttycount; $id++) {
62 next if $id == 7; # reserved for X11
63 my $levels = ($id == 1) ?
'2345' : '23';
65 $inittab .= "$id:$levels:respawn:/sbin/getty -L 38400 tty$id\n";
67 $inittab .= "$id:$levels:respawn:/sbin/getty --noclear 38400 tty$id\n";
71 $self->ct_file_set_contents($filename, $inittab);
73 my $systemd = $self->ct_readlink('/sbin/init');
74 if (defined($systemd) && $systemd =~ m
@/systemd$@) {
75 $self->setup_container_getty_service(1);
79 sub remove_gateway_scripts
{
81 my $length = scalar(@$attr);
82 for (my $i = 0; $i < $length; ++$i) {
84 if ($a =~ m
@^\s*post-up\s
+.*route
.*add
.*default.*(?
:gw
|via
)\s
+(\S
+)@) {
86 if ($i > 0 && $attr->[$i-1] =~ m
@^\s*post-up\s
+.*route
.*add
.*\Q
$1\E@) {
97 if ($a =~ m
@^\s*pre-down\s
+.*route
.*del
.*default.*(?
:gw
|via
)\s
+(\S
+)@) {
99 if ($attr->[$i+1] =~ m
@^\s*pre-down\s
+.*route
.*del
.*\Q
$1\E@) {
100 splice @$attr, $i, 2;
103 splice @$attr, $i, 1;
112 sub make_gateway_scripts
{
113 my ($ifname, $gw) = @_;
115 \tpost-up ip route add $gw dev $ifname
116 \tpost-up ip route add default via $gw
117 \tpre-down ip route del default via $gw
118 \tpre-down ip route del $gw dev $ifname
123 my ($self, $conf) = @_;
126 foreach my $k (keys %$conf) {
127 next if $k !~ m/^net(\d+)$/;
129 my $d = PVE
::LXC
::Config-
>parse_lxc_network($conf->{$k});
133 if (defined($d->{ip
})) {
134 if ($d->{ip
} =~ /^(?:dhcp|manual)$/) {
135 $net->{address
} = $d->{ip
};
137 my $ipinfo = PVE
::LXC
::parse_ipv4_cidr
($d->{ip
});
138 $net->{address
} = $ipinfo->{address
};
139 $net->{netmask
} = $ipinfo->{netmask
};
143 if (defined($d->{'gw'})) {
144 $net->{gateway
} = $d->{'gw'};
145 if (defined($cidr) && !PVE
::Network
::is_ip_in_cidr
($d->{gw
}, $cidr, 4)) {
146 # gateway is not reachable, need an extra route
147 $net->{needsroute
} = 1;
151 if (defined($d->{ip6
})) {
152 if ($d->{ip6
} =~ /^(?:auto|dhcp|manual)$/) {
153 $net->{address6
} = $d->{ip6
};
154 } elsif ($d->{ip6
} !~ /^($IPV6RE)\/(\d
+)$/) {
155 die "unable to parse ipv6 address/prefix\n";
157 $net->{address6
} = $1;
158 $net->{netmask6
} = $2;
162 if (defined($d->{'gw6'})) {
163 $net->{gateway6
} = $d->{'gw6'};
164 if (defined($cidr) && !PVE
::Network
::is_ip_in_cidr
($d->{gw6
}, $cidr, 6)) {
165 # gateway is not reachable, need an extra route
166 $net->{needsroute6
} = 1;
169 $networks->{$d->{name
}} = $net if keys %$net;
173 return if !scalar(keys %$networks);
175 my $filename = "/etc/network/interfaces";
181 my $done_v4_hash = {};
182 my $done_v6_hash = {};
184 my $print_section = sub {
187 my $ifname = $section->{ifname
};
188 my $net = $networks->{$ifname};
190 if (!$done_auto->{$ifname}) {
191 $interfaces .= "auto $ifname\n";
192 $done_auto->{$ifname} = 1;
195 if ($section->{type
} eq 'ipv4') {
196 $done_v4_hash->{$ifname} = 1;
198 if ($net->{address
} =~ /^(dhcp|manual)$/) {
199 $interfaces .= "iface $ifname inet $1\n";
201 $interfaces .= "iface $ifname inet static\n";
202 $interfaces .= "\taddress $net->{address}\n" if defined($net->{address
});
203 $interfaces .= "\tnetmask $net->{netmask}\n" if defined($net->{netmask
});
204 if (defined(my $gw = $net->{gateway
})) {
205 remove_gateway_scripts
($section->{attr
});
206 if ($net->{needsroute
}) {
207 $interfaces .= make_gateway_scripts
($ifname, $gw);
209 $interfaces .= "\tgateway $gw\n";
212 foreach my $attr (@{$section->{attr
}}) {
213 $interfaces .= "\t$attr\n";
219 } elsif ($section->{type
} eq 'ipv6') {
220 $done_v6_hash->{$ifname} = 1;
222 if ($net->{address6
} =~ /^(auto|dhcp|manual)$/) {
223 $interfaces .= "iface $ifname inet6 $1\n";
225 $interfaces .= "iface $ifname inet6 static\n";
226 $interfaces .= "\taddress $net->{address6}\n" if defined($net->{address6
});
227 $interfaces .= "\tnetmask $net->{netmask6}\n" if defined($net->{netmask6
});
228 if (defined(my $gw = $net->{gateway6
})) {
229 remove_gateway_scripts
($section->{attr
});
230 if ($net->{needsroute6
}) {
231 $interfaces .= make_gateway_scripts
($ifname, $gw);
233 $interfaces .= "\tgateway $net->{gateway6}\n" if defined($net->{gateway6
});
236 foreach my $attr (@{$section->{attr
}}) {
237 $interfaces .= "\t$attr\n";
243 die "unknown section type '$section->{type}'";
249 if (my $fh = $self->ct_open_file_read($filename)) {
250 while (defined (my $line = <$fh>)) {
252 if ($line =~ m/^#/) {
253 $interfaces .= "$line\n";
256 if ($line =~ m/^\s*$/) {
260 $interfaces .= "$line\n";
264 if ($line =~ m/^\s*iface\s+(\S+)\s+inet\s+(\S+)\s*$/) {
266 &$print_section(); # print previous section
267 if (!$networks->{$ifname}) {
268 $interfaces .= "$line\n";
271 $section = { type
=> 'ipv4', ifname
=> $ifname, attr
=> []};
274 if ($line =~ m/^\s*iface\s+(\S+)\s+inet6\s+(\S+)\s*$/) {
276 &$print_section(); # print previous section
277 if (!$networks->{$ifname}) {
278 $interfaces .= "$line\n";
281 $section = { type
=> 'ipv6', ifname
=> $ifname, attr
=> []};
285 if ($line =~ m/^\s*auto\s*(.*)$/) {
286 foreach my $iface (split(/\s+/, $1)) {
287 $done_auto->{$iface} = 1;
290 $interfaces .= "$line\n";
293 # Handle other section delimiters:
294 if ($line =~ m
/^\s
*(?
:mapping\s
300 $interfaces .= "$line\n";
303 if ($section && $line =~ m/^\s*((\S+)\s(.*))$/) {
304 my ($adata, $aname) = ($1, $2);
305 if ($aname eq 'address' || $aname eq 'netmask' ||
306 $aname eq 'gateway' || $aname eq 'broadcast') {
309 push @{$section->{attr
}}, $adata;
314 $interfaces .= "$line\n";
319 my $need_separator = length($interfaces) && ($interfaces !~ /\n\n$/);
320 foreach my $ifname (sort keys %$networks) {
321 my $net = $networks->{$ifname};
323 if (!$done_v4_hash->{$ifname} && defined($net->{address
})) {
324 if ($need_separator) { $interfaces .= "\n"; $need_separator = 0; };
325 $section = { type
=> 'ipv4', ifname
=> $ifname, attr
=> []};
328 if (!$done_v6_hash->{$ifname} && defined($net->{address6
})) {
329 if ($need_separator) { $interfaces .= "\n"; $need_separator = 0; };
330 $section = { type
=> 'ipv6', ifname
=> $ifname, attr
=> []};
335 $self->ct_file_set_contents($filename, $interfaces);