Resource upgrade is meant to provide a means for the plugin developer to be able to touch already inventoried resources and thus provide a way of "upgrading" the resources.
There is a couple of main use cases that drive this effort:
- Resource key found not unique - the resource key generation algorithm in the original version of the plugin was later found to be non-unique. For the new corrected version of the plugin to be able to operate on the resource that have already been inventoried, those resources need to have their resource keys upgraded to the corrected format.
- "Ugly" resource name - the same type of a problem as with the resource key, only much less crucial. Still from the user POV, this can be quite important.
- Structural changes to plugin/resource configuration needed - if the plugin/resource configuration of some resource types is found insufficient, the new version of the plugin should be provided with a way of modifying the actual configuration values from the old-style configuration to the new structure. This is by far the most complicated matter as it would involve changes to the way we store the server-side configuration update history, associated UI updates, etc.
Plugin configuration update support has been added for version 4.8. The updated plugin configuration properties must conform to the plugin configuration definition.
There is a tracking bugzilla for this https://bugzilla.redhat.com/show_bug.cgi?id=592038
Before we dive into the changes in the plugin container, server and other RHQ subsystems, let's first examine the situation from the point of view of the plugin developer. The components the plugin developer creates have no explicit means to examine and traverse the inventory, not to mention to modify it. But the plugin discovery components are responsible for (re)creating the individual resources in the inventory tree. Therefore the best place to insert some additional logic for upgrade would be the discovery components. A standard means of enabling some functionality in the plugin is to provide a facet interface for the plugins to implement, and the resource upgrade is no different:
The upgrade() method of this facet is called for every inventoried resource that is determined to be upgraded. The ResourceUpgradeContext<T> class provides the discovery component with all the information about the resource and the component returns a report detailing what should be changed on that resource.
Where is simple - only the plugin has enough information to perform the upgrade. The upgrade must happen as soon as possible during the initialization of the plugin container so that once the plugin container starts fully up, everything is already up-to-date. The ideal spot for upgrade functionality is therefore the InventoryManager.initialize() method that is run very early in the plugin container startup and has enough context already in place to perform the upgrade.
The agent-side inventory is initialized during the InventoryManager.initialize() method. That method is the place we should invoke the resource upgrade, before any other agent subsystems are started (configuration manager, content manager, etc.) and also before any inventory scan schedulers are started (to prevent their concurrent intervention with the upgrade process).
The upgrade starts with a sync with the server side inventory and then just goes through the synchronized inventory and collects the upgrade requests from individual resources. Once those requests are successfully sent to the server, they are applied on the agent side inventory.
Error recovery during upgrade should be as fine grained as possible. A failure to upgrade one resource shouldn't abort the whole upgrade process or prevent upgrade attempts on other resources even if they are of the same type.
Because our plugin system doesn't support running several versions of the same plugin in parallel (either on agent or server), we can't support rolling back to previous version of the plugin (in that case "similar" resources on different agents could be managed by different versions of the plugins and the server-side code would have make sense of it). The chosen approach is therefore to report the per-resource errors back to the server and stop the resources that failed to upgrade on the agent. At the same time, the discovery of the sibling resources of the failed ones is suspended (for the lifetime of the plugin container) because the discovery could discover a new resource that would be "logically equivalent" to the one that failed and if the user imported that new resource we'd end up in a situation that the whole resource upgrade functionality is trying to solve - duplicate resources that should have been one.