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

Reply via email to