Skip to content

Commit 3f1d830

Browse files
authored
MINOR: Remove duplicate renewTimePeriodOpt in DelegationTokenCommand validation (#20177)
The bug was a duplicate parameter validation in the `DelegationTokenCommand` class. The `checkInvalidArgs` method for the `describeOpt` was incorrectly including `renewTimePeriodOpt` twice in the set of invalid arguments. This bug caused unexpected command errors during E2E testing. ### Before the fix: The following command would fail due to the duplicate validation logic: ``` TC_PATHS="tests/kafkatest/tests/core/delegation_token_test.py::DelegationTokenTest" /bin/bash tests/docker/run_tests.sh ``` ### Error output: ``` ducktape.cluster.remoteaccount.RemoteCommandError: ducker@ducker03: Command 'KAFKA_OPTS="-Djava.security.auth.login.config=/mnt/security/jaas.conf -Djava.security.krb5.conf=/mnt/security/krb5.conf" /opt/kafka-dev/bin/kafka-delegation-tokens.sh --bootstrap-server ducker03:9094 --create --max-life-time-period -1 --command-config /mnt/kafka/client.properties > /mnt/kafka/delegation_token.out' returned non-zero exit status 1. Remote error message: b'duplicate element: [renew-time-period]\njava.lang.IllegalArgumentException: duplicate element: [renew-time-period]\n\tat java.base/java.util.ImmutableCollections$SetN.<init>(ImmutableCollections.java:918)\n\tat java.base/java.util.Set.of(Set.java:544)\n\tat org.apache.kafka.tools.DelegationTokenCommand$DelegationTokenCommandOptions.checkArgs(DelegationTokenCommand.java:304)\n\tat org.apache.kafka.tools.DelegationTokenCommand.execute(DelegationTokenCommand.java:79)\n\tat org.apache.kafka.tools.DelegationTokenCommand.mainNoExit(DelegationTokenCommand.java:57)\n\tat org.apache.kafka.tools.DelegationTokenCommand.main(DelegationTokenCommand.java:52)\n\n' [INFO:2025-07-31 11:27:25,531]: RunnerClient: kafkatest.tests.core.delegation_token_test.DelegationTokenTest.test_delegation_token_lifecycle.metadata_quorum=ISOLATED_KRAFT: Data: None ================================================================================ SESSION REPORT (ALL TESTS) ducktape version: 0.12.0 session_id: 2025-07-31--002 run time: 33.213 seconds tests run: 1 passed: 0 flaky: 0 failed: 1 ignored: 0 ================================================================================ test_id: kafkatest.tests.core.delegation_token_test.DelegationTokenTest.test_delegation_token_lifecycle.metadata_quorum=ISOLATED_KRAFT status: FAIL run time: 33.090 seconds ``` ### After the fix: The same command now executes successfully: ``` TC_PATHS="tests/kafkatest/tests/core/delegation_token_test.py::DelegationTokenTest" /bin/bash tests/docker/run_tests.sh ``` ### Success output: ``` ================================================================================ SESSION REPORT (ALL TESTS) ducktape version: 0.12.0 session_id: 2025-07-31--001 run time: 35.488 seconds tests run: 1 passed: 1 flaky: 0 failed: 0 ignored: 0 ================================================================================ test_id: kafkatest.tests.core.delegation_token_test.DelegationTokenTest.test_delegation_token_lifecycle.metadata_quorum=ISOLATED_KRAFT status: PASS run time: 35.363 seconds -------------------------------------------------------------------------------- ``` Reviewers: Jhen-Yung Hsu <jhenyunghsu@gmail.com>, TengYao Chi <frankvicky@apache.org>, Ken Huang <s7133700@gmail.com>, PoAn Yang <payang@apache.org>, Chia-Ping Tsai <chia7712@gmail.com>
1 parent 05d71ad commit 3f1d830

File tree

2 files changed

+154
-1
lines changed

2 files changed

+154
-1
lines changed

tools/src/main/java/org/apache/kafka/tools/DelegationTokenCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public void checkArgs() {
300300
CommandLineUtils.checkInvalidArgs(parser, options, createOpt, Set.of(hmacOpt, renewTimePeriodOpt, expiryTimePeriodOpt));
301301
CommandLineUtils.checkInvalidArgs(parser, options, renewOpt, Set.of(renewPrincipalsOpt, maxLifeTimeOpt, expiryTimePeriodOpt, ownerPrincipalsOpt));
302302
CommandLineUtils.checkInvalidArgs(parser, options, expiryOpt, Set.of(renewOpt, maxLifeTimeOpt, renewTimePeriodOpt, ownerPrincipalsOpt));
303-
CommandLineUtils.checkInvalidArgs(parser, options, describeOpt, Set.of(renewTimePeriodOpt, maxLifeTimeOpt, hmacOpt, renewTimePeriodOpt, expiryTimePeriodOpt));
303+
CommandLineUtils.checkInvalidArgs(parser, options, describeOpt, Set.of(renewTimePeriodOpt, maxLifeTimeOpt, hmacOpt, expiryTimePeriodOpt));
304304
}
305305
}
306306
}

