]> git.proxmox.com Git - pve-container.git/blobdiff - src/lxc-pve-prestart-hook
prestart hook: avoid variable declared in conditional statement
[pve-container.git] / src / lxc-pve-prestart-hook
index 1d62f3bdfb07f8d1b7eba97e88bbda67b114d53f..3bdf7e4bd67e92e510dca9919e2cada1bc5af98e 100755 (executable)
@@ -9,24 +9,39 @@ use Fcntl qw(O_DIRECTORY :mode);
 use File::Path;
 use POSIX;
 
+use PVE::CGroup;
 use PVE::Cluster;
 use PVE::LXC::Config;
 use PVE::LXC::Setup;
 use PVE::LXC::Tools;
 use PVE::LXC;
+use PVE::RESTEnvironment;
+use PVE::SafeSyslog;
 use PVE::Storage;
 use PVE::Syscall qw(:fsmount);
 use PVE::Tools qw(AT_FDCWD O_PATH);
 
+my $WARNFD;
+sub log_warn {
+    my ($vmid, $message) = @_;
+
+    if (!defined($WARNFD)) {
+       open($WARNFD, '>', "/run/pve/ct-${vmid}.warnings");
+    }
+    print $WARNFD "$message\n";
+}
+
 PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub {
     my ($vmid, $vars, undef, undef) = @_;
 
     my $skiplock_flag_fn = "/run/lxc/skiplock-$vmid";
-    my $skiplock = 1 if -e $skiplock_flag_fn;
+    my $skiplock = -e $skiplock_flag_fn;
     unlink $skiplock_flag_fn if $skiplock;
 
     PVE::Cluster::check_cfs_quorum(); # only start if we have quorum
 
+    PVE::RESTEnvironment->setup_default_cli_env();
+
     return undef if ! -f PVE::LXC::Config->config_file($vmid);
 
     my $conf = PVE::LXC::Config->load_config($vmid);
@@ -34,12 +49,9 @@ PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub {
        PVE::LXC::Config->check_lock($conf);
     }
 
-    my $storage_cfg = PVE::Storage::config();
-
-    my $vollist = PVE::LXC::Config->get_vm_volumes($conf);
-    my $loopdevlist = PVE::LXC::Config->get_vm_volumes($conf, 'rootfs');
+    cleanup_cgroups($vmid);
 
-    PVE::Storage::activate_volumes($storage_cfg, $vollist);
+    my $storage_cfg = PVE::Storage::config();
 
     my $rootdir = $vars->{ROOTFS_PATH};
 
@@ -123,11 +135,19 @@ PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub {
        };
     }
 
-    PVE::LXC::Config->foreach_mountpoint($conf, $setup_mountpoint);
+    PVE::LXC::Config->foreach_volume($conf, $setup_mountpoint);
 
     my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir);
     $lxc_setup->pre_start_hook();
 
+    if (PVE::CGroup::cgroup_mode() == 2) {
+       if (!$lxc_setup->unified_cgroupv2_support()) {
+           log_warn($vmid, "old systemd (< v232) detected, container won't run in a pure cgroupv2"
+               ." environment! Please see documentation -> container -> cgroup version.");
+           syslog('err', "CT $vmid does not support running in a pure cgroupv2 environment\n");
+       }
+    }
+
     if (@$devices) {
        my $devlist = '';
        foreach my $dev (@$devices) {
@@ -140,3 +160,50 @@ PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub {
        PVE::Tools::file_set_contents($devlist_file, $devlist);
     }
 });
+
+# Leftover cgroups prevent lxc from starting without any useful information
+# showing up in the journal, it is also often unable to properly clean them up
+# at shutdown, so we do this here.
+sub cleanup_cgroups($) {
+    my ($vmid) = @_;
+
+    if (PVE::CGroup::cgroup_mode() == 2) {
+       rmdir_recursive("/sys/fs/cgroup/lxc/$vmid");
+       rmdir_recursive("/sys/fs/cgroup/lxc.monitor/$vmid");
+    } else {
+       my ($v1, $v2) = PVE::CGroup::get_cgroup_controllers();
+
+       my @controllers_cgv1 = keys %$v1;
+       foreach my $controller (@controllers_cgv1) {
+           $controller =~ s/^name=//; # `name=systemd` is mounted just as `systemd`
+           rmdir_recursive("/sys/fs/cgroup/$controller/lxc/$vmid");
+           rmdir_recursive("/sys/fs/cgroup/$controller/lxc.monitor/$vmid");
+       }
+
+       if ($v2) {
+           rmdir_recursive("/sys/fs/cgroup/unified/lxc/$vmid");
+           rmdir_recursive("/sys/fs/cgroup/unified/lxc.monitor/$vmid");
+       }
+    }
+}
+
+# FIXME: This is an ugly version without openat() because perl has no equivalent
+# of fdopendir() so we cannot readdir from an openat() opened handle.
+sub rmdir_recursive {
+    my ($path) = @_;
+
+    my $dh;
+    if (!opendir($dh, $path)) {
+       return if $!{ENOENT};
+       die "failed to open directory '$path': $!\n";
+    }
+
+    while (defined(my $entry = readdir($dh))) {
+       next if $entry eq '.' || $entry eq '..';
+       my $next = "$path/$entry";
+       next if ! -d $next;
+       rmdir_recursive($next);
+    }
+
+    rmdir($path) or die "failed to remove directory '$path': $!\n";
+}