we now inherit these from AbstractConfig, so they need to be
defined/overwritten in QemuConfig instead of QemuServer.

Signed-off-by: Oguz Bektas <o.bek...@proxmox.com>
---

this patch requires my previous patch from pve-guest-common.
everything should work the same as before when both patches are applied.


 PVE/API2/Qemu.pm             |  20 +--
 PVE/QemuConfig.pm            | 233 ++++++++++++++++++++++++++
 PVE/QemuServer.pm            | 306 +----------------------------------
 PVE/QemuServer/ImportDisk.pm |   4 +-
 4 files changed, 250 insertions(+), 313 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index b30931d..2958d8a 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -885,7 +885,7 @@ __PACKAGE__->register_method({
                next if ref($value); # just to be sure
                $conf->{$opt} = $value;
            }
-           my $pending_delete_hash = 
PVE::QemuServer::split_flagged_list($conf->{pending}->{delete});
+           my $pending_delete_hash = 
PVE::QemuConfig->split_flagged_list($conf->{pending}->{delete});
            foreach my $opt (keys %$pending_delete_hash) {
                delete $conf->{$opt} if $conf->{$opt};
            }
@@ -952,7 +952,7 @@ __PACKAGE__->register_method({
 
        my $conf = PVE::QemuConfig->load_config($param->{vmid});
 
-       my $pending_delete_hash = 
PVE::QemuServer::split_flagged_list($conf->{pending}->{delete});
+       my $pending_delete_hash = 
PVE::QemuConfig->split_flagged_list($conf->{pending}->{delete});
 
        my $res = [];
 
@@ -1199,7 +1199,7 @@ my $update_vm_api  = sub {
                    $rpcenv->check_vm_perm($authuser, $vmid, undef, 
['VM.Config.Disk']);
                    PVE::QemuServer::vmconfig_register_unused_drive($storecfg, 
$vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
                        if defined($conf->{pending}->{$opt});
-                   PVE::QemuServer::vmconfig_delete_pending_option($conf, 
$opt, $force);
+                   PVE::QemuConfig->vmconfig_delete_pending_option($conf, 
$opt, $force);
                    PVE::QemuConfig->write_config($vmid, $conf);
                } elsif ($opt =~ m/^serial\d+$/) {
                    if ($conf->{$opt} eq 'socket') {
@@ -1207,7 +1207,7 @@ my $update_vm_api  = sub {
                    } elsif ($authuser ne 'root@pam') {
                        die "only root can delete '$opt' config for real 
devices\n";
                    }
-                   PVE::QemuServer::vmconfig_delete_pending_option($conf, 
$opt, $force);
+                   PVE::QemuConfig->vmconfig_delete_pending_option($conf, 
$opt, $force);
                    PVE::QemuConfig->write_config($vmid, $conf);
                } elsif ($opt =~ m/^usb\d+$/) {
                    if ($conf->{$opt} =~ m/spice/) {
@@ -1215,10 +1215,10 @@ my $update_vm_api  = sub {
                    } elsif ($authuser ne 'root@pam') {
                        die "only root can delete '$opt' config for real 
devices\n";
                    }
-                   PVE::QemuServer::vmconfig_delete_pending_option($conf, 
$opt, $force);
+                   PVE::QemuConfig->vmconfig_delete_pending_option($conf, 
$opt, $force);
                    PVE::QemuConfig->write_config($vmid, $conf);
                } else {
-                   PVE::QemuServer::vmconfig_delete_pending_option($conf, 
$opt, $force);
+                   PVE::QemuConfig->vmconfig_delete_pending_option($conf, 
$opt, $force);
                    PVE::QemuConfig->write_config($vmid, $conf);
                }
            }
@@ -1259,13 +1259,13 @@ my $update_vm_api  = sub {
                } else {
                    $conf->{pending}->{$opt} = $param->{$opt};
                }
-               PVE::QemuServer::vmconfig_undelete_pending_option($conf, $opt);
+               PVE::QemuConfig->vmconfig_undelete_pending_option($conf, $opt);
                PVE::QemuConfig->write_config($vmid, $conf);
            }
 
            # remove pending changes when nothing changed
            $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-           my $changes = PVE::QemuServer::vmconfig_cleanup_pending($conf);
+           my $changes = PVE::QemuConfig->vmconfig_cleanup_pending($conf);
            PVE::QemuConfig->write_config($vmid, $conf) if $changes;
 
            return if !scalar(keys %{$conf->{pending}});
@@ -1278,10 +1278,10 @@ my $update_vm_api  = sub {
 
            if ($running) {
                my $errors = {};
-               PVE::QemuServer::vmconfig_hotplug_pending($vmid, $conf, 
$storecfg, $modified, $errors);
+               PVE::QemuConfig->vmconfig_hotplug_pending($vmid, $conf, 
$storecfg, $modified, $errors);
                raise_param_exc($errors) if scalar(keys %$errors);
            } else {
-               PVE::QemuServer::vmconfig_apply_pending($vmid, $conf, 
$storecfg, $running);
+               PVE::QemuConfig->vmconfig_apply_pending($vmid, $conf, 
$storecfg, $running);
            }
 
            return;
diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm
index 84d601a..ea3d7ba 100644
--- a/PVE/QemuConfig.pm
+++ b/PVE/QemuConfig.pm
@@ -397,6 +397,239 @@ sub __snapshot_foreach_volume {
 
     PVE::QemuServer::foreach_drive($conf, $func);
 }
+
+# hotplug changes in [PENDING]
+# $selection hash can be used to only apply specified options, for
+# example: { cores => 1 } (only apply changed 'cores')
+# $errors ref is used to return error messages
+sub vmconfig_hotplug_pending {
+    my ($class, $vmid, $conf, $storecfg, $selection, $errors) = @_;
+
+    my $defaults = PVE::QemuServer::load_defaults();
+    my ($arch, $machine_type) = PVE::QemuServer::get_basic_machine_info($conf, 
undef);
+
+    # commit values which do not have any impact on running VM first
+    # Note: those option cannot raise errors, we we do not care about
+    # $selection and always apply them.
+
+    my $add_error = sub {
+       my ($opt, $msg) = @_;
+       $errors->{$opt} = "hotplug problem - $msg";
+    };
+
+    my $changes = 0;
+    foreach my $opt (keys %{$conf->{pending}}) { # add/change
+       if ($PVE::QemuServer::fast_plug_option->{$opt}) {
+           $conf->{$opt} = $conf->{pending}->{$opt};
+           delete $conf->{pending}->{$opt};
+           $changes = 1;
+       }
+    }
+
+    if ($changes) {
+       $class->write_config($vmid, $conf);
+       $conf = $class->load_config($vmid); # update/reload
+    }
+
+    my $hotplug_features = 
PVE::QemuServer::parse_hotplug_features(defined($conf->{hotplug}) ? 
$conf->{hotplug} : '1');
+
+    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 ($opt eq 'hotplug') {
+               die "skip\n" if ($conf->{hotplug} =~ /memory/);
+           } elsif ($opt eq 'tablet') {
+               die "skip\n" if !$hotplug_features->{usb};
+               if ($defaults->{tablet}) {
+                   PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, 
'tablet', $arch, $machine_type);
+                   PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, 
'keyboard', $arch, $machine_type)
+                       if $arch eq 'aarch64';
+               } else {
+                   PVE::QemuServer::vm_deviceunplug($vmid, $conf, 'tablet');
+                   PVE::Qemuservervm_deviceunplug($vmid, $conf, 'keyboard') if 
$arch eq 'aarch64';
+               }
+           } elsif ($opt =~ m/^usb\d+/) {
+               die "skip\n";
+               # since we cannot reliably hot unplug usb devices
+               # we are disabling it
+               die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ 
m/spice/i;
+               PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+           } elsif ($opt eq 'vcpus') {
+               die "skip\n" if !$hotplug_features->{cpu};
+               PVE::Qemuserver::qemu_cpu_hotplug($vmid, $conf, undef);
+            } elsif ($opt eq 'balloon') {
+               # enable balloon device is not hotpluggable
+               die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} 
== 0;
+               # here we reset the ballooning value to memory
+               my $balloon = $conf->{memory} || $defaults->{memory};
+               PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => 
$balloon*1024*1024);
+           } elsif ($PVE::QemuServer::fast_plug_option->{$opt}) {
+               # do nothing
+           } elsif ($opt =~ m/^net(\d+)$/) {
+               die "skip\n" if !$hotplug_features->{network};
+               PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+           } elsif (PVE::QemuServer::is_valid_drivename($opt)) {
+               die "skip\n" if !$hotplug_features->{disk} || $opt =~ 
m/(ide|sata)(\d+)/;
+               PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+               PVE::QemuServer::vmconfig_delete_or_detach_drive($vmid, 
$storecfg, $conf, $opt, $force);
+           } elsif ($opt =~ m/^memory$/) {
+               die "skip\n" if !$hotplug_features->{memory};
+               PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, 
$defaults, $opt);
+           } elsif ($opt eq 'cpuunits') {
+               PVE::QemuServer::cgroups_write("cpu", $vmid, "cpu.shares", 
$defaults->{cpuunits});
+           } elsif ($opt eq 'cpulimit') {
+               PVE::QemuServer::cgroups_write("cpu", $vmid, 
"cpu.cfs_quota_us", -1);
+           } else {
+               die "skip\n";
+           }
+       };
+       if (my $err = $@) {
+           &$add_error($opt, $err) if $err ne "skip\n";
+       } else {
+           # save new config if hotplug was successful
+           delete $conf->{$opt};
+           $class->vmconfig_undelete_pending_option($conf, $opt);
+           $class->write_config($vmid, $conf);
+           $conf = $class->load_config($vmid); # update/reload
+       }
+    }
+
+    my $apply_pending_cloudinit;
+    $apply_pending_cloudinit = sub {
+       my ($key, $value) = @_;
+       $apply_pending_cloudinit = sub {}; # once is enough
+
+       my @cloudinit_opts = keys %$PVE::QemuServer::confdesc_cloudinit;
+       foreach my $opt (keys %{$conf->{pending}}) {
+           next if !grep { $_ eq $opt } @cloudinit_opts;
+           $conf->{$opt} = delete $conf->{pending}->{$opt};
+       }
+
+       my $new_conf = { %$conf };
+       $new_conf->{$key} = $value;
+       PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
+    };
+
+    foreach my $opt (keys %{$conf->{pending}}) {
+       next if $selection && !$selection->{$opt};
+       my $value = $conf->{pending}->{$opt};
+       eval {
+           if ($opt eq 'hotplug') {
+               die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && 
$conf->{hotplug} =~ /memory/);
+           } elsif ($opt eq 'tablet') {
+               die "skip\n" if !$hotplug_features->{usb};
+               if ($value == 1) {
+                   PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, 
'tablet', $arch, $machine_type);
+                   PVE::QemuServer::vm_deviceplug($storecfg, $conf, $vmid, 
'keyboard', $arch, $machine_type)
+                       if $arch eq 'aarch64';
+               } elsif ($value == 0) {
+                   PVE::QemuServer::vm_deviceunplug($vmid, $conf, 'tablet');
+                   PVE::QemuServer::vm_deviceunplug($vmid, $conf, 'keyboard') 
if $arch eq 'aarch64';
+               }
+           } elsif ($opt =~ m/^usb\d+$/) {
+               die "skip\n";
+               # since we cannot reliably hot unplug usb devices
+               # we are disabling it
+               die "skip\n" if !$hotplug_features->{usb} || $value =~ 
m/spice/i;
+               my $d = eval { 
PVE::JSONSchema::parse_property_string($PVE::QemuServer::usbdesc->{format}, 
$value) };
+               die "skip\n" if !$d;
+               PVE::QemuServer::qemu_usb_hotplug($storecfg, $conf, $vmid, 
$opt, $d, $arch, $machine_type);
+           } elsif ($opt eq 'vcpus') {
+               die "skip\n" if !$hotplug_features->{cpu};
+               PVE::QemuServer::qemu_cpu_hotplug($vmid, $conf, $value);
+           } elsif ($opt eq 'balloon') {
+               # enable/disable balloning device is not hotpluggable
+               my $old_balloon_enabled =  !!(!defined($conf->{balloon}) || 
$conf->{balloon});
+               my $new_balloon_enabled =  
!!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
+               die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
+
+               # allow manual ballooning if shares is set to zero
+               if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
+                   my $balloon = $conf->{pending}->{balloon} || 
$conf->{memory} || $defaults->{memory};
+                   PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => 
$balloon*1024*1024);
+               }
+           } elsif ($opt =~ m/^net(\d+)$/) {
+               # some changes can be done without hotplug
+               PVE::QemuServer::vmconfig_update_net($storecfg, $conf, 
$hotplug_features->{network},
+                                   $vmid, $opt, $value, $arch, $machine_type);
+           } elsif (PVE::QemuServer::is_valid_drivename($opt)) {
+               # some changes can be done without hotplug
+               my $drive = PVE::QemuServer::parse_drive($opt, $value);
+               if (PVE::QemuServer::drive_is_cloudinit($drive)) {
+                   &$apply_pending_cloudinit($opt, $value);
+               }
+               PVE::QemuServer::vmconfig_update_disk($storecfg, $conf, 
$hotplug_features->{disk},
+                                    $vmid, $opt, $value, 1, $arch, 
$machine_type);
+           } elsif ($opt =~ m/^memory$/) { #dimms
+               die "skip\n" if !$hotplug_features->{memory};
+               $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, 
$conf, $defaults, $opt, $value);
+           } elsif ($opt eq 'cpuunits') {
+               PVE::QemuServer::cgroups_write("cpu", $vmid, "cpu.shares", 
$conf->{pending}->{$opt});
+           } elsif ($opt eq 'cpulimit') {
+               my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : 
int($conf->{pending}->{$opt} * 100000);
+               PVE::QemuServer::cgroups_write("cpu", $vmid, 
"cpu.cfs_quota_us", $cpulimit);
+           } else {
+               die "skip\n";  # skip non-hot-pluggable options
+           }
+       };
+       if (my $err = $@) {
+           &$add_error($opt, $err) if $err ne "skip\n";
+       } else {
+           # save new config if hotplug was successful
+           $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) = @_;
+
+    # cold plug
+
+    my $pending_delete_hash = 
$class->split_flagged_list($conf->{pending}->{delete});
+    while (my ($opt, $force) = each %$pending_delete_hash) {
+       die "internal error" if $opt =~ m/^unused/;
+       $conf = $class->load_config($vmid); # update/reload
+       if (!defined($conf->{$opt})) {
+           $class->vmconfig_undelete_pending_option($conf, $opt);
+           $class->write_config($vmid, $conf);
+       } elsif (PVE::QemuServer::is_valid_drivename($opt)) {
+           PVE::QemuServer::vmconfig_delete_or_detach_drive($vmid, $storecfg, 
$conf, $opt, $force);
+           $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
+
+       if (defined($conf->{$opt}) && ($conf->{$opt} eq 
$conf->{pending}->{$opt})) {
+           # skip if nothing changed
+       } elsif (PVE::QemuServer::is_valid_drivename($opt)) {
+           PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, 
$conf, PVE::QemuServer::parse_drive($opt, $conf->{$opt}))
+               if defined($conf->{$opt});
+           $conf->{$opt} = $conf->{pending}->{$opt};
+       } else {
+           $conf->{$opt} = $conf->{pending}->{$opt};
+       }
+
+       delete $conf->{pending}->{$opt};
+       $class->write_config($vmid, $conf);
+    }
+}
+
+
 # END implemented abstract methods from PVE::AbstractConfig
 
 1;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 6e3b19e..7ff45f4 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -700,7 +700,7 @@ my $cicustom_fmt = {
 };
 PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
 
