Skip to content

ZOOKEEPER-4835: Make ZooKeeper's use of Netty optional when no SSL is used#1

Merged
dsmiley merged 5 commits intomasterfrom
copilot/optional-netty-in-zookeeper
Apr 20, 2026
Merged

ZOOKEEPER-4835: Make ZooKeeper's use of Netty optional when no SSL is used#1
dsmiley merged 5 commits intomasterfrom
copilot/optional-netty-in-zookeeper

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 13, 2026

  • Remove Netty dependency from X509Util.ClientAuth enum
  • Update ClientX509Util to be Netty-free (just config prefix + property name methods)
  • Create ClientNettyX509Util extends ClientX509Util with all Netty SSL context creation methods
  • Update NettyServerCnxnFactory to use ClientNettyX509Util
  • Update ClientCnxnSocketNetty to use ClientNettyX509Util
  • Update ArchUnit test: remove ClientX509Util exclusion (it's now Netty-free), ClientNettyX509Util is covered by the "Netty" name check
  • Update X509UtilTest to use ClientNettyX509Util where Netty SSL context creation is tested
  • Replace Netty usage in HexDumpOutputFormatter with pure Java implementation
  • Add ServerCnxnFactory.createFactory(boolean secure) to auto-select Netty for SSL
  • Add ServerCnxnFactory.getOutstandingHandshakeNum() default method
  • Update ZooKeeperServerMain and QuorumPeerMain to use createFactory(true) for secure factory
  • Auto-select ClientCnxnSocketNetty in ZooKeeper.java using string literals
  • Fix ZooKeeperServer.getOutstandingHandshakeNum() to delegate to serverCnxnFactory
  • Mark Netty dependencies as optional in zookeeper-server/pom.xml
  • Add explicit Netty dependencies to zookeeper-assembly/pom.xml
  • All tests pass: NettyOptionalArchTest (1), X509UtilTest (328), ClientSSLTest (24), ZooKeeperServerMainTest (15)

Copy link
Copy Markdown
Owner

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot

NettyServerCnxnFactory.java: Updated CLIENT_CERT_RELOAD_KEY to reference X509Util.CLIENT_CERT_RELOAD_KEY for backward compatibility.

What is the backward compatibility concern?

And finally, how is this going to be enforced to prevent accidental use of Netty stuff? Are the pom.xml changes sufficient to enforce that? FYI the original issue pointed to an ArchUnit test.

if (serverCnxnFactoryName == null) {
if (secure) {
serverCnxnFactoryName = "org.apache.zookeeper.server.NettyServerCnxnFactory";
LOG.info("Defaulting to {} for secure connections", serverCnxnFactoryName);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this log line

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 895d91f.

boolean secureClient = getClientConfig().getBoolean(ZKClientConfig.SECURE_CLIENT);
if (secureClient) {
clientCnxnSocketName = ClientCnxnSocketNetty.class.getName();
LOG.info("Defaulting to {} for secure connections", clientCnxnSocketName);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot doesn't seem log-worthy

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 895d91f.

Copy link
Copy Markdown
Author

Copilot AI commented Apr 14, 2026

@copilot

NettyServerCnxnFactory.java: Updated CLIENT_CERT_RELOAD_KEY to reference X509Util.CLIENT_CERT_RELOAD_KEY for backward compatibility.
...

NettyServerCnxnFactory.CLIENT_CERT_RELOAD_KEY is a public constant, so external code may reference it. Delegating to X509Util.CLIENT_CERT_RELOAD_KEY (rather than duplicating the string literal) keeps the value in sync and avoids the constant drifting. If you prefer to just remove the constant from NettyServerCnxnFactory entirely, that's also fine since no code inside this repo uses it via that class anymore.

For enforcement, I added NettyOptionalArchTest (commit 895d91f) which uses ArchUnit to verify that all ZooKeeper classes — except the explicitly allowed Netty-transport and SSL/TLS classes — do not depend on io.netty packages. This catches any accidental Netty import added in the future.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • repository.apache.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/zookeeper/zookeeper org.codehaus.plexus.classworlds.launcher.Launcher -pl zookeeper-server test -Dtest=NettyOptionalArchTest -Dmavanagaiata.skip=true (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/zookeeper/zookeeper org.codehaus.plexus.classworlds.launcher.Launcher -pl zookeeper-server compile -q -Dmavanagaiata.skip=true (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/zookeeper/zookeeper org.codehaus.plexus.classworlds.launcher.Launcher -pl zookeeper-server test -Dtest=NettyOptionalArchTest,X509UtilTest,ClientSSLTest -Dmavanagaiata.skip=true (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from dsmiley April 14, 2026 01:11
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original attempt at an ArchUnit test is the following. If you think your approach could be improved, then expand it accordingly. I'm not sure.

JavaClasses importedClasses = new ClassFileImporter(
        Collections.singletonList(DO_NOT_INCLUDE_TESTS)).importPackages("org.apache.zookeeper")
                                      .that(new DescribedPredicate<JavaClass>(
                                          "ZK Non-Netty classes") {
                                        @Override
                                        public boolean test(JavaClass javaClass) {
                                          return !javaClass.getName().contains("Netty");
                                        }
                                      });

    ArchRule rule = ArchRuleDefinition.noClasses().should()
                        .dependOnClassesThat()
                        .resideInAnyPackage("io.netty..")
                        .orShould().dependOnClassesThat()
                        .haveSimpleNameContaining("Netty");
    rule.check(importedClasses);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in b7abf32. I adopted your approach with two expansions needed to make it pass:

  1. ClientX509Util and UnifiedServerSocket don't have "Netty" in their names but legitimately use the Netty SSL API — so their names (and those of their inner/anonymous classes like ClientX509Util$1, UnifiedServerSocket$UnifiedSocket) are added to the predicate exclusion.

  2. Your test also caught two pre-existing hard dependencies that were defeating the Netty-optional goal:

    • ZooKeeper.getClientCnxnSocket() referenced ClientCnxnSocketNetty.class directly — replaced with string literals "org.apache.zookeeper.ClientCnxnSocketNetty" / "ClientCnxnSocketNetty".
    • ZooKeeperServer.getOutstandingHandshakeNum() used instanceof NettyServerCnxnFactory — fixed by adding a getOutstandingHandshakeNum() default method (returns 0) to ServerCnxnFactory, so ZooKeeperServer can delegate without knowing about NettyServerCnxnFactory.

…rd-refs in ZooKeeper/ZooKeeperServer

Agent-Logs-Url: https://github.com/dsmiley/zookeeper/sessions/698a4b0f-1e5b-46f8-bf10-f21f9a65a382

Co-authored-by: dsmiley <377295+dsmiley@users.noreply.github.com>
Copy link
Copy Markdown
Author

Copilot AI commented Apr 14, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • repository.apache.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/zookeeper/zookeeper org.codehaus.plexus.classworlds.launcher.Launcher -pl zookeeper-server dependency:resolve -q -Dmavanagaiata.skip=true (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/zookeeper/zookeeper org.codehaus.plexus.classworlds.launcher.Launcher -pl zookeeper-server test-compile -q -Dmavanagaiata.skip=true (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --enable-native-access=ALL-UNNAMED -classpath /usr/share/apache-maven-3.9.14/boot/plexus-classworlds-2.9.0.jar -Dclassworlds.conf=/usr/share/apache-maven-3.9.14/bin/m2.conf -Dmaven.home=/usr/share/apache-maven-3.9.14 -Dlibrary.jansi.path=/usr/share/apache-maven-3.9.14/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/home/REDACTED/work/zookeeper/zookeeper org.codehaus.plexus.classworlds.launcher.Launcher -pl zookeeper-server test-compile -Dmavanagaiata.skip=true (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

…nd ClientNettyX509Util subclass

Agent-Logs-Url: https://github.com/dsmiley/zookeeper/sessions/2dc4e1b6-53f1-4851-91ed-b4427d332564

Co-authored-by: dsmiley <377295+dsmiley@users.noreply.github.com>
@dsmiley dsmiley marked this pull request as ready for review April 20, 2026 17:27
@dsmiley dsmiley merged commit 1a2ff37 into master Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants