]>
Commit | Line | Data |
---|---|---|
7af97ad5 | 1 | package PVE::LXC::Setup::Debian; |
1c7f4f65 DM |
2 | |
3 | use strict; | |
4 | use warnings; | |
55fa4e09 | 5 | use Data::Dumper; |
a1b1a247 | 6 | use PVE::Tools qw($IPV6RE); |
55fa4e09 DM |
7 | use PVE::LXC; |
8 | use File::Path; | |
1c7f4f65 | 9 | |
7af97ad5 | 10 | use PVE::LXC::Setup::Base; |
1c7f4f65 | 11 | |
7af97ad5 | 12 | use base qw(PVE::LXC::Setup::Base); |
1c7f4f65 | 13 | |
633a7bd8 | 14 | sub new { |
5b4657d0 | 15 | my ($class, $conf, $rootdir) = @_; |
633a7bd8 | 16 | |
5b4657d0 | 17 | my $version = PVE::Tools::file_read_firstline("$rootdir/etc/debian_version"); |
633a7bd8 DM |
18 | |
19 | die "unable to read version info\n" if !defined($version); | |
adc8f577 DM |
20 | |
21 | die "unable to parse version info\n" | |
22 | if $version !~ m/^(\d+(\.\d+)?)(\.\d+)?/; | |
23 | ||
24 | $version = $1; | |
25 | ||
1c0a5ac7 | 26 | die "unsupported debian version '$version'\n" |
4596e30d | 27 | if !($version >= 4 && $version < 9); |
633a7bd8 | 28 | |
5b4657d0 DM |
29 | my $self = { conf => $conf, rootdir => $rootdir, version => $version }; |
30 | ||
27916659 | 31 | $conf->{ostype} = "debian"; |
633a7bd8 DM |
32 | |
33 | return bless $self, $class; | |
34 | } | |
35 | ||
d66768a2 | 36 | sub setup_init { |
633a7bd8 | 37 | my ($self, $conf) = @_; |
d66768a2 | 38 | |
2063d380 | 39 | my $filename = "/etc/inittab"; |
fe8a16b8 | 40 | return if !$self->ct_file_exists($filename); |
d66768a2 | 41 | |
fe8a16b8 WB |
42 | my $ttycount = PVE::LXC::get_tty_count($conf); |
43 | my $inittab = $self->ct_file_get_contents($filename); | |
44 | ||
45 | my @lines = grep { | |
46 | # remove getty lines | |
47 | !/^\s*\d+:\d+:[^:]*:.*getty/ && | |
48 | # remove power lines | |
49 | !/^\s*p[fno0]:/ | |
50 | } split(/\n/, $inittab); | |
51 | ||
52 | $inittab = join("\n", @lines) . "\n"; | |
53 | ||
54 | $inittab .= "p0::powerfail:/sbin/init 0\n"; | |
55 | ||
56 | my $version = $self->{version}; | |
39630c0d DM |
57 | for (my $id = 1; $id <= $ttycount; $id++) { |
58 | next if $id == 7; # reserved for X11 | |
59 | my $levels = ($id == 1) ? '2345' : '23'; | |
fe8a16b8 WB |
60 | if ($version < 7) { |
61 | $inittab .= "$id:$levels:respawn:/sbin/getty -L 38400 tty$id\n"; | |
62 | } else { | |
63 | $inittab .= "$id:$levels:respawn:/sbin/getty --noclear 38400 tty$id\n"; | |
d66768a2 | 64 | } |
d66768a2 | 65 | } |
fe8a16b8 WB |
66 | |
67 | $self->ct_file_set_contents($filename, $inittab); | |
d66768a2 DM |
68 | } |
69 | ||
55fa4e09 | 70 | sub setup_network { |
633a7bd8 | 71 | my ($self, $conf) = @_; |
55fa4e09 | 72 | |
55fa4e09 DM |
73 | my $networks = {}; |
74 | foreach my $k (keys %$conf) { | |
75 | next if $k !~ m/^net(\d+)$/; | |
93285df8 | 76 | my $ind = $1; |
27916659 | 77 | my $d = PVE::LXC::parse_lxc_network($conf->{$k}); |
55fa4e09 DM |
78 | if ($d->{name}) { |
79 | my $net = {}; | |
93285df8 | 80 | if (defined($d->{ip})) { |
ecf84da0 | 81 | if ($d->{ip} =~ /^(?:dhcp|manual)$/) { |
0178cffa WB |
82 | $net->{address} = $d->{ip}; |
83 | } else { | |
84 | my $ipinfo = PVE::LXC::parse_ipv4_cidr($d->{ip}); | |
85 | $net->{address} = $ipinfo->{address}; | |
86 | $net->{netmask} = $ipinfo->{netmask}; | |
87 | } | |
55fa4e09 | 88 | } |
93285df8 | 89 | if (defined($d->{'gw'})) { |
a1b1a247 | 90 | $net->{gateway} = $d->{'gw'}; |
55fa4e09 | 91 | } |
93285df8 | 92 | if (defined($d->{ip6})) { |
c6b8740b | 93 | if ($d->{ip6} =~ /^(?:auto|dhcp|manual)$/) { |
0178cffa WB |
94 | $net->{address6} = $d->{ip6}; |
95 | } elsif ($d->{ip6} !~ /^($IPV6RE)\/(\d+)$/) { | |
a1b1a247 | 96 | die "unable to parse ipv6 address/prefix\n"; |
0178cffa WB |
97 | } else { |
98 | $net->{address6} = $1; | |
99 | $net->{netmask6} = $2; | |
a1b1a247 | 100 | } |
a1b1a247 WB |
101 | } |
102 | if (defined($d->{'gw6'})) { | |
103 | $net->{gateway6} = $d->{'gw6'}; | |
55fa4e09 | 104 | } |
0178cffa | 105 | $networks->{$d->{name}} = $net if keys %$net; |
55fa4e09 DM |
106 | } |
107 | } | |
108 | ||
f44d23a5 | 109 | return if !scalar(keys %$networks); |
55fa4e09 | 110 | |
2063d380 | 111 | my $filename = "/etc/network/interfaces"; |
55fa4e09 DM |
112 | my $interfaces = ""; |
113 | ||
114 | my $section; | |
115 | ||
56be201e | 116 | my $done_auto = {}; |
55fa4e09 DM |
117 | my $done_v4_hash = {}; |
118 | my $done_v6_hash = {}; | |
1c0a5ac7 | 119 | |
55fa4e09 DM |
120 | my $print_section = sub { |
121 | my ($new) = @_; | |
1c0a5ac7 | 122 | |
55fa4e09 DM |
123 | return if !$section; |
124 | ||
125 | my $net = $networks->{$section->{ifname}}; | |
126 | ||
56be201e WB |
127 | if ($new && !$done_auto->{$section->{ifname}}) { |
128 | $interfaces .= "auto $section->{ifname}\n"; | |
129 | $done_auto->{$section->{ifname}} = 1; | |
130 | } | |
131 | ||
55fa4e09 DM |
132 | if ($section->{type} eq 'ipv4') { |
133 | $done_v4_hash->{$section->{ifname}} = 1; | |
134 | ||
ecf84da0 | 135 | if ($net->{address} =~ /^(dhcp|manual)$/) { |
0178cffa | 136 | $interfaces .= "iface $section->{ifname} inet $1\n"; |
fcaca113 | 137 | } else { |
55fa4e09 | 138 | $interfaces .= "iface $section->{ifname} inet static\n"; |
a1b1a247 WB |
139 | $interfaces .= "\taddress $net->{address}\n" if defined($net->{address}); |
140 | $interfaces .= "\tnetmask $net->{netmask}\n" if defined($net->{netmask}); | |
141 | $interfaces .= "\tgateway $net->{gateway}\n" if defined($net->{gateway}); | |
55fa4e09 DM |
142 | foreach my $attr (@{$section->{attr}}) { |
143 | $interfaces .= "\t$attr\n"; | |
144 | } | |
55fa4e09 | 145 | } |
1c0a5ac7 | 146 | |
55fa4e09 | 147 | $interfaces .= "\n"; |
1c0a5ac7 | 148 | |
55fa4e09 DM |
149 | } elsif ($section->{type} eq 'ipv6') { |
150 | $done_v6_hash->{$section->{ifname}} = 1; | |
1c0a5ac7 | 151 | |
c6b8740b | 152 | if ($net->{address6} =~ /^(auto|dhcp|manual)$/) { |
0178cffa | 153 | $interfaces .= "iface $section->{ifname} inet6 $1\n"; |
fcaca113 | 154 | } else { |
55fa4e09 | 155 | $interfaces .= "iface $section->{ifname} inet6 static\n"; |
a1b1a247 WB |
156 | $interfaces .= "\taddress $net->{address6}\n" if defined($net->{address6}); |
157 | $interfaces .= "\tnetmask $net->{netmask6}\n" if defined($net->{netmask6}); | |
158 | $interfaces .= "\tgateway $net->{gateway6}\n" if defined($net->{gateway6}); | |
55fa4e09 DM |
159 | foreach my $attr (@{$section->{attr}}) { |
160 | $interfaces .= "\t$attr\n"; | |
161 | } | |
162 | } | |
1c0a5ac7 WB |
163 | |
164 | $interfaces .= "\n"; | |
55fa4e09 DM |
165 | } else { |
166 | die "unknown section type '$section->{type}'"; | |
167 | } | |
168 | ||
169 | $section = undef; | |
170 | }; | |
1c0a5ac7 | 171 | |
2063d380 | 172 | if (my $fh = $self->ct_open_file($filename, "r")) { |
55fa4e09 DM |
173 | while (defined (my $line = <$fh>)) { |
174 | chomp $line; | |
175 | if ($line =~ m/^#/) { | |
176 | $interfaces .= "$line\n"; | |
177 | next; | |
178 | } | |
179 | if ($line =~ m/^\s*$/) { | |
180 | if ($section) { | |
181 | &$print_section(); | |
182 | } else { | |
183 | $interfaces .= "$line\n"; | |
184 | } | |
185 | next; | |
186 | } | |
0178cffa | 187 | if ($line =~ m/^\s*iface\s+(\S+)\s+inet\s+(\S+)\s*$/) { |
55fa4e09 | 188 | my $ifname = $1; |
0178cffa | 189 | &$print_section(); # print previous section |
55fa4e09 DM |
190 | if (!$networks->{$ifname}) { |
191 | $interfaces .= "$line\n"; | |
192 | next; | |
193 | } | |
194 | $section = { type => 'ipv4', ifname => $ifname, attr => []}; | |
195 | next; | |
196 | } | |
0178cffa | 197 | if ($line =~ m/^\s*iface\s+(\S+)\s+inet6\s+(\S+)\s*$/) { |
55fa4e09 | 198 | my $ifname = $1; |
0178cffa | 199 | &$print_section(); # print previous section |
55fa4e09 DM |
200 | if (!$networks->{$ifname}) { |
201 | $interfaces .= "$line\n"; | |
202 | next; | |
203 | } | |
204 | $section = { type => 'ipv6', ifname => $ifname, attr => []}; | |
205 | next; | |
206 | } | |
56be201e WB |
207 | # Handle 'auto' |
208 | if ($line =~ m/^\s*auto\s*(.*)$/) { | |
209 | foreach my $iface (split(/\s+/, $1)) { | |
210 | $done_auto->{$iface} = 1; | |
211 | } | |
212 | &$print_section(); | |
213 | $interfaces .= "$line\n"; | |
214 | next; | |
215 | } | |
0178cffa WB |
216 | # Handle other section delimiters: |
217 | if ($line =~ m/^\s*(?:mapping\s | |
0178cffa WB |
218 | |allow- |
219 | |source\s | |
220 | |source-directory\s | |
221 | )/x) { | |
222 | &$print_section(); | |
223 | $interfaces .= "$line\n"; | |
224 | next; | |
225 | } | |
55fa4e09 DM |
226 | if ($section && $line =~ m/^\s*((\S+)\s(.*))$/) { |
227 | my ($adata, $aname) = ($1, $2); | |
228 | if ($aname eq 'address' || $aname eq 'netmask' || | |
229 | $aname eq 'gateway' || $aname eq 'broadcast') { | |
230 | # skip | |
231 | } else { | |
1c0a5ac7 | 232 | push @{$section->{attr}}, $adata; |
55fa4e09 DM |
233 | } |
234 | next; | |
235 | } | |
1c0a5ac7 WB |
236 | |
237 | $interfaces .= "$line\n"; | |
55fa4e09 DM |
238 | } |
239 | &$print_section(); | |
55fa4e09 DM |
240 | } |
241 | ||
e90673a8 | 242 | my $need_separator = length($interfaces) && ($interfaces !~ /\n\n$/); |
55fa4e09 DM |
243 | foreach my $ifname (sort keys %$networks) { |
244 | my $net = $networks->{$ifname}; | |
1c0a5ac7 | 245 | |
fcaca113 | 246 | if (!$done_v4_hash->{$ifname} && defined($net->{address})) { |
1c0a5ac7 | 247 | if ($need_separator) { $interfaces .= "\n"; $need_separator = 0; }; |
55fa4e09 DM |
248 | $section = { type => 'ipv4', ifname => $ifname, attr => []}; |
249 | &$print_section(1); | |
250 | } | |
a1b1a247 | 251 | if (!$done_v6_hash->{$ifname} && defined($net->{address6})) { |
1c0a5ac7 | 252 | if ($need_separator) { $interfaces .= "\n"; $need_separator = 0; }; |
55fa4e09 DM |
253 | $section = { type => 'ipv6', ifname => $ifname, attr => []}; |
254 | &$print_section(1); | |
255 | } | |
256 | } | |
1c0a5ac7 | 257 | |
2063d380 | 258 | $self->ct_file_set_contents($filename, $interfaces); |
55fa4e09 | 259 | } |
1c7f4f65 DM |
260 | |
261 | 1; |