-my $confdesc_cloudinit = {
+our $confdesc_cloudinit = {
     citype => {
        optional => 1,
        type => 'string',
@@ -1302,7 +1302,7 @@ EODESCR
     },
 };
 
-my $usbdesc = {
+our $usbdesc = {
     optional => 1,
     type => 'string', format => $usb_fmt,
     description => "Configure an USB device (n is 0 to 4).",
@@ -2323,40 +2323,6 @@ sub vm_is_volid_owner {
     return undef;
 }
 
-sub split_flagged_list {
-    my $text = shift || '';
-    $text =~ s/[,;]/ /g;
-    $text =~ s/^\s+//;
-    return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
-}
-
-sub join_flagged_list {
-    my ($how, $lst) = @_;
-    join $how, map { $lst->{$_} . $_ } keys %$lst;
-}
-
-sub vmconfig_delete_pending_option {
-    my ($conf, $key, $force) = @_;
-
-    delete $conf->{pending}->{$key};
-    my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
-    $pending_delete_hash->{$key} = $force ? '!' : '';
-    $conf->{pending}->{delete} = join_flagged_list(',', $pending_delete_hash);
-}
-
-sub vmconfig_undelete_pending_option {
-    my ($conf, $key) = @_;
-
-    my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
-    delete $pending_delete_hash->{$key};
-
-    if (%$pending_delete_hash) {
-       $conf->{pending}->{delete} = join_flagged_list(',', 
$pending_delete_hash);
-    } else {
-       delete $conf->{pending}->{delete};
-    }
-}
-
 sub vmconfig_register_unused_drive {
     my ($storecfg, $vmid, $conf, $drive) = @_;
 
@@ -2371,37 +2337,6 @@ sub vmconfig_register_unused_drive {
     }
 }
 
-sub vmconfig_cleanup_pending {
-    my ($conf) = @_;
-
-    # remove pending changes when nothing changed
-    my $changes;
-    foreach my $opt (keys %{$conf->{pending}}) {
-       if (defined($conf->{$opt}) && ($conf->{pending}->{$opt} eq  
$conf->{$opt})) {
-           $changes = 1;
-           delete $conf->{pending}->{$opt};
-       }
-    }
-
-    my $current_delete_hash = split_flagged_list($conf->{pending}->{delete});
-    my $pending_delete_hash = {};
-    while (my ($opt, $force) = each %$current_delete_hash) {
-       if (defined($conf->{$opt})) {
-           $pending_delete_hash->{$opt} = $force;
-       } else {
-           $changes = 1;
-       }
-    }
-
-    if (%$pending_delete_hash) {
-       $conf->{pending}->{delete} = join_flagged_list(',', 
$pending_delete_hash);
-    } else {
-       delete $conf->{pending}->{delete};
-    }
-
-    return $changes;
-}
-
 # smbios: 
[manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
 my $smbios1_fmt = {
     uuid => {
@@ -4839,7 +4774,7 @@ sub set_migration_caps {
     vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => 
$cap_ref);
 }
 
-my $fast_plug_option = {
+our $fast_plug_option = {
     'lock' => 1,
     'name' => 1,
     'onboot' => 1,
@@ -4851,193 +4786,6 @@ my $fast_plug_option = {
     'hookscript' => 1,
 };
 
-# hotplug changes in [PENDING]
-# $selection hash can be used to only apply specified options, for
-# example: { cores => 1 } (only apply changed 'cores')
-# $errors ref is used to return error messages
-sub vmconfig_hotplug_pending {
-    my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
-
-    my $defaults = load_defaults();
-    my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
-
-    # commit values which do not have any impact on running VM first
-    # Note: those option cannot raise errors, we we do not care about
-    # $selection and always apply them.
-
-    my $add_error = sub {
-       my ($opt, $msg) = @_;
-       $errors->{$opt} = "hotplug problem - $msg";
-    };
-
-    my $changes = 0;
-    foreach my $opt (keys %{$conf->{pending}}) { # add/change
-       if ($fast_plug_option->{$opt}) {
-           $conf->{$opt} = $conf->{pending}->{$opt};
-           delete $conf->{pending}->{$opt};
-           $changes = 1;
-       }
-    }
-
-    if ($changes) {
-       PVE::QemuConfig->write_config($vmid, $conf);
-       $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-    }
-
-    my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? 
$conf->{hotplug} : '1');
-
-    my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
-    while (my ($opt, $force) = each %$pending_delete_hash) {
-       next if $selection && !$selection->{$opt};
-       eval {
-           if ($opt eq 'hotplug') {
-               die "skip\n" if ($conf->{hotplug} =~ /memory/);
-           } elsif ($opt eq 'tablet') {
-               die "skip\n" if !$hotplug_features->{usb};
-               if ($defaults->{tablet}) {
-                   vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, 
$machine_type);
-                   vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, 
$machine_type)
-                       if $arch eq 'aarch64';
-               } else {
-                   vm_deviceunplug($vmid, $conf, 'tablet');
-                   vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 
'aarch64';
-               }
-           } elsif ($opt =~ m/^usb\d+/) {
-               die "skip\n";
-               # since we cannot reliably hot unplug usb devices
-               # we are disabling it
-               die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ 
m/spice/i;
-               vm_deviceunplug($vmid, $conf, $opt);
-           } elsif ($opt eq 'vcpus') {
-               die "skip\n" if !$hotplug_features->{cpu};
-               qemu_cpu_hotplug($vmid, $conf, undef);
-            } elsif ($opt eq 'balloon') {
-               # enable balloon device is not hotpluggable
-               die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} 
== 0;
-               # here we reset the ballooning value to memory
-               my $balloon = $conf->{memory} || $defaults->{memory};
-               vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
-           } elsif ($fast_plug_option->{$opt}) {
-               # do nothing
-           } elsif ($opt =~ m/^net(\d+)$/) {
-               die "skip\n" if !$hotplug_features->{network};
-               vm_deviceunplug($vmid, $conf, $opt);
-           } elsif (is_valid_drivename($opt)) {
-               die "skip\n" if !$hotplug_features->{disk} || $opt =~ 
m/(ide|sata)(\d+)/;
-               vm_deviceunplug($vmid, $conf, $opt);
-               vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, 
$force);
-           } elsif ($opt =~ m/^memory$/) {
-               die "skip\n" if !$hotplug_features->{memory};
-               PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, 
$defaults, $opt);
-           } elsif ($opt eq 'cpuunits') {
-               cgroups_write("cpu", $vmid, "cpu.shares", 
$defaults->{cpuunits});
-           } elsif ($opt eq 'cpulimit') {
-               cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
-           } else {
-               die "skip\n";
-           }
-       };
-       if (my $err = $@) {
-           &$add_error($opt, $err) if $err ne "skip\n";
-       } else {
-           # save new config if hotplug was successful
-           delete $conf->{$opt};
-           vmconfig_undelete_pending_option($conf, $opt);
-           PVE::QemuConfig->write_config($vmid, $conf);
-           $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-       }
-    }
-
-    my $apply_pending_cloudinit;
-    $apply_pending_cloudinit = sub {
-       my ($key, $value) = @_;
-       $apply_pending_cloudinit = sub {}; # once is enough
-
-       my @cloudinit_opts = keys %$confdesc_cloudinit;
-       foreach my $opt (keys %{$conf->{pending}}) {
-           next if !grep { $_ eq $opt } @cloudinit_opts;
-           $conf->{$opt} = delete $conf->{pending}->{$opt};
-       }
-
-       my $new_conf = { %$conf };
-       $new_conf->{$key} = $value;
-       PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
-    };
-
-    foreach my $opt (keys %{$conf->{pending}}) {
-       next if $selection && !$selection->{$opt};
-       my $value = $conf->{pending}->{$opt};
-       eval {
-           if ($opt eq 'hotplug') {
-               die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && 
$conf->{hotplug} =~ /memory/);
-           } elsif ($opt eq 'tablet') {
-               die "skip\n" if !$hotplug_features->{usb};
-               if ($value == 1) {
-                   vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, 
$machine_type);
-                   vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, 
$machine_type)
-                       if $arch eq 'aarch64';
-               } elsif ($value == 0) {
-                   vm_deviceunplug($vmid, $conf, 'tablet');
-                   vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 
'aarch64';
-               }
-           } elsif ($opt =~ m/^usb\d+$/) {
-               die "skip\n";
-               # since we cannot reliably hot unplug usb devices
-               # we are disabling it
-               die "skip\n" if !$hotplug_features->{usb} || $value =~ 
m/spice/i;
-               my $d = eval { 
PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
-               die "skip\n" if !$d;
-               qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, 
$machine_type);
-           } elsif ($opt eq 'vcpus') {
-               die "skip\n" if !$hotplug_features->{cpu};
-               qemu_cpu_hotplug($vmid, $conf, $value);
-           } elsif ($opt eq 'balloon') {
-               # enable/disable balloning device is not hotpluggable
-               my $old_balloon_enabled =  !!(!defined($conf->{balloon}) || 
$conf->{balloon});
-               my $new_balloon_enabled =  
!!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
-               die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
-
-               # allow manual ballooning if shares is set to zero
-               if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
-                   my $balloon = $conf->{pending}->{balloon} || 
$conf->{memory} || $defaults->{memory};
-                   vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
-               }
-           } elsif ($opt =~ m/^net(\d+)$/) {
-               # some changes can be done without hotplug
-               vmconfig_update_net($storecfg, $conf, 
$hotplug_features->{network},
-                                   $vmid, $opt, $value, $arch, $machine_type);
-           } elsif (is_valid_drivename($opt)) {
-               # some changes can be done without hotplug
-               my $drive = parse_drive($opt, $value);
-               if (drive_is_cloudinit($drive)) {
-                   &$apply_pending_cloudinit($opt, $value);
-               }
-               vmconfig_update_disk($storecfg, $conf, 
$hotplug_features->{disk},
-                                    $vmid, $opt, $value, 1, $arch, 
$machine_type);
-           } elsif ($opt =~ m/^memory$/) { #dimms
-               die "skip\n" if !$hotplug_features->{memory};
-               $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, 
$conf, $defaults, $opt, $value);
-           } elsif ($opt eq 'cpuunits') {
-               cgroups_write("cpu", $vmid, "cpu.shares", 
$conf->{pending}->{$opt});
-           } elsif ($opt eq 'cpulimit') {
-               my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : 
int($conf->{pending}->{$opt} * 100000);
-               cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
-           } else {
-               die "skip\n";  # skip non-hot-pluggable options
-           }
-       };
-       if (my $err = $@) {
-           &$add_error($opt, $err) if $err ne "skip\n";
-       } else {
-           # save new config if hotplug was successful
-           $conf->{$opt} = $value;
-           delete $conf->{pending}->{$opt};
-           PVE::QemuConfig->write_config($vmid, $conf);
-           $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-       }
-    }
-}
-
 sub try_deallocate_drive {
     my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = 
@_;
 
@@ -5077,50 +4825,6 @@ sub vmconfig_delete_or_detach_drive {
     }
 }
 
