[
https://issues.apache.org/jira/browse/NIFI-15365?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Bob Paulin updated NIFI-15365:
------------------------------
Description:
When Verifying configuration on a newly created DBCPConnectionPool (Controller
Service) the user is presented with an error [1]
Driver Class found but not loaded: Apply configuration before verifying.
This is due to the StandardControllerServiceNode.verifyConfiguration method
creating a new instance classloader [2] but still using the original controller
service [3] that was loaded with the original ControllerService instance class
loader any usage of Class.forName with in the controller service (or any
included sdks) will not be able to see additional urls included in the new
instance classloader [2].
*Proposal* (patch in progress)
For this to work a new temporary controller service must be created with the
new instance classloader and verify must be called on the temporary controller
service.
Will look to model this after the component reload that takes the following
actions (required or maybe required actions in this process bolded)
*1) get existing instance class loader*
*a) Save reference to original instance classloader to a variable*
b)Close classloader and call on remove [We should not close the classloader
as it is still needed or call on remove]
*2) Create new controller service.*
*A) Invoke build Controller service*
*i) Create Instance Class loader.*
*ii) get raw class*
*iii) set thread context class loader as new detected instance class loader*
*iv) Subclass raw class as ControllerService*
*v) Invoke Declared Constructor on class to instantiate impl*
vi) Create invocation handler for implementation [No needed controller
service will not be proxied].
vii) Extract all interfaces to create proxy service [No needed controller
service will not be proxied]
*viii) Build Initialization context with loggers, state managers, kerberos
etc. Invoke initialization. [ Propose doing this with a mock. Risk does
validation ever consider the original controller’s state management?
Kerberos?]*
ix) Verify controller service references to prevent issues with instance
class loading where service api and impls are in same nar but should not be [
Doesn’t matter should have already failed on initial controller creation]
x) Create new Controller Service Node and Validation context [Don’t need a
new node just to validate]
*xi) Set controller service node name, logging context, [node name not
needed…. Do we need the logging context? Maybe].*
xii) set Invocation handler service node as newly create service node. [ not
needed proxy won’t be used]
*xiii) set thread context back to original thread context class loader*
*B) if first time invoke on configuration restored and on added [ Do we need
controller service lifecycle called? Maybe but we definitely should not call
any framework methods]*
3) Put controller Service in process group [ Not needed we’ll be destroying
after validation]
4) Set invocation handler to existing node [ Not needed we’ll be destroying
after validation]
5) Create loggable components (implement and proxy) [ Not needed we’ll be
destroying after validation]
6) set luggable components into existing node and set extension missing [Not
needed we’ll be destroying after validation]
7) Refresh properties on existing node [ Not needed we’ll should be able to
pass properties in directly to verify]
8) Reset Validation State on existing node [ Not needed we’ll be destroying
after validation]
9) trigger validation on existing node. [ Not needed we’ll be destroying after
validation]
Note: This works fine if the Property defining the driver location is defined
as a Parameter within a Parameter Context because the apply action in the UI
reloads the controller service [4]
[1][https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-extension-bundles/nifi-extension-utils/nifi-dbcp-base/src/main/java/org/apache/nifi/dbcp/AbstractDBCPConnectionPool.java#L132C45-L132C117]
[2][https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java#L541]
[3]
[https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java#L544]
[4]
[https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java#L368]
was:
When Verifying configuration on a newly created DBCPConnectionPool (Controller
Service) the user is presented with an error [1]
Driver Class found but not loaded: Apply configuration before verifying.
This is due to the StandardControllerServiceNode.verifyConfiguration method
creating a new instance classloader [2] but still using the original controller
service [3] that was loaded with the original ControllerService instance class
loader any usage of Class.forName with in the controller service (or any
included sdks) will not be able to see additional urls included in the new
instance classloader [2].
*Proposal* (patch in progress)
For this to work a new temporary controller service must be created with the
new instance classloader and verify must be called on the temporary controller
service.
Will look to model this after the component reload that takes the following
actions (required or maybe required actions in this process bolded)
*1) get existing instance class loader and close calling on remove*
*2) Create new controller service.*
*A) Invoke build Controller service*
*i) Create Instance Class loader.*
*ii) get raw class*
*iii) set thread context class loader as new detected instance class loader*
*iv) Subclass raw class as ControllerService*
*v) Invoke Declared Constructor on class to instantiate impl*
vi) Create invocation handler for implementation [No needed controller
service will not be proxied].
vii) Extract all interfaces to create proxy service [No needed controller
service will not be proxied]
*viii) Build Initialization context with loggers, state managers, kerberos
etc. Invoke initialization. [ Propose doing this with a mock. Risk does
validation ever consider the original controller’s state management?
Kerberos?]*
ix) Verify controller service references to prevent issues with instance
class loading where service api and impls are in same nar but should not be [
Doesn’t matter should have already failed on initial controller creation]
x) Create new Controller Service Node and Validation context [Don’t need a
new node just to validate]
*xi) Set controller service node name, logging context, [node name not
needed…. Do we need the logging context? Maybe].*
xii) set Invocation handler service node as newly create service node. [ not
needed proxy won’t be used]
*xiii) set thread context back to original thread context class loader*
*B) if first time invoke on configuration restored and on added [ Do we need
controller service lifecycle called? Maybe but we definitely should not call
any framework methods]*
3) Put controller Service in process group [ Not needed we’ll be destroying
after validation]
4) Set invocation handler to existing node [ Not needed we’ll be destroying
after validation]
5) Create loggable components (implement and proxy) [ Not needed we’ll be
destroying after validation]
6) set luggable components into existing node and set extension missing [Not
needed we’ll be destroying after validation]
7) Refresh properties on existing node [ Not needed we’ll should be able to
pass properties in directly to verify]
8) Reset Validation State on existing node [ Not needed we’ll be destroying
after validation]
9) trigger validation on existing node. [ Not needed we’ll be destroying after
validation]
Note: This works fine if the Property defining the driver location is defined
as a Parameter within a Parameter Context because the apply action in the UI
reloads the controller service [4]
[1][https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-extension-bundles/nifi-extension-utils/nifi-dbcp-base/src/main/java/org/apache/nifi/dbcp/AbstractDBCPConnectionPool.java#L132C45-L132C117]
[2][https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java#L541]
[3]
[https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java#L544]
[4]
[https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java#L368]
> Classloader used during Controller Service Verify Configuration missing
> additional resources
> --------------------------------------------------------------------------------------------
>
> Key: NIFI-15365
> URL: https://issues.apache.org/jira/browse/NIFI-15365
> Project: Apache NiFi
> Issue Type: Bug
> Components: Core Framework
> Affects Versions: 2.7.0
> Reporter: Bob Paulin
> Priority: Major
>
> When Verifying configuration on a newly created DBCPConnectionPool
> (Controller Service) the user is presented with an error [1]
> Driver Class found but not loaded: Apply configuration before verifying.
> This is due to the StandardControllerServiceNode.verifyConfiguration method
> creating a new instance classloader [2] but still using the original
> controller service [3] that was loaded with the original ControllerService
> instance class loader any usage of Class.forName with in the controller
> service (or any included sdks) will not be able to see additional urls
> included in the new instance classloader [2].
>
> *Proposal* (patch in progress)
> For this to work a new temporary controller service must be created with the
> new instance classloader and verify must be called on the temporary
> controller service.
> Will look to model this after the component reload that takes the following
> actions (required or maybe required actions in this process bolded)
> *1) get existing instance class loader*
> *a) Save reference to original instance classloader to a variable*
> b)Close classloader and call on remove [We should not close the
> classloader as it is still needed or call on remove]
> *2) Create new controller service.*
> *A) Invoke build Controller service*
> *i) Create Instance Class loader.*
> *ii) get raw class*
> *iii) set thread context class loader as new detected instance class
> loader*
> *iv) Subclass raw class as ControllerService*
> *v) Invoke Declared Constructor on class to instantiate impl*
> vi) Create invocation handler for implementation [No needed controller
> service will not be proxied].
> vii) Extract all interfaces to create proxy service [No needed controller
> service will not be proxied]
> *viii) Build Initialization context with loggers, state managers, kerberos
> etc. Invoke initialization. [ Propose doing this with a mock. Risk does
> validation ever consider the original controller’s state management?
> Kerberos?]*
> ix) Verify controller service references to prevent issues with instance
> class loading where service api and impls are in same nar but should not be [
> Doesn’t matter should have already failed on initial controller creation]
> x) Create new Controller Service Node and Validation context [Don’t need a
> new node just to validate]
> *xi) Set controller service node name, logging context, [node name not
> needed…. Do we need the logging context? Maybe].*
> xii) set Invocation handler service node as newly create service node. [
> not needed proxy won’t be used]
> *xiii) set thread context back to original thread context class loader*
> *B) if first time invoke on configuration restored and on added [ Do we need
> controller service lifecycle called? Maybe but we definitely should not call
> any framework methods]*
> 3) Put controller Service in process group [ Not needed we’ll be destroying
> after validation]
> 4) Set invocation handler to existing node [ Not needed we’ll be destroying
> after validation]
> 5) Create loggable components (implement and proxy) [ Not needed we’ll be
> destroying after validation]
> 6) set luggable components into existing node and set extension missing [Not
> needed we’ll be destroying after validation]
> 7) Refresh properties on existing node [ Not needed we’ll should be able to
> pass properties in directly to verify]
> 8) Reset Validation State on existing node [ Not needed we’ll be destroying
> after validation]
> 9) trigger validation on existing node. [ Not needed we’ll be destroying
> after validation]
>
> Note: This works fine if the Property defining the driver location is defined
> as a Parameter within a Parameter Context because the apply action in the UI
> reloads the controller service [4]
> [1][https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-extension-bundles/nifi-extension-utils/nifi-dbcp-base/src/main/java/org/apache/nifi/dbcp/AbstractDBCPConnectionPool.java#L132C45-L132C117]
>
>
> [2][https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java#L541]
> [3]
> [https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java#L544]
> [4]
> [https://github.com/apache/nifi/blob/09cfea2f5458474ec9f365370ca0b44741a65a93/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java#L368]
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)