[pve-devel] [PATCH container 7/9] add vmconfig_hotplug_pending and vmconfig_apply_pending
Oguz Bektas
o.bektas at proxmox.com
Thu Sep 5 16:11:19 CEST 2019
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.bektas at 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
More information about the pve-devel
mailing list