-sub vmconfig_apply_pending {
-    my ($vmid, $conf, $storecfg) = @_;
-
-    # cold plug
-
-    my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
-    while (my ($opt, $force) = each %$pending_delete_hash) {
-       die "internal error" if $opt =~ m/^unused/;
-       $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-       if (!defined($conf->{$opt})) {
-           vmconfig_undelete_pending_option($conf, $opt);
-           PVE::QemuConfig->write_config($vmid, $conf);
-       } elsif (is_valid_drivename($opt)) {
-           vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, 
$force);
-           vmconfig_undelete_pending_option($conf, $opt);
-           delete $conf->{$opt};
-           PVE::QemuConfig->write_config($vmid, $conf);
-       } else {
-           vmconfig_undelete_pending_option($conf, $opt);
-           delete $conf->{$opt};
-           PVE::QemuConfig->write_config($vmid, $conf);
-       }
-    }
-
-    $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-
-    foreach my $opt (keys %{$conf->{pending}}) { # add/change
-       $conf = PVE::QemuConfig->load_config($vmid); # update/reload
-
-       if (defined($conf->{$opt}) && ($conf->{$opt} eq 
$conf->{pending}->{$opt})) {
-           # skip if nothing changed
-       } elsif (is_valid_drivename($opt)) {
-           vmconfig_register_unused_drive($storecfg, $vmid, $conf, 
parse_drive($opt, $conf->{$opt}))
-               if defined($conf->{$opt});
-           $conf->{$opt} = $conf->{pending}->{$opt};
-       } else {
-           $conf->{$opt} = $conf->{pending}->{$opt};
-       }
-
-       delete $conf->{pending}->{$opt};
-       PVE::QemuConfig->write_config($vmid, $conf);
-    }
-}
-
 my $safe_num_ne = sub {
     my ($a, $b) = @_;
 
@@ -5311,7 +5015,7 @@ sub vm_start {
        die "VM $vmid already running\n" if check_running($vmid, undef, 
$migratedfrom);
 
        if (!$statefile && scalar(keys %{$conf->{pending}})) {
-           vmconfig_apply_pending($vmid, $conf, $storecfg);
+           PVE::QemuConfig->vmconfig_apply_pending($vmid, $conf, $storecfg);
            $conf = PVE::QemuConfig->load_config($vmid); # update/reload
        }
 
@@ -5729,7 +5433,7 @@ sub vm_stop_cleanup {
            }
        }
 
-       vmconfig_apply_pending($vmid, $conf, $storecfg) if 
$apply_pending_changes;
+       PVE::QemuConfig->vmconfig_apply_pending($vmid, $conf, $storecfg) if 
$apply_pending_changes;
     };
     warn $@ if $@; # avoid errors - just warn
 }
diff --git a/PVE/QemuServer/ImportDisk.pm b/PVE/QemuServer/ImportDisk.pm
index db7db63..dd0b16c 100755
--- a/PVE/QemuServer/ImportDisk.pm
+++ b/PVE/QemuServer/ImportDisk.pm
@@ -62,7 +62,7 @@ sub do_import {
                my $running = PVE::QemuServer::check_running($vmid);
                if ($running) {
                    my $errors = {};
-                   PVE::QemuServer::vmconfig_hotplug_pending($vmid, $vm_conf, 
$storecfg, $modified, $errors);
+                   PVE::QemuConfig->vmconfig_hotplug_pending($vmid, $vm_conf, 
$storecfg, $modified, $errors);
                    if (scalar(keys %$errors)) {
                        foreach my $k (keys %$errors) {
                            warn "$k: $errors->{$k}\n" if $debug;
@@ -70,7 +70,7 @@ sub do_import {
                        }
                    }
                } else {
-                   PVE::QemuServer::vmconfig_apply_pending($vmid, $vm_conf, 
$storecfg);
+                   PVE::QemuConfig->vmconfig_apply_pending($vmid, $vm_conf, 
$storecfg);
                }
 
        } else {
-- 
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