|
@@ -24,8 +24,10 @@ import java.nio.charset.Charset;
|
|
|
|
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
|
+import org.apache.hadoop.yarn.api.records.ContainerId;
|
|
|
+import org.apache.hadoop.yarn.server.nodemanager.Context;
|
|
|
import org.apache.hadoop.yarn.server.nodemanager.ContainerExecutor;
|
|
|
-import org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor;
|
|
|
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
|
|
|
import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerExecContext;
|
|
|
import org.eclipse.jetty.websocket.api.Session;
|
|
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
|
@@ -47,31 +49,43 @@ import org.slf4j.LoggerFactory;
|
|
|
public class ContainerShellWebSocket {
|
|
|
private static final Logger LOG =
|
|
|
LoggerFactory.getLogger(ContainerShellWebSocket.class);
|
|
|
+ private static Context nmContext;
|
|
|
|
|
|
- private final ContainerExecutor exec = new LinuxContainerExecutor();
|
|
|
-
|
|
|
+ private final ContainerExecutor exec;
|
|
|
private IOStreamPair pair;
|
|
|
|
|
|
+ public ContainerShellWebSocket() {
|
|
|
+ exec = nmContext.getContainerExecutor();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void init(Context nm) {
|
|
|
+ ContainerShellWebSocket.nmContext = nm;
|
|
|
+ }
|
|
|
+
|
|
|
@OnWebSocketMessage
|
|
|
public void onText(Session session, String message) throws IOException {
|
|
|
- LOG.info("Message received: " + message);
|
|
|
|
|
|
try {
|
|
|
byte[] buffer = new byte[4000];
|
|
|
if (session.isOpen()) {
|
|
|
- int ni = message.length();
|
|
|
- if (ni > 0) {
|
|
|
- pair.out.write(message.getBytes(Charset.forName("UTF-8")));
|
|
|
- pair.out.flush();
|
|
|
+ if (!message.equals("1{}")) {
|
|
|
+ // Send keystroke to process input
|
|
|
+ byte[] payload;
|
|
|
+ payload = message.getBytes(Charset.forName("UTF-8"));
|
|
|
+ if (payload != null) {
|
|
|
+ pair.out.write(payload);
|
|
|
+ pair.out.flush();
|
|
|
+ }
|
|
|
}
|
|
|
+ // Render process output
|
|
|
int no = pair.in.available();
|
|
|
pair.in.read(buffer, 0, Math.min(no, buffer.length));
|
|
|
String formatted = new String(buffer, Charset.forName("UTF-8"))
|
|
|
.replaceAll("\n", "\r\n");
|
|
|
session.getRemote().sendString(formatted);
|
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
- LOG.error("Failed to parse WebSocket message from Client", e);
|
|
|
+ } catch (IOException e) {
|
|
|
+ onClose(session, 1001, "Shutdown");
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -84,12 +98,14 @@ public class ContainerShellWebSocket {
|
|
|
URI containerURI = session.getUpgradeRequest().getRequestURI();
|
|
|
String[] containerPath = containerURI.getPath().split("/");
|
|
|
String cId = containerPath[2];
|
|
|
+ Container container = nmContext.getContainers().get(ContainerId
|
|
|
+ .fromString(cId));
|
|
|
LOG.info(
|
|
|
"Making interactive connection to running docker container with ID: "
|
|
|
+ cId);
|
|
|
ContainerExecContext execContext = new ContainerExecContext
|
|
|
.Builder()
|
|
|
- .setContainer(cId)
|
|
|
+ .setContainer(container)
|
|
|
.build();
|
|
|
pair = exec.execContainer(execContext);
|
|
|
} catch (Exception e) {
|
|
@@ -100,7 +116,14 @@ public class ContainerShellWebSocket {
|
|
|
|
|
|
@OnWebSocketClose
|
|
|
public void onClose(Session session, int status, String reason) {
|
|
|
- LOG.info(session.getRemoteAddress().getHostString() + " closed!");
|
|
|
+ try {
|
|
|
+ LOG.info(session.getRemoteAddress().getHostString() + " closed!");
|
|
|
+ pair.in.close();
|
|
|
+ pair.out.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ } finally {
|
|
|
+ session.close();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
+}
|