We now get rid of all the PVE::CLIHandler baggage which reduces the code a lot. It is also not compatible with the new lxc.hook.version=1 method of hooks!
The new helper is specific to lxc hooks and supports both current `lxc.hook.version`s. Signed-off-by: Wolfgang Bumiller <w.bumil...@proxmox.com> --- src/lxc-pve-autodev-hook | 136 +++++++++++++++----------------- src/lxc-pve-poststop-hook | 154 ++++++++++++------------------------ src/lxc-pve-prestart-hook | 161 ++++++++++++-------------------------- 3 files changed, 166 insertions(+), 285 deletions(-) diff --git a/src/lxc-pve-autodev-hook b/src/lxc-pve-autodev-hook index c934bfd..4913870 100755 --- a/src/lxc-pve-autodev-hook +++ b/src/lxc-pve-autodev-hook @@ -3,89 +3,81 @@ use strict; use warnings; -exit 0 if $ENV{LXC_NAME} && $ENV{LXC_NAME} !~ /^\d+$/; - use File::Path; use File::Basename; +use PVE::LXC::Tools; use PVE::Tools; -my $vmid = $ENV{LXC_NAME}; -my $root = $ENV{LXC_ROOTFS_MOUNT}; - -if (@ARGV != 3 || $ARGV[1] ne 'lxc' || $ARGV[2] ne 'autodev') { - die "invalid usage, this is an LXC autodev hook\n"; -} - -if ($vmid ne $ARGV[0]) { - die "got wrong name: $ARGV[0] while LXC_NAME=$vmid\n"; -} - -my $devlist_file = "/var/lib/lxc/$vmid/devices"; -my $fd; +PVE::LXC::Tools::lxc_hook('autodev', 'lxc', sub { + my ($vmid, $vars, undef, undef) = @_; -if (! open $fd, '<', $devlist_file) { - exit 0 if $!{ENOENT}; # If the list is empty the file might not exist. - die "failed to open device list: $!\n"; -} + my $root = $vars->{ROOTFS_MOUNT}; -sub cgroup_do_write($$) { - my ($path, $value) = @_; + my $devlist_file = "/var/lib/lxc/$vmid/devices"; my $fd; - if (!open($fd, '>', $path)) { - warn "failed to open cgroup file $path: $!\n"; - return 0; - } - if (!defined syswrite($fd, $value)) { - warn "failed to write value $value to cgroup file $path: $!\n"; - return 0; - } - close($fd); - return 1; -} - -while (defined(my $line = <$fd>)) { - if ($line !~ m@^(b):(\d+):(\d+):/dev/(\S+)\s*$@) { - warn "invalid .pve-devices entry: $line\n"; - } - my ($type, $major, $minor, $dev) = ($1, $2, $3, $4); - # Don't break out of $root/dev/ - if ($dev =~ /\.\./) { - warn "skipping illegal device node entry: $dev\n"; - next; + if (! open $fd, '<', $devlist_file) { + exit 0 if $!{ENOENT}; # If the list is empty the file might not exist. + die "failed to open device list: $!\n"; } - # Never expose /dev/loop-control - if ($major == 10 && $minor == 237) { - warn "skipping illegal device entry (loop-control) for: $dev\n"; - next; + sub cgroup_do_write($$) { + my ($path, $value) = @_; + my $fd; + if (!open($fd, '>', $path)) { + warn "failed to open cgroup file $path: $!\n"; + return 0; + } + if (!defined syswrite($fd, $value)) { + warn "failed to write value $value to cgroup file $path: $!\n"; + return 0; + } + close($fd); + return 1; } - my $rel_devpath = "/dev/$dev"; - my $rel_dir = dirname($rel_devpath); - File::Path::mkpath("$root/$rel_dir"); - - PVE::Tools::run_command(['mknod', '-m', '666', "$root/dev/$dev", - $type, $major, $minor]); - - if ($dev =~ /^dm-\d+$/) { - File::Path::mkpath("$root/dev/mapper"); - my $mapped_name = PVE::Tools::file_get_contents("/sys/block/$dev/dm/name"); - chomp $mapped_name; - symlink("/dev/$dev", "$root/dev/mapper/$mapped_name"); + while (defined(my $line = <$fd>)) { + if ($line !~ m@^(b):(\d+):(\d+):/dev/(\S+)\s*$@) { + warn "invalid .pve-devices entry: $line\n"; + } + my ($type, $major, $minor, $dev) = ($1, $2, $3, $4); + + # Don't break out of $root/dev/ + if ($dev =~ /\.\./) { + warn "skipping illegal device node entry: $dev\n"; + next; + } + + # Never expose /dev/loop-control + if ($major == 10 && $minor == 237) { + warn "skipping illegal device entry (loop-control) for: $dev\n"; + next; + } + + my $rel_devpath = "/dev/$dev"; + my $rel_dir = dirname($rel_devpath); + File::Path::mkpath("$root/$rel_dir"); + + PVE::Tools::run_command(['mknod', '-m', '666', "$root/dev/$dev", + $type, $major, $minor]); + + if ($dev =~ /^dm-\d+$/) { + File::Path::mkpath("$root/dev/mapper"); + my $mapped_name = PVE::Tools::file_get_contents("/sys/block/$dev/dm/name"); + chomp $mapped_name; + symlink("/dev/$dev", "$root/dev/mapper/$mapped_name"); + } + + my $cgbase = "/sys/fs/cgroup/devices/lxc/$vmid"; + my $limitpath = "$cgbase/devices.allow"; + my $nspath = "$cgbase/ns/devices.allow"; + if (!cgroup_do_write($limitpath, "$type $major:$minor rwm")) { + warn "failed to allow access to device $dev ($major:$minor)\n"; + } + if (!cgroup_do_write($nspath, "$type $major:$minor rwm")) { + warn "failed to allow access to device $dev ($major:$minor) inside the namespace\n"; + } } - - my $cgbase = "/sys/fs/cgroup/devices/lxc/$vmid"; - my $limitpath = "$cgbase/devices.allow"; - my $nspath = "$cgbase/ns/devices.allow"; - if (!cgroup_do_write($limitpath, "$type $major:$minor rwm")) { - warn "failed to allow access to device $dev ($major:$minor)\n"; - } - if (!cgroup_do_write($nspath, "$type $major:$minor rwm")) { - warn "failed to allow access to device $dev ($major:$minor) inside the namespace\n"; - } -} -close $fd; - -exit 0; + close $fd; +}); diff --git a/src/lxc-pve-poststop-hook b/src/lxc-pve-poststop-hook index 00bd0b3..19d0b52 100755 --- a/src/lxc-pve-poststop-hook +++ b/src/lxc-pve-poststop-hook @@ -1,114 +1,60 @@ #!/usr/bin/perl -package lxc_pve_poststop_hook; - use strict; use warnings; -exit 0 if $ENV{LXC_NAME} && $ENV{LXC_NAME} !~ /^\d+$/; - use POSIX; use File::Path; -use PVE::SafeSyslog; -use PVE::Tools; -use PVE::Cluster; -use PVE::INotify; -use PVE::RPCEnvironment; -use PVE::JSONSchema qw(get_standard_option); -use PVE::CLIHandler; -use PVE::Storage; -use PVE::Storage::Plugin; -use PVE::LXC; use PVE::GuestHelpers; +use PVE::LXC::Config; +use PVE::LXC::Tools; +use PVE::LXC; +use PVE::Network; +use PVE::Storage; +use PVE::Tools; -use base qw(PVE::CLIHandler); - -__PACKAGE__->register_method ({ - name => 'lxc-pve-poststop-hook', - path => 'lxc-pve-poststop-hook', - method => 'GET', - description => "vm_stop_cleanup.", - parameters => { - additionalProperties => 0, - properties => { - name => { - description => "The container name. This hook is only active for containers using numeric IDs, where configuration is stored on /etc/pve/lxc/<name>.conf (else it is just a NOP).", - type => 'string', - pattern => '\S+', - maxLength => 64, - } - }, - }, - returns => { type => 'null' }, - - code => sub { - my ($param) = @_; - - return undef if $param->{name} !~ m/^\d+$/; - - my $vmid = $param->{name}; - - return undef if ! -f PVE::LXC::Config->config_file($vmid); - - my $conf = PVE::LXC::Config->load_config($vmid); - - my $storage_cfg = PVE::Storage::config(); - - PVE::LXC::vm_stop_cleanup($storage_cfg, $vmid, $conf); - - my $rootfs = $ENV{LXC_ROOTFS_PATH}; - die "Missing container root directory!\n" if !$rootfs; - PVE::Tools::run_command(['umount', '--recursive', $rootfs]); - - # Because netlink is not a reliable protocol it can happen that lxc's - # link-deletion messages get lost (or end up being too early?) - for my $k (keys %$conf) { - next if $k !~ /^net(\d+)/; - my $ind = $1; - my $net = PVE::LXC::Config->parse_lxc_network($conf->{$k}); - next if $net->{type} ne 'veth'; - # veth_delete tests with '-d /sys/class/net/$name' before running the command - PVE::Network::veth_delete("veth${vmid}i$ind"); - } - - my $target = $ENV{LXC_TARGET}; - if ($target && $target eq 'reboot') { - # In order to make sure hot-plugged config changes aren't reverted - # to what the monitor initially loaded we need to stop the container - # and restart it. - # Update the config and queue a restart of the pve-container@$vmid - # task, note that we must not block because we're part of the - # service cgroup systemd waits for to die before issuing the new - # lxc-start command. - PVE::LXC::update_lxc_config($vmid, $conf); - # Tell the post-stop hook we want to be restarted. - open(my $fh, '>', "/var/lib/lxc/$vmid/reboot") - or die "failed to create reboot trigger file: $!\n"; - close($fh); - # cause lxc to stop instead of rebooting - exit(1); - } - - PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-stop'); - - return undef; - }}); - - -push @ARGV, 'help' if !scalar(@ARGV); - -my $param = {}; - -if ((scalar(@ARGV) == 3) && ($ARGV[1] eq 'lxc') && ($ARGV[2] eq 'post-stop')) { - $param->{name} = $ENV{'LXC_NAME'}; - die "got wrong name" if $param->{name} ne $ARGV[0]; - - @ARGV = (); -} else { - @ARGV = ('help'); -} - -our $cmddef = [ __PACKAGE__, 'lxc-pve-poststop-hook', [], $param]; - -__PACKAGE__->run_cli_handler(); +PVE::LXC::Tools::lxc_hook('post-stop', 'lxc', sub { + my ($vmid, $vars, undef, undef) = @_; + + return undef if ! -f PVE::LXC::Config->config_file($vmid); + + my $conf = PVE::LXC::Config->load_config($vmid); + + my $storage_cfg = PVE::Storage::config(); + + PVE::LXC::vm_stop_cleanup($storage_cfg, $vmid, $conf); + + PVE::Tools::run_command(['umount', '--recursive', $vars->{ROOTFS_PATH}]); + + # Because netlink is not a reliable protocol it can happen that lxc's + # link-deletion messages get lost (or end up being too early?) + for my $k (keys %$conf) { + next if $k !~ /^net(\d+)/; + my $ind = $1; + my $net = PVE::LXC::Config->parse_lxc_network($conf->{$k}); + next if $net->{type} ne 'veth'; + # veth_delete tests with '-d /sys/class/net/$name' before running the command + PVE::Network::veth_delete("veth${vmid}i$ind"); + } + + my $target = $vars->{TARGET}; + if ($target && $target eq 'reboot') { + # In order to make sure hot-plugged config changes aren't reverted + # to what the monitor initially loaded we need to stop the container + # and restart it. + # Update the config and queue a restart of the pve-container@$vmid + # task, note that we must not block because we're part of the + # service cgroup systemd waits for to die before issuing the new + # lxc-start command. + PVE::LXC::update_lxc_config($vmid, $conf); + # Tell the post-stop hook we want to be restarted. + open(my $fh, '>', "/var/lib/lxc/$vmid/reboot") + or die "failed to create reboot trigger file: $!\n"; + close($fh); + # cause lxc to stop instead of rebooting + exit(1); + } + + PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-stop'); +}); diff --git a/src/lxc-pve-prestart-hook b/src/lxc-pve-prestart-hook index 18b60cf..c0965ab 100755 --- a/src/lxc-pve-prestart-hook +++ b/src/lxc-pve-prestart-hook @@ -5,136 +5,79 @@ package lxc_pve_prestart_hook; use strict; use warnings; -exit 0 if $ENV{LXC_NAME} && $ENV{LXC_NAME} !~ /^\d+$/; - use POSIX; use File::Path; use Fcntl ':mode'; -use PVE::SafeSyslog; -use PVE::Tools; use PVE::Cluster; -use PVE::INotify; -use PVE::RPCEnvironment; -use PVE::JSONSchema qw(get_standard_option); -use PVE::CLIHandler; -use PVE::Storage; -use PVE::LXC; +use PVE::LXC::Config; use PVE::LXC::Setup; +use PVE::LXC::Tools; +use PVE::LXC; +use PVE::Storage; +use PVE::Tools; -use base qw(PVE::CLIHandler); - -__PACKAGE__->register_method ({ - name => 'lxc-pve-prestart-hook', - path => 'lxc-pve-prestart-hook', - method => 'GET', - description => "Create a new container root directory.", - parameters => { - additionalProperties => 0, - properties => { - name => { - description => "The container name. This hook is only active for containers using numeric IDs, where configuration is stored on /etc/pve/lxc/<name>.conf (else it is just a NOP).", - type => 'string', - pattern => '\S+', - maxLength => 64, - }, - path => { - description => "The path to the container configuration directory (LXC internal argument - do not pass manually!).", - type => 'string', - }, - rootfs => { - description => "The path to the container's rootfs (LXC internal argument - do not pass manually!)", - type => 'string', - }, - }, - }, - returns => { type => 'null' }, - - code => sub { - my ($param) = @_; - - return undef if $param->{name} !~ m/^\d+$/; - - my $vmid = $param->{name}; - my $skiplock_flag_fn = "/run/lxc/skiplock-$vmid"; - my $skiplock = 1 if -e $skiplock_flag_fn; - unlink $skiplock_flag_fn if $skiplock; - - PVE::Cluster::check_cfs_quorum(); # only start if we have quorum - - return undef if ! -f PVE::LXC::Config->config_file($vmid); - - my $conf = PVE::LXC::Config->load_config($vmid); - if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { - 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'); - - PVE::Storage::activate_volumes($storage_cfg, $vollist); +PVE::LXC::Tools::lxc_hook('pre-start', 'lxc', sub { + my ($vmid, $vars, undef, undef) = @_; - my $rootdir = $param->{rootfs}; + my $skiplock_flag_fn = "/run/lxc/skiplock-$vmid"; + my $skiplock = 1 if -e $skiplock_flag_fn; + unlink $skiplock_flag_fn if $skiplock; - # Delete any leftover reboot-trigger file - unlink("/var/lib/lxc/$vmid/reboot"); + PVE::Cluster::check_cfs_quorum(); # only start if we have quorum - my $devlist_file = "/var/lib/lxc/$vmid/devices"; - unlink $devlist_file; - my $devices = []; + return undef if ! -f PVE::LXC::Config->config_file($vmid); - my (undef, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf); + my $conf = PVE::LXC::Config->load_config($vmid); + if (!$skiplock && !PVE::LXC::Config->has_lock($conf, 'mounted')) { + PVE::LXC::Config->check_lock($conf); + } - my $setup_mountpoint = sub { - my ($ms, $mountpoint) = @_; + my $storage_cfg = PVE::Storage::config(); - #return if $ms eq 'rootfs'; - my (undef, undef, $dev) = PVE::LXC::mountpoint_mount($mountpoint, $rootdir, $storage_cfg, undef, $rootuid, $rootgid); - push @$devices, $dev if $dev && $mountpoint->{quota}; - }; + my $vollist = PVE::LXC::Config->get_vm_volumes($conf); + my $loopdevlist = PVE::LXC::Config->get_vm_volumes($conf, 'rootfs'); - # Unmount first when the user mounted the container with "pct mount". - eval { - PVE::Tools::run_command(['umount', '--recursive', $rootdir], outfunc => sub {}, errfunc => sub {}); - }; + PVE::Storage::activate_volumes($storage_cfg, $vollist); - PVE::LXC::Config->foreach_mountpoint($conf, $setup_mountpoint); + my $rootdir = $vars->{ROOTFS_PATH}; - my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); - $lxc_setup->pre_start_hook(); + # Delete any leftover reboot-trigger file + unlink("/var/lib/lxc/$vmid/reboot"); - if (@$devices) { - my $devlist = ''; - foreach my $dev (@$devices) { - my ($mode, $rdev) = (stat($dev))[2,6]; - next if !$mode || !S_ISBLK($mode) || !$rdev; - my $major = PVE::Tools::dev_t_major($rdev); - my $minor = PVE::Tools::dev_t_minor($rdev); - $devlist .= "b:$major:$minor:$dev\n"; - } - PVE::Tools::file_set_contents($devlist_file, $devlist); - } - return undef; - }}); + my $devlist_file = "/var/lib/lxc/$vmid/devices"; + unlink $devlist_file; + my $devices = []; + my (undef, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf); -push @ARGV, 'help' if !scalar(@ARGV); + my $setup_mountpoint = sub { + my ($ms, $mountpoint) = @_; -my $param = {}; + #return if $ms eq 'rootfs'; + my (undef, undef, $dev) = PVE::LXC::mountpoint_mount($mountpoint, $rootdir, $storage_cfg, undef, $rootuid, $rootgid); + push @$devices, $dev if $dev && $mountpoint->{quota}; + }; -if ((scalar(@ARGV) == 3) && ($ARGV[1] eq 'lxc') && ($ARGV[2] eq 'pre-start')) { - $param->{name} = $ENV{'LXC_NAME'}; - die "got wrong name" if $param->{name} ne $ARGV[0]; + # Unmount first when the user mounted the container with "pct mount". + eval { + PVE::Tools::run_command(['umount', '--recursive', $rootdir], outfunc => sub {}, errfunc => sub {}); + }; - $param->{path} = $ENV{'LXC_CONFIG_FILE'}; - $param->{rootfs} = $ENV{'LXC_ROOTFS_PATH'}; - @ARGV = (); -} else { - @ARGV = ('help'); -} + PVE::LXC::Config->foreach_mountpoint($conf, $setup_mountpoint); -our $cmddef = [ __PACKAGE__, 'lxc-pve-prestart-hook', [], $param]; + my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir); + $lxc_setup->pre_start_hook(); -__PACKAGE__->run_cli_handler(); + if (@$devices) { + my $devlist = ''; + foreach my $dev (@$devices) { + my ($mode, $rdev) = (stat($dev))[2,6]; + next if !$mode || !S_ISBLK($mode) || !$rdev; + my $major = PVE::Tools::dev_t_major($rdev); + my $minor = PVE::Tools::dev_t_minor($rdev); + $devlist .= "b:$major:$minor:$dev\n"; + } + PVE::Tools::file_set_contents($devlist_file, $devlist); + } +}); -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel