Shinjo Wang created NIFI-16481:
----------------------------------

             Summary: Kafka3ConnectionService cannot be enabled until restart 
after a dynamic property is set through the REST API: NoClassDefFoundError for 
ProducerConfig
                 Key: NIFI-16481
                 URL: https://issues.apache.org/jira/browse/NIFI-16481
             Project: Apache NiFi
          Issue Type: Bug
          Components: Core Framework, Extensions
    Affects Versions: 2.12.0, 2.11.0, 2.6.0
         Environment: NiFi 2.6.0, 2.11.0, 2.12.0 (apache/nifi Docker images, 
linux/arm64), standalone, single-user authentication
Not reproducible on NiFi 2.5.0 (kafka-clients 4.0.0)
            Reporter: Shinjo Wang


h3. Summary

After NiFi starts, if the first code path that initializes {{ProducerConfig}} 
in {{nifi-kafka-3-service-nar}} is a REST request that creates or updates a 
Kafka3ConnectionService with a dynamic property (for example 
{{metadata.max.age.ms}}), the request returns HTTP 500. After that, no 
Kafka3ConnectionService can be enabled until NiFi is restarted. Services stay 
in ENABLING with {{NoClassDefFoundError: Could not initialize class 
org.apache.kafka.clients.producer.ProducerConfig}}.

This affects NiFi 2.6.0 and later (kafka-clients 4.1.0 and later).

h3. Steps to Reproduce

# Start NiFi with an empty flow, for example {{apache/nifi:2.12.0}}. Do not 
add, enable, or verify any Kafka component first.
# Create a Kafka3ConnectionService with a dynamic property. This returns HTTP 
500.
{code:bash}
curl -sk -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' 
-X POST \
  https://localhost:8443/nifi-api/process-groups/$PG/controller-services -d '{
  "revision":{"version":0},
  "component":{
    "type":"org.apache.nifi.kafka.service.Kafka3ConnectionService",
    
"properties":{"bootstrap.servers":"localhost:9092","metadata.max.age.ms":"60000"}}}'
{code}
# Create a Kafka3ConnectionService without dynamic properties and enable it. It 
stays in ENABLING.

If a Kafka3ConnectionService without dynamic properties is enabled before step 
2, the problem does not occur. The UI does not reproduce it, probably because 
it calls {{GET /controller-services/\{id\}/descriptors}} first, which uses the 
NAR class loader.

h3. Errors

{noformat}
ERROR [NiFi Web Server-31] o.a.nifi.web.api.config.ThrowableMapper An 
unexpected error has occurred: java.lang.ExceptionInInitializerError. Returning 
Internal Server Error response.
java.lang.ExceptionInInitializerError: null
        at 
org.apache.nifi.kafka.shared.property.provider.StandardKafkaPropertyNameProvider.<init>(StandardKafkaPropertyNameProvider.java:48)
        at 
org.apache.nifi.kafka.shared.validation.DynamicPropertyValidator.<init>(DynamicPropertyValidator.java:39)
        at 
org.apache.nifi.kafka.service.Kafka3ConnectionService.getSupportedDynamicPropertyDescriptor(Kafka3ConnectionService.java:219)
        at 
org.apache.nifi.components.AbstractConfigurableComponent.getPropertyDescriptor(AbstractConfigurableComponent.java:56)
        at 
org.apache.nifi.authorization.StandardAuthorizableLookup$ConfigurableComponentAuthorizable.getPropertyDescriptor(StandardAuthorizableLookup.java:871)
        at 
org.apache.nifi.authorization.AuthorizeControllerServiceReference.authorizeControllerServiceReferences(AuthorizeControllerServiceReference.java:91)
        at 
org.apache.nifi.web.api.ProcessGroupResource.lambda$createControllerService$55(ProcessGroupResource.java:2557)
        ...
Caused by: org.apache.kafka.common.config.ConfigException: Invalid value 
org.apache.kafka.common.security.oauthbearer.DefaultJwtRetriever for 
configuration sasl.oauthbearer.jwt.retriever.class: Class 
org.apache.kafka.common.security.oauthbearer.DefaultJwtRetriever could not be 
found.
        at 
org.apache.kafka.common.config.ConfigDef.parseType(ConfigDef.java:778)
        ...
        at 
org.apache.kafka.clients.producer.ProducerConfig.<clinit>(ProducerConfig.java:518)
{noformat}

h3. Root Cause

# *The framework calls component code without the component NAR class loader 
during authorization.* {{AuthorizeControllerServiceReference}} calls 
{{getPropertyDescriptor(name)}} for each requested property. 
{{StandardAuthorizableLookup.ConfigurableComponentAuthorizable}} (create) and 
{{ControllerServiceComponentAuthorizable}} (update) call the component 
directly, so the call runs with the Jetty thread context class loader. 
{{AbstractComponentNode.getPropertyDescriptor}} and 
{{ProcessorComponentAuthorizable}} already switch to the NAR class loader. The 
authorizables for Reporting Tasks, Flow Analysis Rules, Parameter Providers, 
and Flow Registry Clients have the same gap.
# *ProducerConfig static initialization depends on the thread context class 
loader in kafka-clients 4.1.0 and later.* For an undefined property name, 
Kafka3ConnectionService creates 
{{DynamicPropertyValidator(ProducerConfig.class, ...)}}, which reads the static 
fields of {{ProducerConfig}}. Since kafka-clients 4.1.0, the static initializer 
resolves the default {{DefaultJwtRetriever}} class through the thread context 
class loader (KAFKA-21107). The Jetty class loader cannot see kafka-clients, so 
initialization fails, and the JVM keeps {{ProducerConfig}} unusable in that NAR 
class loader.

NiFi 2.5.0 has the same framework code path, but kafka-clients 4.0.0 has no 
such default, so it does not fail. The upgrade to kafka-clients 4.1.0 in 
NIFI-14937 exposed the problem. The dynamic property code path was added in 
NIFI-14271.

h3. Workaround

After a restart, enable a Kafka3ConnectionService without dynamic properties 
before setting a dynamic property through the REST API.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to