This is an automated email from the ASF dual-hosted git repository.
chia7712 pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git
The following commit(s) were added to refs/heads/trunk by this push:
new 09713a38fbc KAFKA-19749 The `version-mapping` of kafka-features.sh
should work without requiring the bootstrap (#20619)
09713a38fbc is described below
commit 09713a38fbce0a1486749292071a1d926c7fa7f4
Author: Chang-Yu Huang <[email protected]>
AuthorDate: Sat Dec 20 07:56:25 2025 -0500
KAFKA-19749 The `version-mapping` of kafka-features.sh should work without
requiring the bootstrap (#20619)
# Description
In kafka-features.sh, exclusive argument group of `--bootstrap-server`
and `--bootstrap-controller` is required in the main parser, but
`version-mapping` and `feature-dependencies` subcommands don't need the
information.
# Changes
To avoid change in argument level, the exclusive group is not moved. It
is now not required and only check for existence if the subcommand needs
it.
Since `FeatureCommand#mainNoExit` catches `ArgumentParserException`,
`ArgumentParser#parseArgs` is used instead of `parseArgsOrFail`. It
makes testing easier.
Two tests are added. One tests whether not-remote subcommand can execute
without bootstrap. Another tests whether remote subcommand cannot
execute without bootstrap.
Reviewers: Ken Huang <[email protected]>, Jhen-Yung Hsu
<[email protected]>, TaiJuWu <[email protected]>, Chia-Ping Tsai
<[email protected]>
---
.../org/apache/kafka/tools/FeatureCommand.java | 29 ++++++++++++++--------
.../org/apache/kafka/tools/FeatureCommandTest.java | 16 ++++++++++++
2 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/tools/src/main/java/org/apache/kafka/tools/FeatureCommand.java
b/tools/src/main/java/org/apache/kafka/tools/FeatureCommand.java
index 6c16dd0db43..fdcaf5e537f 100644
--- a/tools/src/main/java/org/apache/kafka/tools/FeatureCommand.java
+++ b/tools/src/main/java/org/apache/kafka/tools/FeatureCommand.java
@@ -77,7 +77,7 @@ public class FeatureCommand {
.newArgumentParser("kafka-features")
.defaultHelp(true)
.description("This tool manages feature flags in Kafka.");
- MutuallyExclusiveGroup bootstrapGroup =
parser.addMutuallyExclusiveGroup().required(true);
+ MutuallyExclusiveGroup bootstrapGroup =
parser.addMutuallyExclusiveGroup();
bootstrapGroup.addArgument("--bootstrap-server")
.help("A comma-separated list of host:port pairs to use for
establishing the connection to the Kafka cluster.");
bootstrapGroup.addArgument("--bootstrap-controller")
@@ -93,14 +93,27 @@ public class FeatureCommand {
addVersionMappingParser(subparsers);
addFeatureDependenciesParser(subparsers);
- Namespace namespace = parser.parseArgsOrFail(args);
+ Namespace namespace = parser.parseArgs(args);
String command = namespace.getString("command");
+ if (command.equals("version-mapping")) {
+ handleVersionMapping(namespace, Feature.PRODUCTION_FEATURES);
+ return;
+ } else if (command.equals("feature-dependencies")) {
+ handleFeatureDependencies(namespace, Feature.PRODUCTION_FEATURES);
+ return;
+ }
String configPath = namespace.getString("command_config");
Properties properties = (configPath == null) ? new Properties() :
Utils.loadProps(configPath);
- CommandLineUtils.initializeBootstrapProperties(properties,
- Optional.ofNullable(namespace.getString("bootstrap_server")),
- Optional.ofNullable(namespace.getString("bootstrap_controller")));
+ try {
+ CommandLineUtils.initializeBootstrapProperties(properties,
+
Optional.ofNullable(namespace.getString("bootstrap_server")),
+
Optional.ofNullable(namespace.getString("bootstrap_controller")));
+ } catch (Exception e) {
+ // bootstrap_server and bootstrap_controller are in a mutually
exclusive group,
+ // so the exception happens only when both of them are missing
+ throw new ArgumentParserException(e.getMessage(), parser);
+ }
try (Admin adminClient = Admin.create(properties)) {
switch (command) {
@@ -116,12 +129,6 @@ public class FeatureCommand {
case "disable":
handleDisable(namespace, adminClient);
break;
- case "version-mapping":
- handleVersionMapping(namespace,
Feature.PRODUCTION_FEATURES);
- break;
- case "feature-dependencies":
- handleFeatureDependencies(namespace,
Feature.PRODUCTION_FEATURES);
- break;
default:
throw new TerseException("Unknown command " + command);
}
diff --git a/tools/src/test/java/org/apache/kafka/tools/FeatureCommandTest.java
b/tools/src/test/java/org/apache/kafka/tools/FeatureCommandTest.java
index b079f377b8c..ff6350693b4 100644
--- a/tools/src/test/java/org/apache/kafka/tools/FeatureCommandTest.java
+++ b/tools/src/test/java/org/apache/kafka/tools/FeatureCommandTest.java
@@ -691,6 +691,22 @@ public class FeatureCommandTest {
MetadataVersion.MINIMUM_VERSION, MetadataVersion.latestTesting()),
exception2.getMessage());
}
+ @Test
+ public void testHandleVersionMappingWithoutBootstrap() {
+ Map.Entry<String, String> output =
ToolsTestUtils.grabConsoleOutputAndError(() ->
FeatureCommand.mainNoExit("version-mapping"));
+ assertEquals("", output.getValue());
+ MetadataVersion metadataVersion = MetadataVersion.latestProduction();
+ assertTrue(output.getKey().contains("metadata.version=" +
metadataVersion.featureLevel() + " (" + metadataVersion.version() + ")"),
+ "Output did not contain expected Metadata Version: " +
output.getKey());
+ }
+
+ @Test
+ public void testHandleRemoteCommandWithoutBootstrap() {
+ String errorMessage = ToolsTestUtils.grabConsoleError(() ->
FeatureCommand.mainNoExit("upgrade"));
+ assertTrue(errorMessage.contains("You must specify either
--bootstrap-controller " +
+ "or --bootstrap-server."));
+ }
+
@Test
public void testHandleFeatureDependenciesForFeatureWithDependencies() {
Map<String, Object> namespace = new HashMap<>();