You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by co...@apache.org on 2016/06/13 01:30:38 UTC

zeppelin git commit: [ZEPPELIN-940] Allow zeppelin server to connect to already executing Remote Interpreter

Repository: zeppelin
Updated Branches:
  refs/heads/master dd70a5729 -> c9e3a6a43


[ZEPPELIN-940] Allow zeppelin server to connect to already executing Remote Interpreter

### What is this PR for?
Currenlty zeppelin server starts interpreter on localhost and with random port.The purpose of this pull request is to allow zeppelin server to connect to remotely executing zeppelin interpreter that user might have started in his service.This feature will be further helpful while cluster manager is to be implemented.(https://cwiki.apache.org/confluence/display/ZEPPELIN/Cluster+Manager+Proposal)

### What type of PR is it?
Improvement

### Todos
[ ] -Add documentation

### What is the Jira issue?
* [ZEPPELIN-940] https://issues.apache.org/jira/browse/ZEPPELIN-940

### How should this be tested?
Added Junit test in RemoteInterpreterProcessTest and it passes

### Screenshots (if appropriate)

### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? Yes for the new properties

Author: Sachin <sj...@snappydata.io>
Author: SachinJanani <sj...@snappydata.io>

Closes #955 from SachinJanani/master and squashes the following commits:

f279767 [Sachin] Changed the Markdown style for code block in document
f57eb78 [Sachin] Incorporated review comments related to documentation
067a06e [Sachin] Add documentation for connecting to existing remote interpreter
84d2347 [Sachin] Added checkbox for Connecting to existing process and renamed the variables
c7fdc66 [Sachin] Merge remote-tracking branch 'upstream/master'
9762134 [Sachin] Merge branch 'master' of https://github.com/SachinJanani/incubator-zeppelin
4d51cd9 [Sachin] Add UI component for the accepting Host and Port when executing option is selected
2e30e3d [Sachin] [ZEPPELIN-940] Allow zeppelin server to connect to already executing Remote Interpreter
355c1f2 [Sachin] Add UI component for the accepting Host and Port when executing option is selected
7af8112 [Sachin] Merge branch 'master' of https://github.com/SachinJanani/incubator-zeppelin
fbe2346 [Sachin] [ZEPPELIN-940] Allow zeppelin server to connect to already executing Remote Interpreter
53c1eea [SachinJanani] Merge pull request #1 from apache/master


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/c9e3a6a4
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/c9e3a6a4
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/c9e3a6a4

Branch: refs/heads/master
Commit: c9e3a6a43d15d7c084a1f9fe0330e01cd802f194
Parents: dd70a57
Author: Sachin <sj...@snappydata.io>
Authored: Fri Jun 10 12:21:21 2016 +0530
Committer: Damien CORNEAU <co...@gmail.com>
Committed: Mon Jun 13 10:30:26 2016 +0900

----------------------------------------------------------------------
 .../img/screenshots/existing_interpreter.png    | Bin 0 -> 7350 bytes
 docs/manual/interpreters.md                     |  16 ++++
 .../apache/zeppelin/interpreter/Constants.java  |  31 ++++++
 .../remote/RemoteInterpreterProcess.java        |  95 ++++++++++++-------
 .../remote/RemoteInterpreterProcessTest.java    |  33 +++++++
 .../interpreter-create/interpreter-create.html  |  18 ++++
 .../app/interpreter/interpreter.controller.js   |   5 +
 .../src/app/interpreter/interpreter.html        |  22 +++++
 .../interpreter/InterpreterFactory.java         |   5 +-
 .../zeppelin/interpreter/InterpreterOption.java |  33 +++++++
 .../interpreter/InterpreterSetting.java         |   4 +-
 .../notebook/NoteInterpreterLoader.java         |   5 +-
 12 files changed, 231 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/docs/assets/themes/zeppelin/img/screenshots/existing_interpreter.png
----------------------------------------------------------------------
diff --git a/docs/assets/themes/zeppelin/img/screenshots/existing_interpreter.png b/docs/assets/themes/zeppelin/img/screenshots/existing_interpreter.png
new file mode 100644
index 0000000..ad32da4
Binary files /dev/null and b/docs/assets/themes/zeppelin/img/screenshots/existing_interpreter.png differ

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/docs/manual/interpreters.md
----------------------------------------------------------------------
diff --git a/docs/manual/interpreters.md b/docs/manual/interpreters.md
index ca73bef..488d5e9 100644
--- a/docs/manual/interpreters.md
+++ b/docs/manual/interpreters.md
@@ -60,3 +60,19 @@ Each Interpreter Setting can choose one of 'shared', 'scoped', 'isolated' interp
 In 'shared' mode, every notebook bound to the Interpreter Setting will share the single Interpreter instance. In 'scoped' mode, each notebook will create new Interpreter instance in the same interpreter process. In 'isolated' mode, each notebook will create new Interpreter process.
 
 <img src="../assets/themes/zeppelin/img/screenshots/interpreter_persession.png" width="400px">
+
+
+## Connecting to the Existing Remote Interpreter
+
+Zeppelin users can start interpreter thread embedded in their service. This will provide flexibility to user to start interpreter on remote host. To start interpreter along with your service you have to create an instance of ``RemoteInterpreterServer`` and start it as follows:
+
+```
+RemoteInterpreterServer interpreter=new RemoteInterpreterServer(3678); 
+// Here, 3678 is the port on which interpreter will listen.    
+interpreter.start()  
+
+```
+
+The above code will start interpreter thread inside your process. Once the interpreter is started you can configure zeppelin to connect to RemoteInterpreter by checking **Connect to existing process** checkbox and then provide **Host** and **Port** on which interpreter porocess is listening as shown in the image below:
+
+<img src="../assets/themes/zeppelin/img/screenshots/existing_interpreter.png" width="400px">

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Constants.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Constants.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Constants.java
new file mode 100644
index 0000000..0ab94ac
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Constants.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.interpreter;
+/**
+ * Interpreter related constants
+ * 
+ *
+ */
+public class Constants {
+  public static final String ZEPPELIN_INTERPRETER_PORT = "zeppelin.interpreter.port";
+
+  public static final String ZEPPELIN_INTERPRETER_HOST = "zeppelin.interpreter.host";
+
+  public static final String EXISTING_PROCESS = "existing_process";
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
index 67a048b..05baf62 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
@@ -22,6 +22,7 @@ import org.apache.commons.exec.*;
 import org.apache.commons.exec.environment.EnvironmentUtils;
 import org.apache.commons.pool2.impl.GenericObjectPool;
 import org.apache.thrift.TException;
+import org.apache.zeppelin.interpreter.Constants;
 import org.apache.zeppelin.interpreter.InterpreterException;
 import org.apache.zeppelin.interpreter.InterpreterGroup;
 import org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService.Client;
@@ -31,13 +32,13 @@ import org.slf4j.LoggerFactory;
 import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Properties;
 
 /**
  *
  */
 public class RemoteInterpreterProcess implements ExecuteResultHandler {
   private static final Logger logger = LoggerFactory.getLogger(RemoteInterpreterProcess.class);
-
   private final AtomicInteger referenceCount;
   private DefaultExecutor executor;
   private ExecuteWatchdog watchdog;
@@ -52,6 +53,8 @@ public class RemoteInterpreterProcess implements ExecuteResultHandler {
   private final RemoteInterpreterEventPoller remoteInterpreterEventPoller;
   private final InterpreterContextRunnerPool interpreterContextRunnerPool;
   private int connectTimeout;
+  String host = "localhost";
+  boolean isInterpreterAlreadyExecuting = false;
 
   public RemoteInterpreterProcess(String intpRunner,
       String intpDir,
@@ -91,54 +94,80 @@ public class RemoteInterpreterProcess implements ExecuteResultHandler {
   public int reference(InterpreterGroup interpreterGroup) {
     synchronized (referenceCount) {
       if (executor == null) {
-        // start server process
-        try {
-          port = RemoteInterpreterUtils.findRandomAvailablePortOnAllLocalInterfaces();
-        } catch (IOException e1) {
-          throw new InterpreterException(e1);
+        if (interpreterGroup.containsKey(Constants.EXISTING_PROCESS)) {
+          Properties properties = interpreterGroup.getProperty();
+          isInterpreterAlreadyExecuting = true;
+          if (isInterpreterAlreadyExecuting) {
+            if (properties.containsKey(Constants.ZEPPELIN_INTERPRETER_HOST)) {
+              host = properties.getProperty(Constants.ZEPPELIN_INTERPRETER_HOST);
+
+            } else {
+              throw new InterpreterException("Can't find value for option Host."
+                  + "Please specify the host on which interpreter is executing");
+            }
+            if (properties.containsKey(Constants.ZEPPELIN_INTERPRETER_PORT)) {
+              port = Integer.parseInt(
+                  interpreterGroup.getProperty().getProperty(Constants.ZEPPELIN_INTERPRETER_PORT));
+            } else {
+              throw new InterpreterException("Can't find value for option Port."
+                  + "Please specify the port on which interpreter is listening");
+            }
+          }
+          running = true;
         }
 
-        CommandLine cmdLine = CommandLine.parse(interpreterRunner);
-        cmdLine.addArgument("-d", false);
-        cmdLine.addArgument(interpreterDir, false);
-        cmdLine.addArgument("-p", false);
-        cmdLine.addArgument(Integer.toString(port), false);
-        cmdLine.addArgument("-l", false);
-        cmdLine.addArgument(localRepoDir, false);
-
-        executor = new DefaultExecutor();
-
-        watchdog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
-        executor.setWatchdog(watchdog);
+        if (!isInterpreterAlreadyExecuting) {
+          try {
+            port = RemoteInterpreterUtils.findRandomAvailablePortOnAllLocalInterfaces();
+          } catch (IOException e1) {
+            throw new InterpreterException(e1);
+          }
+          CommandLine cmdLine = CommandLine.parse(interpreterRunner);
+          cmdLine.addArgument("-d", false);
+          cmdLine.addArgument(interpreterDir, false);
+          cmdLine.addArgument("-p", false);
+          cmdLine.addArgument(Integer.toString(port), false);
+          cmdLine.addArgument("-l", false);
+          cmdLine.addArgument(localRepoDir, false);
+
+          executor = new DefaultExecutor();
+
+          watchdog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
+          executor.setWatchdog(watchdog);
+
+          running = true;
+          try {
+            Map procEnv = EnvironmentUtils.getProcEnvironment();
+            procEnv.putAll(env);
+
+            logger.info("Run interpreter process {}", cmdLine);
+            executor.execute(cmdLine, procEnv, this);
+
+          } catch (IOException e) {
+            running = false;
+            throw new InterpreterException(e);
+          }
 
-        running = true;
-        try {
-          Map procEnv = EnvironmentUtils.getProcEnvironment();
-          procEnv.putAll(env);
-
-          logger.info("Run interpreter process {}", cmdLine);
-          executor.execute(cmdLine, procEnv, this);
-        } catch (IOException e) {
-          running = false;
-          throw new InterpreterException(e);
+        } else {
+          logger.info(
+              "Not starting interpreter as \"isExistingProcess\" is enabled");
         }
 
-
         long startTime = System.currentTimeMillis();
         while (System.currentTimeMillis() - startTime < connectTimeout) {
-          if (RemoteInterpreterUtils.checkIfRemoteEndpointAccessible("localhost", port)) {
+          if (RemoteInterpreterUtils.checkIfRemoteEndpointAccessible(host, port)) {
             break;
           } else {
             try {
               Thread.sleep(500);
             } catch (InterruptedException e) {
-              logger.error("Exception in RemoteInterpreterProcess while synchronized reference " +
-                  "Thread.sleep", e);
+              logger.error("Exception in RemoteInterpreterProcess while synchronized reference "
+                  + "Thread.sleep", e);
             }
           }
         }
 
-        clientPool = new GenericObjectPool<Client>(new ClientFactory("localhost", port));
+        clientPool = new GenericObjectPool<Client>(new ClientFactory(host, port));
 
         remoteInterpreterEventPoller.setInterpreterGroup(interpreterGroup);
         remoteInterpreterEventPoller.setInterpreterProcess(this);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessTest.java
index 52d3858..f9d7d39 100644
--- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessTest.java
+++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessTest.java
@@ -22,7 +22,11 @@ import static org.junit.Assert.assertFalse;
 import static org.mockito.Mockito.*;
 
 import java.util.HashMap;
+import java.util.Properties;
 
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransportException;
+import org.apache.zeppelin.interpreter.Constants;
 import org.apache.zeppelin.interpreter.InterpreterGroup;
 import org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService.Client;
 import org.junit.Test;
@@ -32,6 +36,7 @@ public class RemoteInterpreterProcessTest {
           System.getProperty("os.name").startsWith("Windows") ?
                   "../bin/interpreter.cmd" :
                   "../bin/interpreter.sh";
+  private static final int DUMMY_PORT=3678;
 
   @Test
   public void testStartStop() {
@@ -70,4 +75,32 @@ public class RemoteInterpreterProcessTest {
 
     rip.dereference();
   }
+
+  @Test
+  public void testStartStopRemoteInterpreter() throws TException, InterruptedException {
+    RemoteInterpreterServer server = new RemoteInterpreterServer(3678);
+    server.start();
+    boolean running = false;
+    long startTime = System.currentTimeMillis();
+    while (System.currentTimeMillis() - startTime < 10 * 1000) {
+      if (server.isRunning()) {
+        running = true;
+        break;
+      } else {
+        Thread.sleep(200);
+      }
+    }
+    Properties properties = new Properties();
+    properties.setProperty(Constants.ZEPPELIN_INTERPRETER_PORT, "3678");
+    properties.setProperty(Constants.ZEPPELIN_INTERPRETER_HOST, "localhost");
+    InterpreterGroup intpGroup = mock(InterpreterGroup.class);
+    when(intpGroup.getProperty()).thenReturn(properties);
+    when(intpGroup.containsKey(Constants.EXISTING_PROCESS)).thenReturn(true);
+    RemoteInterpreterProcess rip = new RemoteInterpreterProcess(INTERPRETER_SCRIPT, "nonexists",
+        "fakeRepo", new HashMap<String, String>(), 10 * 1000, null);
+    assertFalse(rip.isRunning());
+    assertEquals(0, rip.referenceCount());
+    assertEquals(1, rip.reference(intpGroup));
+    assertEquals(true, rip.isRunning());
+  }
 }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
index f41dbfb..d802b53 100644
--- a/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
+++ b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
@@ -69,6 +69,24 @@ limitations under the License.
           <span>Interpreter for note</span>
         </div>
         <br />
+        
+        <div class="col-md-12" style="padding-left:0px">
+          <div class="checkbox">
+            <span class="input-group">
+              <label><input type="checkbox" style="width:0%;height:0%" ng-model="newInterpreterSetting.option.isExistingProcess"> </input> Connect to existing process </label>
+            </span>
+          </div>
+        </div>
+        <div ng-show="newInterpreterSetting.option.isExistingProcess" class="form-group" style="width:200px">
+          <b>Host</b>
+            <input id="newInterpreterSettingHost" input pu-elastic-input
+              pu-elastic-input-minwidth="180px" ng-model="newInterpreterSetting.option.host" />
+        </div>
+        <div ng-show="newInterpreterSetting.option.isExistingProcess" class="form-group" style="width:200px">
+          <b>Port</b>
+           <input id="newInterpreterSettingPort" input pu-elastic-input
+            pu-elastic-input-minwidth="180px" ng-model="newInterpreterSetting.option.port" />
+        </div>
 
         <b>Properties</b>
         <table class="table table-striped properties">

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-web/src/app/interpreter/interpreter.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js b/zeppelin-web/src/app/interpreter/interpreter.controller.js
index 5d561a7..8610910 100644
--- a/zeppelin-web/src/app/interpreter/interpreter.controller.js
+++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js
@@ -120,6 +120,9 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl', function($scope,
           if (!setting.option) {
             setting.option = {};
           }
+          if (setting.option.isExistingProcess === undefined) {
+            setting.option.isExistingProcess = false;
+          }
           if (setting.option.remote === undefined) {
             // remote always true for now
             setting.option.remote = true;
@@ -273,8 +276,10 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl', function($scope,
       dependencies: [],
       option: {
         remote: true,
+        isExistingProcess: false,
         perNoteSession: false,
         perNoteProcess: false
+
       }
     };
     emptyNewProperty($scope.newInterpreterSetting);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-web/src/app/interpreter/interpreter.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/interpreter/interpreter.html b/zeppelin-web/src/app/interpreter/interpreter.html
index 24831bc..c840f89 100644
--- a/zeppelin-web/src/app/interpreter/interpreter.html
+++ b/zeppelin-web/src/app/interpreter/interpreter.html
@@ -152,6 +152,28 @@ limitations under the License.
         </span>
         <span>Interpreter for note</span>
       </div>
+      
+      <br />
+      <div class="col-md-12">
+        <div class="checkbox">
+          <span class="input-group">
+            <label><input type="checkbox" style="width:0%;height:0%" id="isExistingProcess" ng-model="setting.option.isExistingProcess" ng-disabled="!valueform.$visible"> </input>
+            Connect to existing process <label>
+          </span>
+        </div>
+      </div>
+
+      <div class="col-md-12" ng-show="setting.option.isExistingProcess">
+        <b>Host</b>
+          <input id="newInterpreterSettingHost" input pu-elastic-input
+            pu-elastic-input-minwidth="180px" ng-model="setting.option.host" ng-disabled="!valueform.$visible"  />
+      </div>
+      <div class="col-md-12" ng-show="setting.option.isExistingProcess">
+         <b>Port</b>
+         <input id="newInterpreterSettingPort" input pu-elastic-input
+            pu-elastic-input-minwidth="180px" ng-model="setting.option.port"  ng-disabled="!valueform.$visible" />
+      </div>
+
 
 
       <div ng-show="_.isEmpty(setting.properties) && _.isEmpty(setting.dependencies) || valueform.$hidden" class="col-md-12 gray40-message">

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java
index 1772840..bad18c0 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java
@@ -544,7 +544,10 @@ public class InterpreterFactory implements InterpreterGroupFactory {
     String groupName = interpreterSetting.getGroup();
     InterpreterOption option = interpreterSetting.getOption();
     Properties properties = interpreterSetting.getProperties();
-
+    if (option.isExistingProcess) {
+      properties.put(Constants.ZEPPELIN_INTERPRETER_HOST, option.getHost());
+      properties.put(Constants.ZEPPELIN_INTERPRETER_PORT, option.getPort());
+    }
     // if interpreters are already there, wait until they're being removed
     synchronized (interpreterGroup) {
       long interpreterRemovalWaitStart = System.nanoTime();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterOption.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterOption.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterOption.java
index ba6f7b9..f9e43ab 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterOption.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterOption.java
@@ -24,6 +24,39 @@ public class InterpreterOption {
   boolean remote;
   boolean perNoteSession;
   boolean perNoteProcess;
+  
+  boolean isExistingProcess;
+
+  String host;
+  String port;
+
+
+  
+
+  public boolean isExistingProcess() {
+    return isExistingProcess;
+  }
+
+  public void setExistingProcess(boolean isExistingProcess) {
+    this.isExistingProcess = isExistingProcess;
+  }
+
+  public String getPort() {
+    return port;
+  }
+
+  public void setPort(String port) {
+    this.port = port;
+  }
+
+  public String getHost() {
+    return host;
+  }
+
+  public void setHost(String host) {
+    this.host = host;
+  }
+
 
   public InterpreterOption() {
     remote = false;

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
index 91eb2c8..2060714 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterSetting.java
@@ -124,7 +124,9 @@ public class InterpreterSetting {
 
 
   private String getInterpreterProcessKey(String noteId) {
-    if (getOption().isPerNoteProcess()) {
+    if (getOption().isExistingProcess) {
+      return Constants.EXISTING_PROCESS;
+    } else if (getOption().isPerNoteProcess()) {
       return noteId;
     } else {
       return SHARED_PROCESS;

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/c9e3a6a4/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteInterpreterLoader.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteInterpreterLoader.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteInterpreterLoader.java
index 7e22ca0..b1719c5 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteInterpreterLoader.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NoteInterpreterLoader.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.zeppelin.interpreter.Constants;
 import org.apache.zeppelin.interpreter.Interpreter;
 import org.apache.zeppelin.interpreter.Interpreter.RegisteredInterpreter;
 import org.apache.zeppelin.interpreter.InterpreterException;
@@ -75,7 +76,9 @@ public class NoteInterpreterLoader {
   }
 
   private String getInterpreterInstanceKey(InterpreterSetting setting) {
-    if (setting.getOption().isPerNoteSession() || setting.getOption().isPerNoteProcess()) {
+    if (setting.getOption().isExistingProcess()) {
+      return Constants.EXISTING_PROCESS;
+    } else if (setting.getOption().isPerNoteSession() || setting.getOption().isPerNoteProcess()) {
       return noteId;
     } else {
       return SHARED_SESSION;