Re: classloader hell
by John Mazzitelli
> Is this an instance of class leakage that was mentioned in a previous
> post?
Yes, it is. Welcome to the jungle :/
> In my reading of LinkageError it sounds like both the bootloader
> and the pluginclassloader have loaded JAXBContext and because of that
> the signatures don't match.
It sounds like you have a bead on what the problem is. I'll explain what I think happened for the benefit of others. Based on the unusually specific and helpful exception message:
1) the plugin classloader loaded "com.sun.xml.internal.ws.client.WSServiceDelegate" (which is what it sounds like you fixed from before - this class is probably now in some library you packaged in your plugin)
2) from looking at what I think is the source for that class, it extends com.sun.xml.ws.api.WSService which in turn extends javax.xml.ws.spi.ServiceDelegate.
3) One or both of those superclasses was loaded by the bootclassloader (the classloader at the very very top of the classloader hierachy) - this is the "leakage" I was saying was a possibility.
4) Both of the superclasses import and use javax.xml.bind.JAXBContext; thus, the bootloader also loaded this JAXBContext class (take special note - this is a JAXB API!)
5) WSServiceDelegate overrides that createDispatch method - but its loaded by the plugin classloader, which means that method needed to load JAXBContext and got the plugin classloader to load it too
6) boom - you have one method overriding another, but the signatures don't "match" because the two methods reference two different classes (the names might be the same, but they are really two different classes because they have two different loaders)
This is one way leaking classes can cause problems - this is what I was talking about when I mentioned to be on the lookout for this. Essentially, JAXBContext leaked from the bootstrap classloader and tried to mix itself with classes loaded by the plugin classloader.
> The other possibility is that the plugin
> was build using a newer version of jaxb than is present in the jdk.
I don't think that's it. The exception seems pretty clear that its this class problem.
As soon as I noticed the leaked class in question was a JAXB class, I asked myself, "How is your agent getting the JAXB classes into the bootstrap classloader I wonder?". I immediately went and looked at how we are deploying the JAXB libraries in the agent. We may have a problem here. But it may be easy to fix.
I'll claim ignorance to this Web Services API and all its dependencies - I've not used that stuff in years. But I believe this javax.xml.ws stuff (and its com.sun.xml.ws impl classes) are built into the JRE. However, JAXB was NOT shipping with the JRE when we were building/running on JRE 5. IT IS SHIPPING NOW WITH JDK6. I will therefore assume you are running the agent on JRE 6.
We actually put our own JAXB API in the agent/lib/endorsed directory because we needed JAXB and we needed to support JRE 5 (which didn't ship with JAXB). We install those JAXB libraries as endorsed libraries via -Djava.endorsed.dirs (see rhq-agent.sh for where we do that). In our root classloader regex, we hide those JAXB classes because we didn't want to clash with other plugins that also want to use their own external JAXB impl. This should allow other plugins to ship their own JAXB libraries and be able to use those (again, because back on JRE5 we didn't have the JRE to supply them to us).
But when you load the Web Services class, they come from the bootstrap classloader - and when their signatures reference that JAXBContext API, its ALSO comes out of the bootstrap classloader because that is now in the the built-in JRE libs! This is probably causing the problem. But we shouldn't be doing this "JAXB installed as an endorsed library" now anymore. We are moving to JRE 6, and since it has JAXB built-in we should not be shipping these JAXB libraries and installing them ourselves (which was only necessary for JRE5 runtimes)
How can you solve this? First, don't have the agent pass in that endorsed dir sysprop. you can do this by:
export RHQ_AGENT_JAVA_ENDORSED_DIRS=/bogus
rhq-agent.sh will use that instead of its own endorsed default and thus its JAXB libraries won't load - it'll fall back to the JRE's built-in JAXB API (and let's cross our fingers we stuff will still work, we were using JAXB 2.1, unsure how compatible that is with the built-in JRE version of JAXB).
Alternatively, if you don't want to set that env var, you can just delete the libraries that you have in agent/lib/endorsed (which I believe are all related to JAXB). Since the JRE 6 should already have them, you won't miss them.
Now we have to tell the agent to no longer hide those javax.xml.bind and related JAXB classes. You have to change the root classloader regex - you need to take the default regex and strip out the JAXB phrases. From the code, those JAXB related regex phrases are:
1200 // Hide our version of JAXB.
1201 // If the plugins want these, they should include their own implementations.
1202 defaultRegex.append("(javax\\.xml\\.bind\\..*)|");
1203 defaultRegex.append("(com\\.sun\\.activation\\..*)|");
1204 defaultRegex.append("(com\\.sun\\.istack\\..*)|");
1205 defaultRegex.append("(com\\.sun\\.xml\\..*)|");
For the record, those line numbers/code come from:
http://git.fedorahosted.org/git/?p=rhq/rhq.git;a=blob;f=modules/enterpris...
That's the class that defines the default regex (see getPluginContainerConfiguration). you can either tweek that class and rebuild the agent jar or set the regex preference with the tweeked regex in agent-configuration.xml and restart the agent clean (--cleanconfig) to pick up the new regex.
Let us know if that works. If so, we can make those changes to the agent (i.e. no longer ship with the jaxb libs) and the changes to the default regex and commit those changes to the master branch.
----- "Bala Nair" <bnairtm(a)comcast.net> wrote:
> Ok, we are officially in classloader hell. Our original problem was a
> class not found exception when trying to use a class defined in an
> external jar in one of our agent plugins. After some good advice and
> an explanation of how resource classloaders work, we decided to do the
> following.
>
> 1. declare an instance classloader for our plugin's server class (in
> the rhq-plugin.xml, server element, classloader="instance" attribute)
> 2. implement the classloaderfacet in the server discovery component
> 3. add the relevant jars to the classpath for the server resource
> component
>
> So now we no longer see the class not found exception. instead we get
> this:
>
> java.util.concurrent.ExecutionException: java.lang.Exception:
> java.lang.LinkageError: loader constraint violation: when resolving
> overridden method
> "com.sun.xml.internal.ws.client.WSServiceDelegate.createDispatch(Ljavax/xml/namespace/QName;Ljavax/xml/bind/JAXBContext;Ljavax/xml/ws/Service$Mode;)Ljavax/xml/ws/Dispatch;"
> the class loader (instance of
> org/rhq/core/pc/plugin/PluginClassLoader) of the current class,
> com/sun/xml/internal/ws/client/WSServiceDelegate, and its superclass
> loader (instance of <bootloader>), have different Class objects for
> the type javax/xml/bind/JAXBContext used in the signature
>
> Is this an instance of class leakage that was mentioned in a previous
> post? In my reading of LinkageError it sounds like both the bootloader
> and the pluginclassloader have loaded JAXBContext and because of that
> the signatures don't match. The other possibility is that the plugin
> was build using a newer version of jaxb than is present in the jdk.
>
> Question: are the steps we took above correct to implement the
> classloaderfacet.
>
> Bala Nair
>
>
> _______________________________________________
> rhq-devel mailing list
> rhq-devel(a)lists.fedorahosted.org
> https://fedorahosted.org/mailman/listinfo/rhq-devel
13 years, 6 months
classloader hell
by Bala Nair
Ok, we are officially in classloader hell. Our original problem was a
class not found exception when trying to use a class defined in an
external jar in one of our agent plugins. After some good advice and an
explanation of how resource classloaders work, we decided to do the
following.
1. declare an instance classloader for our plugin's server class (in the
rhq-plugin.xml, server element, classloader="instance" attribute)
2. implement the classloaderfacet in the server discovery component
3. add the relevant jars to the classpath for the server resource component
So now we no longer see the class not found exception. instead we get this:
java.util.concurrent.ExecutionException: java.lang.Exception:
java.lang.LinkageError: loader constraint violation: when resolving
overridden method
"com.sun.xml.internal.ws.client.WSServiceDelegate.createDispatch(Ljavax/xml/namespace/QName;Ljavax/xml/bind/JAXBContext;Ljavax/xml/ws/Service$Mode;)Ljavax/xml/ws/Dispatch;"
the class loader (instance of org/rhq/core/pc/plugin/PluginClassLoader)
of the current class, com/sun/xml/internal/ws/client/WSServiceDelegate,
and its superclass loader (instance of <bootloader>), have different
Class objects for the type javax/xml/bind/JAXBContext used in the signature
Is this an instance of class leakage that was mentioned in a previous
post? In my reading of LinkageError it sounds like both the bootloader
and the pluginclassloader have loaded JAXBContext and because of that
the signatures don't match. The other possibility is that the plugin
was build using a newer version of jaxb than is present in the jdk.
Question: are the steps we took above correct to implement the
classloaderfacet.
Bala Nair
13 years, 7 months
quartz scheduler exception
by Bala Nair
We're getting a very strange exception in our rhq server log with the
quartz scheduler. I have done some reading about this on the web and
most of the reports are when you are running clustered. We're not
running clustered, so I'm confused as to why we're seeing this
particular error. The only strange thing we're doing is
uninventorying/reinventorying platforms and servers. We are still able
to use the gui w/o problems, but these exceptions are filling up the log
file. Any help would be appreciated. The stack trace is below:
Bala Nair
2010-09-28 15:18:17,687 WARN
[org.jboss.resource.connectionmanager.JBossManagedConnectionPool]
Throwable while attempting to get a new connection: null
org.jboss.resource.JBossResourceException: Could not create connection;
- nested throwable: (org.postgresql.util.PSQLException: Connection
refused. Check that the hostname and port are correct and that the
postmaster is accepting TCP/IP connections.)
at
org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory.createManagedConnection(LocalManagedConnectionFactory.java:190)
at
org.jboss.resource.connectionmanager.InternalManagedConnectionPool.createConnectionEventListener(InternalManagedConnectionPool.java:619)
at
org.jboss.resource.connectionmanager.InternalManagedConnectionPool.getConnection(InternalManagedConnectionPool.java:264)
at
org.jboss.resource.connectionmanager.JBossManagedConnectionPool$BasePool.getConnection(JBossManagedConnectionPool.java:575)
at
org.jboss.resource.connectionmanager.BaseConnectionManager2.getManagedConnection(BaseConnectionManager2.java:347)
at
org.jboss.resource.connectionmanager.BaseConnectionManager2.getManagedConnection(BaseConnectionManager2.java:332)
at
org.jboss.resource.connectionmanager.BaseConnectionManager2.allocateConnection(BaseConnectionManager2.java:402)
at
org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.allocateConnection(BaseConnectionManager2.java:849)
at
org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:89)
at
org.quartz.utils.JNDIConnectionProvider.getConnection(JNDIConnectionProvider.java:160)
at
org.quartz.utils.DBConnectionManager.getConnection(DBConnectionManager.java:112)
at
org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:164)
at
org.quartz.impl.jdbcjobstore.JobStoreSupport.doCheckin(JobStoreSupport.java:3167)
at
org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.manage(JobStoreSupport.java:3811)
at
org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.run(JobStoreSupport.java:3847)
Caused by: org.postgresql.util.PSQLException: Connection refused. Check
that the hostname and port are correct and that the postmaster is
accepting TCP/IP connections.
at
org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:136)
at
org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
at
org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:125)
at
org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:30)
at org.postgresql.jdbc3.Jdbc3Connection.<init>(Jdbc3Connection.java:24)
at org.postgresql.Driver.makeConnection(Driver.java:393)
at org.postgresql.Driver.connect(Driver.java:267)
at
org.jboss.resource.adapter.jdbc.local.LocalManagedConnectionFactory.createManagedConnection(LocalManagedConnectionFactory.java:172)
... 14 more
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at java.net.Socket.connect(Socket.java:475)
at java.net.Socket.<init>(Socket.java:372)
at java.net.Socket.<init>(Socket.java:186)
at org.postgresql.core.PGStream.<init>(PGStream.java:62)
at
org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:76)
... 21 more
2010-09-28 15:18:17,687 ERROR [org.quartz.impl.jdbcjobstore.JobStoreCMT]
ClusterManager: Error managing cluster: Failed to obtain DB connection
from data source 'NoTxRHQDS': java.sql.SQLException: Could not retrieve
datasource via JNDI url 'java:/NoTxRHQDS'
org.jboss.util.NestedSQLException: Could not create connection; - nested
throwable: (org.postgresql.util.PSQLException: Connection refused. Check
that the hostname and port are correct and that the postmaster is
accepting TCP/IP connections.); - nested throwable:
(org.jboss.resource.JBossResourceException: Could not create connection;
- nested throwable: (org.postgresql.util.PSQLException: Connection
refused. Check that the hostname and port are correct and that the
postmaster is accepting TCP/IP connections.))
org.quartz.JobPersistenceException: Failed to obtain DB connection from
data source 'NoTxRHQDS': java.sql.SQLException: Could not retrieve
datasource via JNDI url 'java:/NoTxRHQDS'
org.jboss.util.NestedSQLException: Could not create connection; - nested
throwable: (org.postgresql.util.PSQLException: Connection refused. Check
that the hostname and port are correct and that the postmaster is
accepting TCP/IP connections.); - nested throwable:
(org.jboss.resource.JBossResourceException: Could not create connection;
- nested throwable: (org.postgresql.util.PSQLException: Connection
refused. Check that the hostname and port are correct and that the
postmaster is accepting TCP/IP connections.)) [See nested exception:
java.sql.SQLException: Could not retrieve datasource via JNDI url
'java:/NoTxRHQDS' org.jboss.util.NestedSQLException: Could not create
connection; - nested throwable: (org.postgresql.util.PSQLException:
Connection refused. Check that the hostname and port are correct and
that the postmaster is accepting TCP/IP connections.); - nested
throwable: (org.jboss.resource.JBossResourceException: Could not create
connection; - nested throwable: (org.postgresql.util.PSQLException:
Connection refused. Check that the hostname and port are correct and
that the postmaster is accepting TCP/IP connections.))]
at
org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:167)
at
org.quartz.impl.jdbcjobstore.JobStoreSupport.doCheckin(JobStoreSupport.java:3167)
at
org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.manage(JobStoreSupport.java:3811)
at
org.quartz.impl.jdbcjobstore.JobStoreSupport$ClusterManager.run(JobStoreSupport.java:3847)
Caused by: java.sql.SQLException: Could not retrieve datasource via JNDI
url 'java:/NoTxRHQDS' org.jboss.util.NestedSQLException: Could not
create connection; - nested throwable:
(org.postgresql.util.PSQLException: Connection refused. Check that the
hostname and port are correct and that the postmaster is accepting
TCP/IP connections.); - nested throwable:
(org.jboss.resource.JBossResourceException: Could not create connection;
- nested throwable: (org.postgresql.util.PSQLException: Connection
refused. Check that the hostname and port are correct and that the
postmaster is accepting TCP/IP connections.))
at
org.quartz.utils.JNDIConnectionProvider.getConnection(JNDIConnectionProvider.java:166)
at
org.quartz.utils.DBConnectionManager.getConnection(DBConnectionManager.java:112)
at
org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:164)
... 3 more
13 years, 7 months
classloader issues using jax-ws in a client plugin
by Bala Nair
We are having issues in our plugin metric collection when we try to
get data from a remote server using a web service interface and the
jax-ws api's. It looks like a class loader issue - the class loader
appears not to have visibility into the jar that contains the web
service provider implementation, but we're to set the classpath
correctly or include the correct jars in the plugin itself. Any help
would be appreciated.
Bala Nair
Senior Engineer
SeaChange International
Here is the relevant agent log section:
2010-09-22 15:53:32,616 DEBUG [MeasurementManager.collector-1]
(rhq.core.pc.inventory.ResourceContainer$ResourceComponentInvocationHandler)-
Call to
[tv.seachange.monitoring.plugins.URM.URMServerComponent.getValues()]
with args [[org.rhq.core.domain.measurement.MeasurementReport@4964784d,
[ScheduledMeasurementInfo[res=10862, name=pg_memory_usage,
sched=16163]]]] failed.
java.util.concurrent.ExecutionException:
javax.xml.ws.WebServiceException: Provider
com.sun.xml.internal.ws.spi.ProviderImpl not found
at
java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:232)
at java.util.concurrent.FutureTask.get(FutureTask.java:91)
at
org.rhq.core.pc.inventory.ResourceContainer$ResourceComponentInvocationHandler.invokeInNewThreadWithLock(ResourceContainer.java:446)
at
org.rhq.core.pc.inventory.ResourceContainer$ResourceComponentInvocationHandler.invoke(ResourceContainer.java:434)
at $Proxy73.getValues(Unknown Source)
at
org.rhq.core.pc.measurement.MeasurementCollectorRunner.getValues(MeasurementCollectorRunner.java:111)
at
org.rhq.core.pc.measurement.MeasurementCollectorRunner.call(MeasurementCollectorRunner.java:91)
at
org.rhq.core.pc.measurement.MeasurementManager$MeasurementCollectionRequester.run(MeasurementManager.java:169)
at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: javax.xml.ws.WebServiceException: Provider
com.sun.xml.internal.ws.spi.ProviderImpl not found
at
javax.xml.ws.spi.FactoryFinder.newInstance(FactoryFinder.java:33)
at javax.xml.ws.spi.FactoryFinder.find(FactoryFinder.java:128)
at javax.xml.ws.spi.Provider.provider(Provider.java:108)
at javax.xml.ws.Service.<init>(Service.java:57)
at
com.netsocket.ws.mgmt.ct.basic.WsAgentService.<init>(WsAgentService.java:50)
at com.schange.urm.WsdmApi.setup(WsdmApi.java:62)
at com.schange.urm.WsdmApi.<init>(WsdmApi.java:29)
at
tv.seachange.monitoring.plugins.URM.URMServerComponent.getValues(URMServerComponent.java:53)
at sun.reflect.GeneratedMethodAccessor124.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.rhq.core.pc.inventory.ResourceContainer$ComponentInvocationThread.call(ResourceContainer.java:525)
at
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
... 3 more
Caused by: java.lang.ClassNotFoundException:
com.sun.xml.internal.ws.spi.ProviderImpl
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at
org.rhq.core.pc.plugin.PluginClassLoader.loadClass(PluginClassLoader.java:63)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at
javax.xml.ws.spi.FactoryFinder.safeLoadClass(FactoryFinder.java:149)
at
javax.xml.ws.spi.FactoryFinder.newInstance(FactoryFinder.java:30)
... 16 more
13 years, 7 months
RHQ 4.0.0 Developer Preview released
by Heiko W.Rupp
Hi,
we have released a RHQ 4 developer preview.
This is NOT FOR PRODUCTION.
To learn more about it go to the release notes page on the Wiki at
http://rhq-project.org/display/RHQ/Release+notes+RHQ+4+DP1
As always: please give us feedback.
Heiko
--
Reg. Adresse: Red Hat GmbH, Otto-Hahn-Strasse 20, 85609 Dornach bei München
Handelsregister: Amtsgericht München HRB 153243
Geschaeftsführer: Brendan Lane, Charlie Peters, Michael Cunningham, Charles Cachera
13 years, 7 months
Gotcha for CoreGUI devs pulling Resource data
by Jay Shaughnessy
Note that there is a filter in place that strips away Resource data
being returned to CoreGUI from findResourcesByCriteria() and
findResourceCompositesByCriteria(). This is not currently
configurable. The fields that make it through are specified at the top
of ResourceGWTServiceImpl.
If you are making either of those calls, and the data you expect back is
not there, then look here to ensure the data is actually not being
stripped away.
This was put in place in an effort to reduce data traffic to the GUI.
Whether it will remain is not certain. But for now it's there.
Jay
13 years, 7 months
calltime metric def?
by John Mazzitelli
I'm in the process of implementing the create-resource-alert-definition pages in GWT. I heard that someone implemented "calltime alerting" in the JSF code. Well, I enabled the metric "HTTP Response Time" (which is a calltime metric) on my "coregui.war" resource under my JBossAS Server resource that represents my RHQ Server.
I then go to the JSF page that created alert defs (that's the temporary "DELETEME" subtab under Alerts tab) and I do not see any way to create a "calltime alert definition". I don't even see the "HTTP Response Time" metric in the metric drop down menu.
Did the calltime alert def stuff make it into master? If so, how do I create a calltime alert def? I need to know specifically how to populate the AlertCondition entity to represent a calltime alert definition condition, but if master branch doesn't support it at all, I won't bother putting it into the GWT UI until that feature is fully ported (e.g. it needs to be ported to the alerting engine on the server-side along with this client side GUI stuff)
13 years, 7 months
projects using RHQ
by Ian Springer
Fyi, we have a new page on the RHQ wiki to keep track of
projects/products that are using RHQ. If you are using RHQ to manage
your project or product, reply to this thread and we'll add it to the page.
Thanks.
- Ian
13 years, 7 months
make method return types in ResourceFactoryManagerRemote non-void?
by John Sanda
The methods in ResourceFactoryManagerRemote have return types of void.
These methods are exposed to remote clients, namely the CLI. I want to
see what folks think about making the return types non-void. In the case
of the create methods, I suggest we return the CreateResourceHistory
object that is persisted as part of these methods. And for the delete
method, we would return the DeleteResourceHistory object. The reason I
propose these changes is that it provides remote clients/CLI scripts a
hook into the progress of these operations which take place out of band.
If for example I write a script to deploy/undeloy an ear or war onto a
jboss server, I don't have a good way to know 1) if/when the operation
completes and 2) if it completes successfully. If we pass back those
history objects, then I can write some more intelligent scripts. I could
make it appear that those operations are blocking while I poll (not
indefinitely) for the history to get updated or I spin off a thread
where I poll so that I can get the updated history asynchronously.
- John
13 years, 7 months
Resource upgrade once more
by Lukas Krejci
Hi team,
there is an unfortunate one last issue with the resource upgrade functionality
that I'd like to get a common agreement on.
But first let me recap the state of resource upgrade functionality as we
decided to implement it.
1) It will only be possible to upgrade resource key, name and description,
with the latter two being disabled on the server side (it'd be easy to add a
GUI switch to switch it on if we see the demand in the community).
2) An upgrade error isn't considered fatal, it is assumed that plugin is
either programmed to handle multiple versions of resource data or that the
failure to upgrade isn't detrimental to the plugin functionality (too much).
3) An upgrade error is going to be merely reported using the resource errors
facility on the server side similarly to how
InvalidPluginConfigurationExceptions are/were reported (some kind of warning
icon and explanatory text).
So now let me explain the issue. The original intention of the whole resource
upgrade effort was to be able to transform an "old" resource with a "new"
resource (transform only means to change its resource key for now).
Now that we have that functionality, let's examine what happens if the upgrade
fails for some reason (a logic error in the plugin code being hopefully the
only possibility here).
1) There is the old resource in the inventory and a new plugin has been
deployed to the server.
2) Agent downloads the new plugin and reinitializes the plugin container.
3) The resource upgrade kicks in, upgrade of the old resource fails, an error
is reported on that resource on the server side.
4) A discovery using the new plugin code is executed on the agent.
5) A new resource is discovered that should have really been the transformed
old resource if the upgrade succeeded.
6) We end up with two logically equal resources in the inventory.
The only way how to prevent this from happening that I can see is to disallow
the discovery for that certain resource type under the old resource's parent
for the lifetime of plugin container (that is until the next upgrade attempt
is made with the next start of plugin container).
But is that acceptable? This way we would basically "conserve" parts of the
inventory in the old state until a new version of the plugin with the fixed
upgrade code would be deployed, which can mean a substantial amount of time
with possibly non-functional resources.
Another way how to fix this would of course be the plugin versioning and
multiple versions of the same plugin being deployed on the agent serving
different resources, but that's a very complicated issue that we agreed to
avoid at all cost.
What are your thoughts?
Thanks,
Lukas
13 years, 7 months