use of io.kubernetes.client.custom.IOTrio in project java by kubernetes-client.
the class Exec method exec.
/**
* A convenience method. Executes a command remotely on a pod and monitors for events in that
* execution. The monitored events are: <br>
* - connection established (onOpen) <br>
* - connection closed (onClosed) <br>
* - execution error occurred (onError) <br>
* This method also allows to specify a MAX timeout for the execution and returns a future in
* order to monitor the execution flow. <br>
* onError and onClosed callbacks are invoked asynchronously, in a separate thread. <br>
*
* @param namespace a namespace the target pod "lives" in
* @param podName a name of the pod to exec the command on
* @param onOpen a callback invoked upon the connection established event.
* @param onClosed a callback invoked upon the process termination. Return code might not always
* be there. N.B. this callback is invoked before the returned {@link Future} is completed.
* @param onError a callback to handle k8s errors (NOT the command errors/stderr!)
* @param timeoutMs timeout in milliseconds for the execution. I.e. the execution will take this
* many ms or less. If the timeout command is running longer than the allowed timeout, the
* command will be "asked" to terminate gracefully. If the command is still running after the
* grace period, the sigkill will be issued. If null is passed, the timeout will not be used
* and will wait for process to exit itself.
* @param tty whether you need tty to pipe the data. TTY mode will trim some binary data in order
* to make it possible to show on screen (tty)
* @param command a tokenized command to run on the pod
* @return a {@link Future} promise representing this execution. Unless something goes south, the
* promise will contain the process return exit code. If the timeoutMs is non-null and the
* timeout expires before the process exits, promise will contain {@link Integer#MAX_VALUE}.
* @throws IOException
*/
public Future<Integer> exec(String namespace, String podName, Consumer<IOTrio> onOpen, BiConsumer<Integer, IOTrio> onClosed, BiConsumer<Throwable, IOTrio> onError, Long timeoutMs, boolean tty, String... command) throws IOException {
CompletableFuture<Integer> future = new CompletableFuture<>();
IOTrio io = new IOTrio();
String cmdStr = Arrays.toString(command);
BiConsumer<Throwable, IOTrio> errHandler = (err, errIO) -> {
if (onError != null) {
onError.accept(err, errIO);
}
};
try {
Process process = exec(namespace, podName, command, null, true, tty);
io.onClose((code, timeout) -> {
process.destroy();
waitForProcessToExit(process, timeout, cmdStr, err -> errHandler.accept(err, io));
// processWaitingThread will handle the rest
});
io.setStdin(process.getOutputStream());
io.setStdout(process.getInputStream());
io.setStderr(process.getErrorStream());
runAsync("Process-Waiting-Thread-" + command[0] + "-" + podName, () -> {
Supplier<Integer> returnCode = process::exitValue;
try {
log.debug("Waiting for process to close in {} ms: {}", timeoutMs, cmdStr);
boolean beforeTimout = waitForProcessToExit(process, timeoutMs, cmdStr, err -> errHandler.accept(err, io));
if (!beforeTimout) {
returnCode = () -> Integer.MAX_VALUE;
}
} catch (Exception e) {
errHandler.accept(e, io);
}
log.debug("process.onExit({}): {}", returnCode.get(), cmdStr);
if (onClosed != null) {
onClosed.accept(returnCode.get(), io);
}
future.complete(returnCode.get());
});
if (onOpen != null) {
onOpen.accept(io);
}
} catch (ApiException e) {
errHandler.accept(e, io);
future.completeExceptionally(e);
}
return future;
}
Aggregations