tools/src/test/java/org/apache/kafka/tools/DelegationTokenCommandTest.java

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.kafka.clients.admin.Admin;
2020
import org.apache.kafka.clients.admin.MockAdminClient;
2121
import org.apache.kafka.common.security.token.delegation.DelegationToken;
22+
import org.apache.kafka.common.utils.Exit;
2223

2324
import org.junit.jupiter.api.Test;
2425

@@ -109,4 +110,156 @@ private DelegationTokenCommand.DelegationTokenCommandOptions getExpireOpts(Strin
109110
String[] args = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--expiry-time-period", "-1", "--hmac", hmac};
110111
return new DelegationTokenCommand.DelegationTokenCommandOptions(args);
111112
}
113+
114+
115+
@Test
116+
public void testCheckArgsMissingRequiredArgs() {
117+
Exit.setExitProcedure((exitCode, message) -> {
118+
throw new RuntimeException("Exit with code " + exitCode + ": " + message);
119+
});
120+
try {
121+
String[] argsCreateMissingBootstrap = {"--command-config", "testfile", "--create", "--max-life-time-period", "604800000"};
122+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreateMissingBootstrap = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreateMissingBootstrap);
123+
assertThrows(RuntimeException.class, optsCreateMissingBootstrap::checkArgs);
124+
125+
String[] argsCreateMissingConfig = {"--bootstrap-server", "localhost:9092", "--create", "--max-life-time-period", "604800000"};
126+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreateMissingConfig = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreateMissingConfig);
127+
assertThrows(RuntimeException.class, optsCreateMissingConfig::checkArgs);
128+
129+
String[] argsCreateMissingMaxLife = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--create"};
130+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreateMissingMaxLife = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreateMissingMaxLife);
131+
assertThrows(RuntimeException.class, optsCreateMissingMaxLife::checkArgs);
132+
133+
String[] argsRenewMissingBootstrap = {"--command-config", "testfile", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000"};
134+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewMissingBootstrap = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewMissingBootstrap);
135+
assertThrows(RuntimeException.class, optsRenewMissingBootstrap::checkArgs);
136+
137+
String[] argsRenewMissingConfig = {"--bootstrap-server", "localhost:9092", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000"};
138+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewMissingConfig = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewMissingConfig);
139+
assertThrows(RuntimeException.class, optsRenewMissingConfig::checkArgs);
140+
141+
String[] argsRenewMissingHmac = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--renew-time-period", "604800000"};
142+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewMissingHmac = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewMissingHmac);
143+
assertThrows(RuntimeException.class, optsRenewMissingHmac::checkArgs);
144+
145+
String[] argsRenewMissingRenewTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--hmac", "test-hmac"};
146+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewMissingRenewTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewMissingRenewTime);
147+
assertThrows(RuntimeException.class, optsRenewMissingRenewTime::checkArgs);
148+
149+
String[] argsExpireMissingBootstrap = {"--command-config", "testfile", "--expire", "--hmac", "test-hmac", "--expiry-time-period", "604800000"};
150+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireMissingBootstrap = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireMissingBootstrap);
151+
assertThrows(RuntimeException.class, optsExpireMissingBootstrap::checkArgs);
152+
153+
String[] argsExpireMissingConfig = {"--bootstrap-server", "localhost:9092", "--expire", "--hmac", "test-hmac", "--expiry-time-period", "604800000"};
154+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireMissingConfig = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireMissingConfig);
155+
assertThrows(RuntimeException.class, optsExpireMissingConfig::checkArgs);
156+
157+
String[] argsExpireMissingHmac = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--expiry-time-period", "604800000"};
158+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireMissingHmac = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireMissingHmac);
159+
assertThrows(RuntimeException.class, optsExpireMissingHmac::checkArgs);
160+
161+
String[] argsExpireMissingExpiryTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--hmac", "test-hmac"};
162+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireMissingExpiryTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireMissingExpiryTime);
163+
assertThrows(RuntimeException.class, optsExpireMissingExpiryTime::checkArgs);
164+
165+
String[] argsDescribeMissingBootstrap = {"--command-config", "testfile", "--describe"};
166+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribeMissingBootstrap = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribeMissingBootstrap);
167+
assertThrows(RuntimeException.class, optsDescribeMissingBootstrap::checkArgs);
168+
169+
String[] argsDescribeMissingConfig = {"--bootstrap-server", "localhost:9092", "--describe"};
170+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribeMissingConfig = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribeMissingConfig);
171+
assertThrows(RuntimeException.class, optsDescribeMissingConfig::checkArgs);
172+
} finally {
173+
Exit.resetExitProcedure();
174+
}
175+
}
176+
177+
@Test
178+
public void testCheckArgsInvalidArgs() {
179+
Exit.setExitProcedure((exitCode, message) -> {
180+
throw new RuntimeException("Exit with code " + exitCode + ": " + message);
181+
});
182+
try {
183+
String[] argsCreateWithHmac = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--create", "--max-life-time-period", "604800000", "--hmac", "test-hmac"};
184+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreateWithHmac = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreateWithHmac);
185+
assertThrows(RuntimeException.class, optsCreateWithHmac::checkArgs);
186+
187+
String[] argsCreateWithRenewTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--create", "--max-life-time-period", "604800000", "--renew-time-period", "604800000"};
188+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreateWithRenewTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreateWithRenewTime);
189+
assertThrows(RuntimeException.class, optsCreateWithRenewTime::checkArgs);
190+
191+
String[] argsCreateWithExpiryTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--create", "--max-life-time-period", "604800000", "--expiry-time-period", "604800000"};
192+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreateWithExpiryTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreateWithExpiryTime);
193+
assertThrows(RuntimeException.class, optsCreateWithExpiryTime::checkArgs);
194+
195+
String[] argsRenewWithRenewPrincipals = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000", "--renewer-principal", "User:renewer"};
196+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewWithRenewPrincipals = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewWithRenewPrincipals);
197+
assertThrows(RuntimeException.class, optsRenewWithRenewPrincipals::checkArgs);
198+
199+
String[] argsRenewWithMaxLife = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000", "--max-life-time-period", "604800000"};
200+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewWithMaxLife = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewWithMaxLife);
201+
assertThrows(RuntimeException.class, optsRenewWithMaxLife::checkArgs);
202+
203+
String[] argsRenewWithExpiryTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000", "--expiry-time-period", "604800000"};
204+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewWithExpiryTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewWithExpiryTime);
205+
assertThrows(RuntimeException.class, optsRenewWithExpiryTime::checkArgs);
206+
207+
String[] argsRenewWithOwner = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000", "--owner-principal", "User:owner"};
208+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenewWithOwner = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenewWithOwner);
209+
assertThrows(RuntimeException.class, optsRenewWithOwner::checkArgs);
210+
211+
String[] argsExpireWithRenew = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--renew", "--hmac", "test-hmac", "--expiry-time-period", "604800000"};
212+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireWithRenew = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireWithRenew);
213+
assertThrows(RuntimeException.class, optsExpireWithRenew::checkArgs);
214+
215+
String[] argsExpireWithMaxLife = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--hmac", "test-hmac", "--expiry-time-period", "604800000", "--max-life-time-period", "604800000"};
216+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireWithMaxLife = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireWithMaxLife);
217+
assertThrows(RuntimeException.class, optsExpireWithMaxLife::checkArgs);
218+
219+
String[] argsExpireWithRenewTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--hmac", "test-hmac", "--expiry-time-period", "604800000", "--renew-time-period", "604800000"};
220+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireWithRenewTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireWithRenewTime);
221+
assertThrows(RuntimeException.class, optsExpireWithRenewTime::checkArgs);
222+
223+
String[] argsExpireWithOwner = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--hmac", "test-hmac", "--expiry-time-period", "604800000", "--owner-principal", "User:owner"};
224+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpireWithOwner = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpireWithOwner);
225+
assertThrows(RuntimeException.class, optsExpireWithOwner::checkArgs);
226+
227+
String[] argsDescribeWithRenewTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--describe", "--renew-time-period", "604800000"};
228+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribeWithRenewTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribeWithRenewTime);
229+
assertThrows(RuntimeException.class, optsDescribeWithRenewTime::checkArgs);
230+
231+
String[] argsDescribeWithExpiryTime = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--describe", "--expiry-time-period", "604800000"};
232+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribeWithExpiryTime = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribeWithExpiryTime);
233+
assertThrows(RuntimeException.class, optsDescribeWithExpiryTime::checkArgs);
234+
235+
String[] argsDescribeWithMaxLife = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--describe", "--max-life-time-period", "604800000"};
236+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribeWithMaxLife = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribeWithMaxLife);
237+
assertThrows(RuntimeException.class, optsDescribeWithMaxLife::checkArgs);
238+
239+
String[] argsDescribeWithHmac = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--describe", "--hmac", "test-hmac"};
240+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribeWithHmac = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribeWithHmac);
241+
assertThrows(RuntimeException.class, optsDescribeWithHmac::checkArgs);
242+
} finally {
243+
Exit.resetExitProcedure();
244+
}
245+
}
246+
247+
@Test
248+
public void testCheckArgsValidOperations() {
249+
String[] argsCreate = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--create", "--max-life-time-period", "604800000"};
250+
DelegationTokenCommand.DelegationTokenCommandOptions optsCreate = new DelegationTokenCommand.DelegationTokenCommandOptions(argsCreate);
251+
optsCreate.checkArgs();
252+
253+
String[] argsRenew = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--renew", "--hmac", "test-hmac", "--renew-time-period", "604800000"};
254+
DelegationTokenCommand.DelegationTokenCommandOptions optsRenew = new DelegationTokenCommand.DelegationTokenCommandOptions(argsRenew);
255+
optsRenew.checkArgs();
256+
257+
String[] argsExpire = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--expire", "--hmac", "test-hmac", "--expiry-time-period", "604800000"};
258+
DelegationTokenCommand.DelegationTokenCommandOptions optsExpire = new DelegationTokenCommand.DelegationTokenCommandOptions(argsExpire);
259+
optsExpire.checkArgs();
260+
261+
String[] argsDescribe = {"--bootstrap-server", "localhost:9092", "--command-config", "testfile", "--describe"};
262+
DelegationTokenCommand.DelegationTokenCommandOptions optsDescribe = new DelegationTokenCommand.DelegationTokenCommandOptions(argsDescribe);
263+
optsDescribe.checkArgs();
264+
}
112265
}

0 commit comments

Comments
 (0)