]>
Commit | Line | Data |
---|---|---|
1c7f4f65 DM |
1 | package PVE::LXCSetup::Debian; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
55fa4e09 | 5 | use Data::Dumper; |
1c7f4f65 | 6 | use PVE::Tools; |
55fa4e09 DM |
7 | use PVE::LXC; |
8 | use File::Path; | |
1c7f4f65 DM |
9 | |
10 | use PVE::LXCSetup::Base; | |
11 | ||
12 | use base qw(PVE::LXCSetup::Base); | |
13 | ||
d66768a2 DM |
14 | my $default_inittab = <<__EOD__; |
15 | ||
16 | # The default runlevel. | |
17 | id:2:initdefault: | |
18 | ||
19 | # Boot-time system configuration/initialization script. | |
20 | # This is run first except when booting in emergency (-b) mode. | |
21 | si::sysinit:/etc/init.d/rcS | |
22 | ||
23 | # /etc/init.d executes the S and K scripts upon change | |
24 | # of runlevel. | |
25 | # | |
26 | # Runlevel 0 is halt. | |
27 | # Runlevel 1 is single-user. | |
28 | # Runlevels 2-5 are multi-user. | |
29 | # Runlevel 6 is reboot. | |
30 | ||
31 | l0:0:wait:/etc/init.d/rc 0 | |
32 | l1:1:wait:/etc/init.d/rc 1 | |
33 | l2:2:wait:/etc/init.d/rc 2 | |
34 | l3:3:wait:/etc/init.d/rc 3 | |
35 | l4:4:wait:/etc/init.d/rc 4 | |
36 | l5:5:wait:/etc/init.d/rc 5 | |
37 | l6:6:wait:/etc/init.d/rc 6 | |
38 | # Normally not reached, but fallthrough in case of emergency. | |
39 | z6:6:respawn:/sbin/sulogin | |
40 | ||
41 | # What to do when CTRL-ALT-DEL is pressed. | |
42 | ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now | |
43 | ||
44 | # What to do when the power fails/returns. | |
45 | p0::powerfail:/sbin/init 0 | |
46 | ||
47 | # /sbin/getty invocations for the runlevels. | |
48 | # | |
49 | # The "id" field MUST be the same as the last | |
50 | # characters of the device (after "tty"). | |
51 | # | |
52 | # Format: | |
53 | # <id>:<runlevels>:<action>:<process> | |
54 | # | |
55 | __EOD__ | |
56 | ||
57 | sub setup_init { | |
58 | my ($class, $conf) = @_; | |
59 | ||
60 | my $rootfs = $conf->{'lxc.rootfs'}; | |
61 | ||
62 | my $filename = "$rootfs/etc/inittab"; | |
63 | ||
64 | if (-f $filename) { | |
65 | my $inittab = $default_inittab; | |
66 | ||
67 | my $ttycount = defined($conf->{'lxc.tty'}) ? $conf->{'lxc.tty'} : 4; | |
68 | for (my $i = 1; $i <= $ttycount; $i++) { | |
69 | next if $i == 7; # reserved for X11 | |
70 | my $levels = ($i == 1) ? '2345' : '23'; | |
71 | $inittab .= "$i:$levels:respawn:/sbin/getty --noclear 38400 tty$i\n"; | |
72 | } | |
73 | ||
74 | PVE::Tools::file_set_contents($filename, $inittab); | |
75 | } | |
76 | } | |
77 | ||
55fa4e09 DM |
78 | sub setup_network { |
79 | my ($class, $conf) = @_; | |
80 | ||
81 | my $rootfs = $conf->{'lxc.rootfs'}; | |
82 | ||
83 | my $networks = {}; | |
84 | foreach my $k (keys %$conf) { | |
85 | next if $k !~ m/^net(\d+)$/; | |
93285df8 | 86 | my $ind = $1; |
55fa4e09 DM |
87 | my $d = $conf->{$k}; |
88 | if ($d->{name}) { | |
89 | my $net = {}; | |
93285df8 DM |
90 | if (defined($d->{ip})) { |
91 | my $ipinfo = PVE::LXC::parse_ipv4_cidr($d->{ip}); | |
55fa4e09 DM |
92 | $net->{v4address} = $ipinfo->{address}; |
93 | $net->{v4netmask} = $ipinfo->{netmask}; | |
94 | } | |
93285df8 DM |
95 | if (defined($d->{'gw'})) { |
96 | $net->{v4gateway} = $d->{'gw'}; | |
55fa4e09 | 97 | } |
93285df8 | 98 | if (defined($d->{ip6})) { |
55fa4e09 DM |
99 | die "implement me"; |
100 | } | |
101 | $networks->{$d->{name}} = $net; | |
102 | } | |
103 | } | |
104 | ||
93285df8 | 105 | return if !scalar(keys %$networks); |
55fa4e09 DM |
106 | |
107 | my $filename = "$rootfs/etc/network/interfaces"; | |
108 | my $data = {}; | |
109 | my $order = []; | |
110 | my $interfaces = ""; | |
111 | ||
112 | my $section; | |
113 | ||
114 | my $done_v4_hash = {}; | |
115 | my $done_v6_hash = {}; | |
116 | ||
117 | my $print_section = sub { | |
118 | my ($new) = @_; | |
119 | ||
120 | return if !$section; | |
121 | ||
122 | my $net = $networks->{$section->{ifname}}; | |
123 | ||
124 | if ($section->{type} eq 'ipv4') { | |
125 | $done_v4_hash->{$section->{ifname}} = 1; | |
126 | ||
127 | $interfaces .= "auto $section->{ifname}\n" if $new; | |
128 | ||
129 | if ($net->{v4address}) { | |
130 | $interfaces .= "iface $section->{ifname} inet static\n"; | |
131 | $interfaces .= "\taddress $net->{v4address}\n" if defined($net->{v4address}); | |
132 | $interfaces .= "\tnetmask $net->{v4netmask}\n" if defined($net->{v4netmask}); | |
93285df8 | 133 | $interfaces .= "\tgateway $net->{v4gateway}\n" if defined($net->{v4gateway}); |
55fa4e09 DM |
134 | foreach my $attr (@{$section->{attr}}) { |
135 | $interfaces .= "\t$attr\n"; | |
136 | } | |
137 | } else { | |
138 | $interfaces .= "iface $section->{ifname} inet manual\n"; | |
139 | } | |
140 | ||
141 | $interfaces .= "\n"; | |
142 | ||
143 | } elsif ($section->{type} eq 'ipv6') { | |
144 | $done_v6_hash->{$section->{ifname}} = 1; | |
145 | ||
146 | if ($net->{v6address}) { | |
147 | $interfaces .= "iface $section->{ifname} inet6 static\n"; | |
148 | $interfaces .= "\taddress $net->{v6address}\n" if defined($net->{v6address}); | |
149 | $interfaces .= "\tnetmask $net->{v6netmask}\n" if defined($net->{v6netmask}); | |
93285df8 | 150 | $interfaces .= "\tgateway $net->{v6gateway}\n" if defined($net->{v6gateway}); |
55fa4e09 DM |
151 | foreach my $attr (@{$section->{attr}}) { |
152 | $interfaces .= "\t$attr\n"; | |
153 | } | |
154 | } | |
155 | ||
156 | $interfaces .= "\n"; | |
157 | } else { | |
158 | die "unknown section type '$section->{type}'"; | |
159 | } | |
160 | ||
161 | $section = undef; | |
162 | }; | |
163 | ||
164 | if (my $fh = IO::File->new($filename, "r")) { | |
165 | while (defined (my $line = <$fh>)) { | |
166 | chomp $line; | |
167 | if ($line =~ m/^#/) { | |
168 | $interfaces .= "$line\n"; | |
169 | next; | |
170 | } | |
171 | if ($line =~ m/^\s*$/) { | |
172 | if ($section) { | |
173 | &$print_section(); | |
174 | } else { | |
175 | $interfaces .= "$line\n"; | |
176 | } | |
177 | next; | |
178 | } | |
179 | if ($line =~ m/^iface\s+(\S+)\s+inet\s+(\S+)\s*$/) { | |
180 | my $ifname = $1; | |
181 | if (!$networks->{$ifname}) { | |
182 | $interfaces .= "$line\n"; | |
183 | next; | |
184 | } | |
185 | $section = { type => 'ipv4', ifname => $ifname, attr => []}; | |
186 | next; | |
187 | } | |
188 | if ($line =~ m/^iface\s+(\S+)\s+inet6\s+(\S+)\s*$/) { | |
189 | my $ifname = $1; | |
190 | if (!$networks->{$ifname}) { | |
191 | $interfaces .= "$line\n"; | |
192 | next; | |
193 | } | |
194 | $section = { type => 'ipv6', ifname => $ifname, attr => []}; | |
195 | next; | |
196 | } | |
197 | if ($section && $line =~ m/^\s*((\S+)\s(.*))$/) { | |
198 | my ($adata, $aname) = ($1, $2); | |
199 | if ($aname eq 'address' || $aname eq 'netmask' || | |
200 | $aname eq 'gateway' || $aname eq 'broadcast') { | |
201 | # skip | |
202 | } else { | |
203 | push @{$section->{attr}}, $adata; | |
204 | } | |
205 | next; | |
206 | } | |
207 | ||
208 | $interfaces .= "$line\n"; | |
209 | } | |
210 | &$print_section(); | |
211 | ||
212 | } | |
213 | ||
93285df8 | 214 | my $need_separator = 1; |
55fa4e09 DM |
215 | foreach my $ifname (sort keys %$networks) { |
216 | my $net = $networks->{$ifname}; | |
93285df8 | 217 | |
55fa4e09 | 218 | if (!$done_v4_hash->{$ifname}) { |
93285df8 | 219 | if ($need_separator) { $interfaces .= "\n"; $need_separator = 0; }; |
55fa4e09 DM |
220 | $section = { type => 'ipv4', ifname => $ifname, attr => []}; |
221 | &$print_section(1); | |
222 | } | |
223 | if (!$done_v6_hash->{$ifname} && defined($net->{v6address})) { | |
93285df8 | 224 | if ($need_separator) { $interfaces .= "\n"; $need_separator = 0; }; |
55fa4e09 DM |
225 | $section = { type => 'ipv6', ifname => $ifname, attr => []}; |
226 | &$print_section(1); | |
227 | } | |
228 | } | |
229 | ||
230 | PVE::Tools::file_set_contents($filename, $interfaces); | |
231 | } | |
1c7f4f65 DM |
232 | |
233 | 1; |