]> git.proxmox.com Git - pve-container.git/blob - src/PVE/LXC/Setup/CentOS.pm
fix #2027: do not disable IPV6_AUTOCONF on centos
[pve-container.git] / src / PVE / LXC / Setup / CentOS.pm
1 package PVE::LXC::Setup::CentOS;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6 use PVE::Tools;
7 use PVE::Network;
8 use PVE::LXC;
9
10 use PVE::LXC::Setup::Base;
11
12 use base qw(PVE::LXC::Setup::Base);
13
14 sub new {
15 my ($class, $conf, $rootdir) = @_;
16
17 my $release = PVE::Tools::file_read_firstline("$rootdir/etc/redhat-release");
18 die "unable to read version info\n" if !defined($release);
19
20 my $version;
21
22 if ($release =~ m/release\s+(\d+\.\d+)(\.\d+)?/) {
23 if ($1 >= 6 && $1 < 8) {
24 $version = $1;
25 }
26 }
27
28 die "unsupported centos release '$release'\n" if !$version;
29
30 my $self = { conf => $conf, rootdir => $rootdir, version => $version };
31
32 $conf->{ostype} = "centos";
33
34 return bless $self, $class;
35 }
36
37 my $tty_conf = <<__EOD__;
38 # tty - getty
39 #
40 # This service maintains a getty on the specified device.
41 #
42 # Do not edit this file directly. If you want to change the behaviour,
43 # please create a file tty.override and put your changes there.
44
45 stop on runlevel [S016]
46
47 respawn
48 instance \$TTY
49 exec /sbin/mingetty \$TTY
50 usage 'tty TTY=/dev/ttyX - where X is console id'
51 __EOD__
52
53 my $start_ttys_conf = <<__EOD__;
54 #
55 # This service starts the configured number of gettys.
56 #
57 # Do not edit this file directly. If you want to change the behaviour,
58 # please create a file start-ttys.override and put your changes there.
59
60 start on stopped rc RUNLEVEL=[2345]
61
62 env ACTIVE_CONSOLES=/dev/tty[1-6]
63 env X_TTY=/dev/tty1
64 task
65 script
66 . /etc/sysconfig/init
67 for tty in \$(echo \$ACTIVE_CONSOLES) ; do
68 [ "\$RUNLEVEL" = "5" -a "\$tty" = "\$X_TTY" ] && continue
69 initctl start tty TTY=\$tty
70 done
71 end script
72 __EOD__
73
74 my $power_status_changed_conf = <<__EOD__;
75 # power-status-changed - shutdown on SIGPWR
76 #
77 start on power-status-changed
78
79 exec /sbin/shutdown -h now "SIGPWR received"
80 __EOD__
81
82 sub template_fixup {
83 my ($self, $conf) = @_;
84
85 if ($self->{version} < 7) {
86 # re-create emissing files for tty
87
88 $self->ct_make_path('/etc/init');
89
90 my $filename = "/etc/init/tty.conf";
91 $self->ct_file_set_contents($filename, $tty_conf)
92 if ! $self->ct_file_exists($filename);
93
94 $filename = "/etc/init/start-ttys.conf";
95 $self->ct_file_set_contents($filename, $start_ttys_conf)
96 if ! $self->ct_file_exists($filename);
97
98 $filename = "/etc/init/power-status-changed.conf";
99 $self->ct_file_set_contents($filename, $power_status_changed_conf)
100 if ! $self->ct_file_exists($filename);
101
102 # do not start udevd
103 $filename = "/etc/rc.d/rc.sysinit";
104 my $data = $self->ct_file_get_contents($filename);
105 $data =~ s!^(/sbin/start_udev.*)$!#$1!gm;
106 $self->ct_file_set_contents($filename, $data);
107
108 # edit /etc/securetty (enable login on console)
109 $self->setup_securetty($conf);
110 }
111 }
112
113 sub setup_init {
114 my ($self, $conf) = @_;
115
116 # edit/etc/securetty
117
118 $self->setup_systemd_console($conf);
119 }
120
121 sub set_hostname {
122 my ($self, $conf) = @_;
123
124 # Redhat wants the fqdn in /etc/sysconfig/network's HOSTNAME
125 my $hostname = $conf->{hostname} || 'localhost';
126
127 my $hostname_fn = "/etc/hostname";
128 my $sysconfig_network = "/etc/sysconfig/network";
129
130 my $oldname;
131 if ($self->ct_file_exists($hostname_fn)) {
132 $oldname = $self->ct_file_read_firstline($hostname_fn) || 'localhost';
133 } else {
134 my $data = $self->ct_file_get_contents($sysconfig_network);
135 if ($data =~ m/^HOSTNAME=\s*(\S+)\s*$/m) {
136 $oldname = $1;
137 }
138 }
139
140 my ($ipv4, $ipv6) = PVE::LXC::get_primary_ips($conf);
141 my $hostip = $ipv4 || $ipv6;
142
143 my ($searchdomains) = $self->lookup_dns_conf($conf);
144
145 $self->update_etc_hosts($hostip, $oldname, $hostname, $searchdomains);
146
147 if ($self->ct_file_exists($hostname_fn)) {
148 $self->ct_file_set_contents($hostname_fn, "$hostname\n");
149 }
150
151 if ($self->ct_file_exists($sysconfig_network)) {
152 my $data = $self->ct_file_get_contents($sysconfig_network);
153 if ($data !~ s/^HOSTNAME=\h*(\S+)\h*$/HOSTNAME=$hostname/m) {
154 $data .= "HOSTNAME=$hostname\n";
155 }
156 $self->ct_file_set_contents($sysconfig_network, $data);
157 }
158 }
159
160 sub setup_network {
161 my ($self, $conf) = @_;
162
163 my ($gw, $gw6);
164
165 $self->ct_make_path('/etc/sysconfig/network-scripts');
166
167 my ($has_ipv4, $has_ipv6);
168
169 foreach my $k (keys %$conf) {
170 next if $k !~ m/^net(\d+)$/;
171 my $d = PVE::LXC::Config->parse_lxc_network($conf->{$k});
172 next if !$d->{name};
173 $has_ipv4 = 1 if defined($d->{ip});
174 $has_ipv6 = 1 if defined($d->{ip6});
175
176 my $filename = "/etc/sysconfig/network-scripts/ifcfg-$d->{name}";
177 my $routefile = "/etc/sysconfig/network-scripts/route-$d->{name}";
178 my $route6file = "/etc/sysconfig/network-scripts/route6-$d->{name}";
179 my $routes = '';
180 my $routes6 = '';
181
182 my $header = "DEVICE=$d->{name}\nONBOOT=yes\n";
183 my $data = '';
184 my $bootproto = '';
185
186 if ($d->{ip} && $d->{ip} ne 'manual') {
187 if ($d->{ip} eq 'dhcp') {
188 $bootproto = 'dhcp';
189 } else {
190 $bootproto = 'none';
191 my $ipinfo = PVE::LXC::parse_ipv4_cidr($d->{ip});
192 $data .= "IPADDR=$ipinfo->{address}\n";
193 $data .= "NETMASK=$ipinfo->{netmask}\n";
194 if (defined($d->{gw})) {
195 $data .= "GATEWAY=$d->{gw}\n";
196 if (!PVE::Network::is_ip_in_cidr($d->{gw}, $d->{ip}, 4)) {
197 $routes .= "$d->{gw} dev $d->{name}\n";
198 $routes .= "default via $d->{gw} dev $d->{name}\n";
199 }
200 }
201 }
202 }
203
204 if ($d->{ip6} && $d->{ip6} ne 'manual') {
205 $bootproto = 'none' if !$bootproto;
206 $data .= "IPV6INIT=yes\n";
207 if ($d->{ip6} eq 'auto') {
208 $data .= "IPV6_AUTOCONF=yes\n";
209 }
210 if ($d->{ip6} eq 'dhcp') {
211 $data .= "DHCPV6C=yes\n";
212 } else {
213 $data .= "IPV6ADDR=$d->{ip6}\n";
214 if (defined($d->{gw6})) {
215 if (!PVE::Network::is_ip_in_cidr($d->{gw6}, $d->{ip6}, 6) &&
216 !PVE::Network::is_ip_in_cidr($d->{gw6}, 'fe80::/10', 6)) {
217 $routes6 .= "$d->{gw6} dev $d->{name}\n";
218 $routes6 .= "default via $d->{gw6} dev $d->{name}\n";
219 } else {
220 $data .= "IPV6_DEFAULTGW=$d->{gw6}\n";
221 }
222 }
223 }
224 }
225
226 next unless $data || $bootproto;
227 $header .= "BOOTPROTO=$bootproto\n";
228 $self->ct_file_set_contents($filename, $header . $data);
229 $self->ct_modify_file($routefile, $routes, delete => 1, prepend => 1);
230 $self->ct_modify_file($route6file, $routes6, delete => 1, prepend => 1);
231 }
232
233 my $sysconfig_network = "/etc/sysconfig/network";
234 if ($self->ct_file_exists($sysconfig_network)) {
235 my $data = $self->ct_file_get_contents($sysconfig_network);
236 if ($has_ipv4) {
237 if ($data !~ s/(NETWORKING)=\S+/$1=yes/) {
238 $data .= "NETWORKING=yes\n";
239 }
240 }
241 if ($has_ipv6) {
242 if ($data !~ s/(NETWORKING_IPV6)=\S+/$1=yes/) {
243 $data .= "NETWORKING_IPV6=yes\n";
244 }
245 }
246 $self->ct_file_set_contents($sysconfig_network, $data);
247 }
248 }
249
250 1;