[pve-devel] [PATCH] check for valid config changes
Stefan Priebe
s.priebe at profihost.ag
Fri Sep 5 09:42:47 CEST 2014
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 <s.priebe at profihost.ag>
---
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 985a9f8..bf560cf 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -759,6 +759,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})) {
@@ -770,10 +772,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}) ||
@@ -802,6 +814,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});
@@ -812,7 +827,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 {
@@ -836,8 +851,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}){
@@ -853,11 +870,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);
@@ -974,50 +997,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 if ($opt !~ /^unused/);
} 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|lock|startup|description)$/) {
+
+ # 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
More information about the pve-devel
mailing list