diff --git a/ApiChangeLog b/ApiChangeLog index 508f85e..de41192 100644 --- a/ApiChangeLog +++ b/ApiChangeLog @@ -48,6 +48,17 @@ Future changes should be documented in here. Plugins that do not require hints can safely ignore the additional parameter. +* Introduce `on_update_hook_full()` plugin method + + The original `on_update_hook()` plugin method was limited, because only the updated properties and + values would be passed in. The new `on_update_hook_full()` plugin method also receives the current + storage configuration and the list of which properties are to be deleted. This allows detecting + and reacting to all changes and knowing how values changed. See also bug #6669 [0] for the initial + motiviation. If a plugin implements `on_update_hook_full()`, that method will be called rather + than the `on_update_hook()` method. + + [0]: https://bugzilla.proxmox.com/show_bug.cgi?id=6669 + ## Version 12: * Introduce `qemu_blockdev_options()` plugin method diff --git a/src/PVE/API2/Storage/Config.pm b/src/PVE/API2/Storage/Config.pm index 34f2d85..c10ccf8 100755 --- a/src/PVE/API2/Storage/Config.pm +++ b/src/PVE/API2/Storage/Config.pm @@ -360,6 +360,9 @@ __PACKAGE__->register_method({ my $plugin = PVE::Storage::Plugin->lookup($type); my $opts = $plugin->check_config($storeid, $param, 0, 1); + # Do checks for deletion up-front, but defer actual deletion until after the + # on_update_hook(_full) call. This makes it possible to pass the unmodified current + # storage configuration to the method. if ($delete) { my $options = $plugin->private()->{options}->{$type}; foreach my $k (@$delete) { @@ -368,12 +371,21 @@ __PACKAGE__->register_method({ die "unable to delete fixed option '$k'\n" if $d->{fixed}; die "cannot set and delete property '$k' at the same time!\n" if defined($opts->{$k}); - - delete $scfg->{$k}; } } - $returned_config = $plugin->on_update_hook($storeid, $opts, %$sensitive); + if ($plugin->can('api') && $plugin->api() < 13) { + $returned_config = $plugin->on_update_hook($storeid, $opts, %$sensitive); + } else { + $returned_config = + $plugin->on_update_hook_full($storeid, $scfg, $opts, $delete, $sensitive); + } + + if ($delete) { + for my $k ($delete->@*) { + delete $scfg->{$k}; + } + } for my $k (keys %$opts) { $scfg->{$k} = $opts->{$k}; diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm index d05c8db..31a79e9 100644 --- a/src/PVE/Storage/Plugin.pm +++ b/src/PVE/Storage/Plugin.pm @@ -711,6 +711,39 @@ sub on_update_hook { return undef; } +=head3 on_update_hook_full + + $returned_config = $plugin->on_update_hook_full($storeid, $scfg, $update, $delete, $sensitive); + +Most plugins use an empty C, so that C<$returned_config> will be C. While a plugin +can return auto-generated properties via C<$returned_config>, this is currently only used for the +C<'encryption-key'> for the PBS plugin. + +Arguments: + +=over + +=item C<$storeid>: The storage ID. + +=item C<$scfg>: The current storage configuration. + +=item C<$update>: Hash reference with properties to be updated and their new values. + +=item C<$delete>: Array reference with properties to be deleted. + +=item C<$sensitive>: Hash reference with sensitive properties and their new values. Sensitive +properties are declared via the plugin data method C. + +=back + +=cut + +sub on_update_hook_full { + my ($class, $storeid, $scfg, $update, $delete, $sensitive) = @_; + + return $class->on_update_hook($storeid, $update, $sensitive->%*); +} + # called during deletion of storage (before the new storage config got written) # and if the activate check on addition fails, to cleanup all storage traces # which on_add_hook may have created.