Skip to content

Commit 9872bad

Browse files
Merge pull request #4967 from sahilkhatri09/fix-exec-exit-code-overwrite
Keep received exec exit status when the connection fails on close
2 parents b2cd919 + 589286f commit 9872bad

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

‎util/src/main/java/io/kubernetes/client/Exec.java‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,15 @@ public void failure(Throwable ex) {
556556
ExecProcess.this.onUnhandledError.accept(ex);
557557

558558
synchronized (ExecProcess.this) {
559-
// Try for a pretty unique error code, so if someone searches
560-
// they'll find this
561-
// code.
562-
statusCode = -1975219;
559+
// The server may close the connection right after sending the exit status, so
560+
// closing our side can fail after the command finished. Keep a received exit
561+
// status in that case.
562+
if (statusCode < 0) {
563+
// Try for a pretty unique error code, so if someone searches
564+
// they'll find this
565+
// code.
566+
statusCode = -1975219;
567+
}
563568
isAlive = false;
564569
ExecProcess.this.latch.countDown();
565570
}

‎util/src/test/java/io/kubernetes/client/ExecTest.java‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,29 @@ void customUnhandledError() throws IOException, InterruptedException {
204204
assertThat(process.exitValue()).isEqualTo(EXPECTED_ERROR_EXIT_CODE);
205205
}
206206

207+
@ParameterizedTest
208+
@MethodSource("exitStatusBeforeFailureData")
209+
void unhandledErrorAfterExitStatusKeepsExitCode(String status, int expectedExitCode)
210+
throws IOException, InterruptedException {
211+
final Consumer<Throwable> consumer = mock(Consumer.class);
212+
final Throwable throwable = mock(Throwable.class);
213+
final ExecProcess process = new ExecProcess(client, consumer);
214+
process.getHandler().open("wss", null);
215+
216+
process.getHandler().bytesMessage(makeStream(3, status.getBytes(StandardCharsets.UTF_8)));
217+
// e.g. sending the close frame fails because the server already closed the connection
218+
process.getHandler().failure(throwable);
219+
process.waitFor();
220+
221+
verify(consumer, times(1)).accept(throwable);
222+
assertThat(process.isAlive()).isFalse();
223+
assertThat(process.exitValue()).isEqualTo(expectedExitCode);
224+
}
225+
226+
private static Stream<Arguments> exitStatusBeforeFailureData() {
227+
return Stream.of(arguments(OUTPUT_EXIT0, 0), arguments(OUTPUT_EXIT126, 126));
228+
}
229+
207230
@Test
208231
void url() throws IOException, ApiException, InterruptedException {
209232
final Consumer<Throwable> consumer = mock(Consumer.class);

0 commit comments

Comments
 (0)