[pve-devel] [RFC qemu-server] qemu: allow partial fastplugging of property string options

Oguz Bektas o.bektas at proxmox.com
Wed Jan 22 17:37:39 CET 2020


this patch adds the partial_fast_plug function, which allows to partially
fastplug an option with a property string.

this is done by having a map $partial_fast_plug_option, the format is commented.

other helper functions:

* safe_boolean_ne (!$a != !$b)
* typesafe_ne (combines safe_string_ne, safe_num_ne and safe_boolean_ne by
taking $type as an argument)

the qemu-guest-agent is our first use case for this (although i am sure
there are more, this is more of a proof of concept. it should be trivial
to add other things via the map), specifically the fstrim_cloned_disks
option.

Co-Authored-by: Stefan Reiter <s.reiter at proxmox.com>
Signed-off-by: Oguz Bektas <o.bektas at proxmox.com>
---

i added stefan as a co-author for this, to thank for his help debugging and 
testing it with me

also please note that i'm sending this as RFC for review only, and it
shouldn't be applied yet since i'm working on generalizing it a bit more
for code reuse via pve-guest-common

 PVE/QemuServer.pm | 78 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index bcdadca..74cbba0 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -5031,6 +5031,10 @@ sub vmconfig_hotplug_pending {
 		}
 		vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
 				     $vmid, $opt, $value, 1, $arch, $machine_type);
+	    } elsif ($opt eq 'agent') {
+		# partially fastpluggable
+		# skip if all options were fastpluggable
+		die "skip\n" if partial_fast_plug($conf, $opt);
 	    } elsif ($opt =~ m/^memory$/) { #dimms
 		die "skip\n" if !$hotplug_features->{memory};
 		$value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
@@ -5165,6 +5169,80 @@ my $safe_string_ne = sub {
     return $a ne $b;
 };
 
+my $safe_boolean_ne = sub {
+    my ($a, $b) = @_;
+
+    # we don't check if value is defined, since undefined
+    # is false (so it's a valid boolean)
+
+    # negate both values to normalize and compare
+    return !$a != !$b;
+};
+
+my $typesafe_ne = sub {
+    my ($a, $b, $type) = @_;
+
+    return 0 if !defined($a) && !defined($b);
+    return 1 if !defined($a);
+    return 1 if !defined($b);
+
+    if ($type eq 'string') {
+	$safe_string_ne->($a, $b);
+    } elsif ($type eq 'number') {
+	$safe_num_ne->($a, $b);
+    } elsif ($type eq 'boolean') {
+	$safe_boolean_ne->($a, $b);
+    }
+};
+
+my $partial_fast_plug_option =
+# name
+# -> fmt -> format variable
+# -> properties -> fastpluggable options hash
+{
+    agent => {
+	fmt => $agent_fmt,
+	properties => {
+	    fstrim_cloned_disks => 1
+	},
+    },
+};
+
+sub partial_fast_plug {
+    my ($conf, $opt) = @_;
+
+    my $format = $partial_fast_plug_option->{$opt}->{fmt};
+    my $properties = $partial_fast_plug_option->{$opt}->{properties};
+
+    my $old = PVE::JSONSchema::parse_property_string($format, $conf->{$opt});
+    my $new = PVE::JSONSchema::parse_property_string($format, $conf->{pending}->{$opt});
+
+    my $changes_left = 0;
+
+    # merge old and new opts to iterate
+    my $all_opts = dclone($old);
+    foreach my $opt1 (keys %$new) {
+	$all_opts->{$opt1} = $new->{$opt1} if !defined($all_opts->{$opt1});
+    }
+
+    foreach my $opt2 (keys %$all_opts) {
+	my $is_fastpluggable = $properties->{$opt2};
+	my $type = $format->{$opt2}->{type};
+	if ($typesafe_ne->($old->{$opt2}, $new->{$opt2}, $type)) {
+	    if (defined($is_fastpluggable)) {
+		$old->{$opt2} = $new->{$opt2};
+	    } else {
+		$changes_left = 1;
+	    }
+	}
+    }
+
+    $conf->{$opt} = PVE::JSONSchema::print_property_string($old, $format);
+
+    return $changes_left;
+}
+
+
 sub vmconfig_update_net {
     my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
 
-- 
2.20.1




More information about the pve-devel mailing list