vmconfig_hotplug_pending is responsible for checking if a key in the pending section is hotpluggable, if yes; perform a generic config value replace or perform specific actions if a special case.
vmconfig_apply_pending is only supposed to be called when ct isn't live. Signed-off-by: Oguz Bektas <o.bek...@proxmox.com> --- src/PVE/LXC/Config.pm | 186 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 2 deletions(-) diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm index 08b958f..26c694f 100644 --- a/src/PVE/LXC/Config.pm +++ b/src/PVE/LXC/Config.pm @@ -7,11 +7,13 @@ use PVE::AbstractConfig; use PVE::Cluster qw(cfs_register_file); use PVE::GuestHelpers; use PVE::INotify; +use PVE::Exception qw(raise_param_exc); use PVE::JSONSchema qw(get_standard_option); -use PVE::Tools; +use PVE::Tools qw(extract_param); use base qw(PVE::AbstractConfig); +my $confdesc; my $nodename = PVE::INotify::nodename(); my $lock_handles = {}; my $lockdir = "/run/lock/lxc"; @@ -76,6 +78,186 @@ sub has_feature { return $err ? 0 : 1; } +my $LXC_FASTPLUG_OPTIONS= { + 'description' => 1, + 'onboot' => 1, + 'startup' => 1, + 'protection' => 1, + 'hostname' => 1, + 'hookscript' => 1, + 'cores' => 1, +}; + +sub vmconfig_hotplug_pending { + my ($class, $vmid, $conf, $storecfg, $selection, $errors) = @_; + + my $pid = PVE::LXC::find_lxc_pid($vmid); + my $rootdir = "/proc/$pid/root"; + + my $add_error = sub { + my ($opt, $msg) = @_; + $errors->{$opt} = "hotplug problem - $msg"; + }; + + my $changes; + foreach my $opt (keys %{$conf->{pending}}) { # add/change + if ($LXC_FASTPLUG_OPTIONS->{$opt}) { + $conf->{$opt} = delete $conf->{pending}->{$opt}; + $changes = 1; + } + } + + if ($changes) { + $class->write_config($vmid, $conf); + $conf = $class->load_config($vmid); # update/reload + } + + my $pending_delete_hash = $class->split_flagged_list($conf->{pending}->{delete}); + while (my ($opt, $force) = each %$pending_delete_hash) { + next if $selection && !$selection->{$opt}; + eval { + if ($LXC_FASTPLUG_OPTIONS->{$opt}) { + # pass + } elsif ($opt eq 'swap') { # TODO FIXME: unlimited swap instead of no swap + PVE::LXC::write_cgroup_value("memory", $vmid, + "memory.memsw.limit_in_bytes", -1); + } elsif ($opt eq 'cpulimit') { + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.cfs_quota_us", -1); + } elsif ($opt eq 'cpuunits') { + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.shared", $confdesc->{cpuunits}->{default}); + } elsif ($opt =~ m/^net(\d)$/) { + my $netid = $1; + PVE::Network::veth_delete("veth${vmid}i$netid"); + } else { + die "skip\n"; # skip non-hotpluggable opts + } + }; + if (my $err = $@) { + $add_error->($opt, $err) if $err ne "skip\n"; + } else { + delete $conf->{$opt}; + $class->vmconfig_undelete_pending_option($conf, $opt); + $class->write_config($vmid, $conf); + $conf = $class->load_config($vmid); # update/reload + } + } + + # There's no separate swap size to configure, there's memory and "total" + # memory (iow. memory+swap). This means we have to change them together. + my $hotplug_memory_done; + my $hotplug_memory = sub { + my ($wanted_memory, $wanted_swap) = @_; + my $old_memory = ($conf->{memory} || 512); + my $old_swap = ($conf->{swap} || 0); + + $wanted_memory //= $old_memory; + $wanted_swap //= $old_swap; + + my $total = $wanted_memory + $wanted_swap; + my $old_total = $old_memory + $old_swap; + + + if ($total > $old_total) { + PVE::LXC::write_cgroup_value("memory", $vmid, + "memory.memsw.limit_in_bytes", + int($total*1024*1024)); + PVE::LXC::write_cgroup_value("memory", $vmid, + "memory.limit_in_bytes", + int($wanted_memory*1024*1024)); + } else { + PVE::LXC::write_cgroup_value("memory", $vmid, + "memory.limit_in_bytes", + int($wanted_memory*1024*1024)); + PVE::LXC::write_cgroup_value("memory", $vmid, + "memory.memsw.limit_in_bytes", + int($total*1024*1024)); + } + $hotplug_memory_done = 1; + }; + + foreach my $opt (keys %{$conf->{pending}}) { + next if $selection && !$selection->{$opt}; + my $value = $conf->{pending}->{$opt}; + eval { + if ($LXC_FASTPLUG_OPTIONS->{$opt}) { + # pass + } elsif ($opt eq 'cpulimit') { + if ($value == 0) { + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.cfs_quota_us", -1); + } else { + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.cfs_quota_us", int(100000*$value)); + } + } elsif ($opt eq 'cpuunits') { + PVE::LXC::write_cgroup_value("cpu", $vmid, "cpu.shares", $value); + } elsif ($opt =~ m/^net(\d+)$/) { + my $netid = $1; + my $net = PVE::LXC::Config->parse_lxc_network($value); + PVE::LXC::update_net($vmid, $conf, $opt, $net, $netid, $rootdir); + } elsif ($opt eq 'memory' || $opt eq 'swap') { + if (!$hotplug_memory_done) { # don't call twice if both opts are passed + $hotplug_memory->($conf->{pending}->{memory}, $conf->{pending}->{swap}); + } + } else { + die "skip\n"; # skip non-hotpluggable + } + }; + if (my $err = $@) { + $add_error->($opt, $err) if $err ne "skip\n"; + } else { + $conf->{$opt} = $value; + delete $conf->{pending}->{$opt}; + $class->write_config($vmid, $conf); + $conf = $class->load_config($vmid); # update/reload + } + } +} + +sub vmconfig_apply_pending { + my ($class, $vmid, $conf, $storecfg) = @_; + + + my $pending_delete_hash = $class->split_flagged_list($conf->{pending}->{delete}); + while (my ($opt, $force) = each %$pending_delete_hash) { + $conf = $class->load_config($vmid); # update/reload + if (!defined($conf->{$opt})) { + $class->vmconfig_undelete_pending_option($conf, $opt); + $class->write_config($vmid, $conf); + } elsif ($opt =~ m/^mp(\d+)$/) { + my $old = $conf->{$opt}; + my $mp = PVE::LXC::Config->parse_ct_mountpoint($conf->{$opt}); + if ($mp->{type} eq 'volume') { + PVE::LXC::Config->add_unused_volume($conf, $mp->{volume}); + } + $class->vmconfig_undelete_pending_option($conf, $opt); + delete $conf->{$opt}; + $class->write_config($vmid, $conf); + } else { + $class->vmconfig_undelete_pending_option($conf, $opt); + delete $conf->{$opt}; + $class->write_config($vmid, $conf); + } + } + + $conf = $class->load_config($vmid); # update/reload + + + foreach my $opt (keys %{$conf->{pending}}) { # add/change + $conf = $class->load_config($vmid); # update/reload + my $value = $conf->{pending}->{$opt}; + + if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) { + # skip if nothing changed + } else { + $conf->{$opt} = $value; + } + + delete $conf->{pending}->{$opt}; + $class->write_config($vmid, $conf); + } + + +} + sub __snapshot_save_vmstate { my ($class, $vmid, $conf, $snapname, $storecfg) = @_; die "implement me - snapshot_save_vmstate\n"; @@ -324,7 +506,7 @@ my $features_desc = { }, }; -my $confdesc = { +$confdesc = { lock => { optional => 1, type => 'string', -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel