currently it is allowed to change all configuration settings for a VM. But may 
be some
are only allowed if VM is offline or if hotplug is enabled

Signed-off-by: Stefan Priebe <[email protected]>
---
 PVE/API2/Qemu.pm |  127 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 102 insertions(+), 25 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 903f1fb..3a23912 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -757,6 +757,8 @@ my $vmconfig_update_disk = sub {
        $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
     }
 
+    my $running = PVE::QemuServer::check_running($vmid);
+
     if ($conf->{$opt}) {
 
        if (my $old_drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt}))  
{
@@ -768,10 +770,20 @@ my $vmconfig_update_disk = sub {
            if (!PVE::QemuServer::drive_is_cdrom($old_drive) &&
                ($drive->{file} ne $old_drive->{file})) {  # delete old disks
 
+               die "Deleting drive '$drive->{file}' not possible while VM is 
running and hotplug disabled.\n"
+                   if $running && !$conf->{hotplug};
+
                &$vmconfig_delete_option($rpcenv, $authuser, $conf, $storecfg, 
$vmid, $opt, $force);
                $conf = PVE::QemuServer::load_config($vmid); # update/reload
            }
 
+           if ((defined $old_drive->{cache} && defined $drive->{cache} && 
$old_drive->{cache} ne $drive->{cache}) ||
+                   (!defined $drive->{cache} && defined $old_drive->{cache}) ||
+                   (!defined $old_drive->{cache} && defined $drive->{cache})) {
+               die "Changing cache mode for drive '$opt' not possible while VM 
is running and hotplug disabled.\n"
+                   if ($running && !PVE::QemuServer::drive_is_cdrom($drive) && 
!$conf->{hotplug});
+           }
+
             if(&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
                &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
                &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
@@ -800,6 +812,9 @@ my $vmconfig_update_disk = sub {
                   if !PVE::QemuServer::drive_is_cdrom($drive);
             }
        }
+    } else {
+       die "Adding drive '$opt' not possible while VM is running and hotplug 
disabled.\n"
+           if ($running && !PVE::QemuServer::drive_is_cdrom($drive) && 
!$conf->{hotplug});
     }
 
     &$create_disks($rpcenv, $authuser, $conf, $storecfg, $vmid, undef, {$opt 
=> $value});
@@ -810,7 +825,7 @@ my $vmconfig_update_disk = sub {
 
     if (PVE::QemuServer::drive_is_cdrom($drive)) { # cdrom
 
-       if (PVE::QemuServer::check_running($vmid)) {
+       if ($running) {
            if ($drive->{file} eq 'none') {
                PVE::QemuServer::vm_mon_cmd($vmid, "eject",force => 
JSON::true,device => "drive-$opt");
            } else {
@@ -834,8 +849,10 @@ my $vmconfig_update_net = sub {
        my $newnet = PVE::QemuServer::parse_net($value);
 
        if($oldnet->{model} ne $newnet->{model}){
+           die "Changing model is not possible while VM is running and hotplug 
disabled.\n"
+               if PVE::QemuServer::check_running($vmid) && !$conf->{hotplug};
            #if model change, we try to hot-unplug
-            die "error hot-unplug $opt for update" if 
!PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+            die "error hot-unplug $opt for update\n" if 
!PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
        }else{
 
            if($newnet->{bridge} && $oldnet->{bridge}){
@@ -851,11 +868,17 @@ my $vmconfig_update_net = sub {
                }
 
            }else{
+               die "Changing bridged/nat mode is not possible while VM is 
running and hotplug disabled.\n"
+                   if PVE::QemuServer::check_running($vmid) && 
!$conf->{hotplug};
                #if bridge/nat mode change, we try to hot-unplug
-               die "error hot-unplug $opt for update" if 
!PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+               die "error hot-unplug $opt for update\n" if 
!PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
            }
        }
 
+    } else {
+       # new device
+       die "Adding new net device '$opt' not possible while VM is running and 
hotplug disabled.\n"
+           if PVE::QemuServer::check_running($vmid) && !$conf->{hotplug};
     }
     $conf->{$opt} = $value;
     PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
@@ -972,50 +995,104 @@ my $update_vm_api  = sub {
 
            print "update VM $vmid: " . join (' ', @paramarr) . "\n";
 
-           foreach my $opt (@delete) { # delete
-               $conf = PVE::QemuServer::load_config($vmid); # update/reload
-               &$vmconfig_delete_option($rpcenv, $authuser, $conf, $storecfg, 
$vmid, $opt, $force);
-           }
-
            my $running = PVE::QemuServer::check_running($vmid);
 
-           foreach my $opt (keys %$param) { # add/change
+           my $conf_param = $param;
+           foreach my $del (@delete) {
+               die "You cannot update/add and delete at the same time 
'$del'\n" if exists $conf_param->{$del};
+               $conf_param->{$del} = undef;
+           }
+
+           foreach my $opt (keys %$conf_param) { # add/change/delete
 
                $conf = PVE::QemuServer::load_config($vmid); # update/reload
 
-               next if $conf->{$opt} && ($param->{$opt} eq $conf->{$opt}); # 
skip if nothing changed
+               next if ((defined $conf->{$opt} && defined $conf_param->{$opt} 
&& $conf_param->{$opt} eq $conf->{$opt}) ||
+                           (!defined $conf->{$opt} && !defined 
$conf_param->{$opt})); # skip if nothing changed
 
-               if (PVE::QemuServer::valid_drivename($opt)) {
+               # ignore sockets setting if maxcpu is set
+               next if ($opt eq "sockets" && $conf->{maxcpus});
+
+               my $need_hotplug = 0;
+               my $need_offlinevm = 0;
+
+               if ($opt eq 'tablet') {
+                   # special handling for tablet option
+
+                   if ($conf_param->{$opt}) {
+                       PVE::QemuServer::vm_deviceplug(undef, $conf, $vmid, 
$opt);
+                   } else {
+                       PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+                   }
+                   next;
 
-                   &$vmconfig_update_disk($rpcenv, $authuser, $conf, 
$storecfg, $vmid,
-                                          $opt, $param->{$opt}, $force);
+               } elsif (PVE::QemuServer::valid_drivename($opt)) {
+
+                   if (defined $conf_param->{$opt}) {
+                       &$vmconfig_update_disk($rpcenv, $authuser, $conf, 
$storecfg, $vmid,
+                                       $opt, $conf_param->{$opt}, $force);
+                       next;
+                   }
+                   $need_hotplug = 1; # for delete / remove
 
                } elsif ($opt =~ m/^net(\d+)$/) { #nics
 
-                   &$vmconfig_update_net($rpcenv, $authuser, $conf, $storecfg, 
$vmid,
-                                         $opt, $param->{$opt});
+                   if (defined $conf_param->{$opt}) {
+                       &$vmconfig_update_net($rpcenv, $authuser, $conf, 
$storecfg, $vmid,
+                                       $opt, $conf_param->{$opt});
+                       next;
+                   }
+                   $need_hotplug = 1; # for delete / remove
 
                } else {
+                   # all options which do not update config on their own
 
-                   if($opt eq 'tablet' && $param->{$opt} == 1){
-                       PVE::QemuServer::vm_deviceplug(undef, $conf, $vmid, 
$opt);
-                   } elsif($opt eq 'tablet' && $param->{$opt} == 0){
-                       PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+                   if ($opt =~ /^(cores)$/) {
+                       # options only possible to change if hotplug is enabled
+                       $need_hotplug = 1;
+
+                   } elsif ($opt =~ /^(balloon)$/ && length $conf->{$opt}) {
+
+                       # options always beeing able to change IF they already 
exist config
+
+                   } elsif ($opt =~ /^(onboot|name|boot|shares)$/) {
+
+                       # options always beeing able to change
+
+                   } else {
+
+                       # options only possible to change if the vm isn't 
running
+                       $need_offlinevm = 1;
                    }
-               
-                   if($opt eq 'cores' && $conf->{maxcpus}){
-                       PVE::QemuServer::qemu_cpu_hotplug($vmid, $conf, 
$param->{$opt});
+               }
+
+               my $type = (!defined $conf_param->{$opt}) ? "Removing" : 
"Changing";
+               if ($running && $need_hotplug && !$conf->{hotplug}) {
+                   die "$type '$opt' not possible while VM is running and 
hotplug disabled.\n";
+               }
+               if ($running && $need_offlinevm) {
+                   die "$type '$opt' not possible while VM is running.\n";
+               }
+
+               if (!defined $conf_param->{$opt}) {
+
+                   # undefined values are "delete" values
+                   &$vmconfig_delete_option($rpcenv, $authuser, $conf, 
$storecfg, $vmid, $opt, $force);
+               } else {
+
+                   if ($opt eq 'cores' && $conf->{maxcpus}){
+                       PVE::QemuServer::qemu_cpu_hotplug($vmid, $conf, 
$conf_param->{$opt});
                    }
 
-                   $conf->{$opt} = $param->{$opt};
+                   $conf->{$opt} = $conf_param->{$opt};
                    PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
                }
            }
 
            # allow manual ballooning if shares is set to zero
-           if ($running && defined($param->{balloon}) &&
+           if ($running && defined($conf_param->{balloon}) &&
                defined($conf->{shares}) && ($conf->{shares} == 0)) {
-               my $balloon = $param->{'balloon'} || $conf->{memory} || 
$defaults->{memory};
+               my $balloon = $conf_param->{'balloon'} || $conf->{memory} || 
$defaults->{memory};
                PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => 
$balloon*1024*1024);
            }
        };
-- 
1.7.10.4

_______________________________________________
pve-devel mailing list
[email protected]
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to