mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
Merge branch 'ZEPPELIN-1306' of https://github.com/astroshim/zeppelin into ZEPPELIN-1306
This commit is contained in:
commit
fc1c819fd7
9 changed files with 238 additions and 20 deletions
|
|
@ -400,6 +400,16 @@ The role of registered interpreters, settings and interpreters group are describ
|
|||
<td>Fail code</td>
|
||||
<td> 500 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sample JSON input (Optional)</td>
|
||||
<td>
|
||||
<pre>
|
||||
{
|
||||
"noteId": "2AVQJVC8N"
|
||||
}
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sample JSON response</td>
|
||||
<td>
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import javax.ws.rs.core.Response.Status;
|
|||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.apache.zeppelin.rest.message.RestartInterpreterRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.sonatype.aether.repository.RemoteRepository;
|
||||
|
|
@ -150,10 +151,15 @@ public class InterpreterRestApi {
|
|||
@PUT
|
||||
@Path("setting/restart/{settingId}")
|
||||
@ZeppelinApi
|
||||
public Response restartSetting(@PathParam("settingId") String settingId) {
|
||||
logger.info("Restart interpreterSetting {}", settingId);
|
||||
public Response restartSetting(String message, @PathParam("settingId") String settingId) {
|
||||
logger.info("Restart interpreterSetting {}, msg={}", settingId, message);
|
||||
|
||||
try {
|
||||
interpreterFactory.restart(settingId);
|
||||
RestartInterpreterRequest request = gson.fromJson(message, RestartInterpreterRequest.class);
|
||||
|
||||
String noteId = request == null ? null : request.getNoteId();
|
||||
interpreterFactory.restart(settingId, noteId);
|
||||
|
||||
} catch (InterpreterException e) {
|
||||
logger.error("Exception in InterpreterRestApi while restartSetting ", e);
|
||||
return new JsonResponse<>(Status.NOT_FOUND, e.getMessage(), ExceptionUtils.getStackTrace(e))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.rest.message;
|
||||
|
||||
/**
|
||||
* RestartInterpreter rest api request message
|
||||
*/
|
||||
public class RestartInterpreterRequest {
|
||||
String noteId;
|
||||
|
||||
public RestartInterpreterRequest() {
|
||||
|
||||
}
|
||||
|
||||
public String getNoteId() {
|
||||
return noteId;
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import org.apache.commons.httpclient.methods.DeleteMethod;
|
|||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.apache.commons.httpclient.methods.PostMethod;
|
||||
import org.apache.commons.httpclient.methods.PutMethod;
|
||||
import org.apache.zeppelin.interpreter.InterpreterOption;
|
||||
import org.apache.zeppelin.interpreter.InterpreterSetting;
|
||||
import org.apache.zeppelin.notebook.Note;
|
||||
import org.apache.zeppelin.notebook.Paragraph;
|
||||
|
|
@ -190,6 +191,59 @@ public class InterpreterRestApiTest extends AbstractTestRestApi {
|
|||
ZeppelinServer.notebook.removeNote(note.getId(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestartInterpreterPerNote() throws IOException, InterruptedException {
|
||||
// create new note
|
||||
Note note = ZeppelinServer.notebook.createNote(null);
|
||||
note.addParagraph();
|
||||
Paragraph p = note.getLastParagraph();
|
||||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
|
||||
// run markdown paragraph.
|
||||
p.setConfig(config);
|
||||
p.setText("%md markdown");
|
||||
note.run(p.getId());
|
||||
while (p.getStatus() != Status.FINISHED) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
assertEquals("<p>markdown</p>\n", p.getResult().message());
|
||||
|
||||
// get md interpreter
|
||||
InterpreterSetting mdIntpSetting = null;
|
||||
for (InterpreterSetting setting : ZeppelinServer.notebook.getInterpreterFactory().getInterpreterSettings(note.getId())) {
|
||||
if (setting.getName().equals("md")) {
|
||||
mdIntpSetting = setting;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String jsonRequest = "{\"noteId\":\"" + note.getId() + "\"}";
|
||||
|
||||
// Restart isolated mode of Interpreter for note.
|
||||
mdIntpSetting.getOption().setPerNoteProcess(true);
|
||||
mdIntpSetting.getOption().setPerNoteSession(false);
|
||||
PutMethod put = httpPut("/interpreter/setting/restart/" + mdIntpSetting.getId(), jsonRequest);
|
||||
assertThat("isolated interpreter restart:", put, isAllowed());
|
||||
put.releaseConnection();
|
||||
|
||||
// Restart scoped mode of Interpreter for note.
|
||||
mdIntpSetting.getOption().setPerNoteSession(true);
|
||||
mdIntpSetting.getOption().setPerNoteProcess(false);
|
||||
put = httpPut("/interpreter/setting/restart/" + mdIntpSetting.getId(), jsonRequest);
|
||||
assertThat("scoped interpreter restart:", put, isAllowed());
|
||||
put.releaseConnection();
|
||||
|
||||
// Restart shared mode of Interpreter for note.
|
||||
mdIntpSetting.getOption().setPerNoteProcess(false);
|
||||
mdIntpSetting.getOption().setPerNoteSession(false);
|
||||
put = httpPut("/interpreter/setting/restart/" + mdIntpSetting.getId(), jsonRequest);
|
||||
assertThat("shared interpreter restart:", put, isAllowed());
|
||||
put.releaseConnection();
|
||||
|
||||
ZeppelinServer.notebook.removeNote(note.getId(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListRepository() throws IOException {
|
||||
GetMethod get = httpGet("/interpreter/repository");
|
||||
|
|
|
|||
|
|
@ -660,6 +660,69 @@
|
|||
message: 'Owners : ' + $scope.permissions.owners + '\n\n' + 'Readers : ' +
|
||||
$scope.permissions.readers + '\n\n' + 'Writers : ' + $scope.permissions.writers
|
||||
});
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$scope.showPermissions = false;
|
||||
}
|
||||
};
|
||||
|
||||
function convertPermissionsToArray() {
|
||||
$scope.permissions.owners = angular.element('#selectOwners').val();
|
||||
$scope.permissions.readers = angular.element('#selectReaders').val();
|
||||
$scope.permissions.writers = angular.element('#selectWriters').val();
|
||||
}
|
||||
|
||||
$scope.restartInterpreter = function(interpeter) {
|
||||
var thisConfirm = BootstrapDialog.confirm({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: '',
|
||||
message: 'Do you want to restart ' + interpeter.name + ' interpreter?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
var payload = {
|
||||
'noteId': $scope.note.id
|
||||
};
|
||||
|
||||
thisConfirm.$modalFooter.find('button').addClass('disabled');
|
||||
thisConfirm.$modalFooter.find('button:contains("OK")')
|
||||
.html('<i class="fa fa-circle-o-notch fa-spin"></i> Saving Setting');
|
||||
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/restart/' + interpeter.id, payload)
|
||||
.success(function(data, status, headers, config) {
|
||||
var index = _.findIndex($scope.interpreterSettings, {'id': interpeter.id});
|
||||
$scope.interpreterSettings[index] = data.body;
|
||||
thisConfirm.close();
|
||||
}).error(function(data, status, headers, config) {
|
||||
thisConfirm.close();
|
||||
console.log('Error %o %o', status, data.message);
|
||||
BootstrapDialog.show({
|
||||
title: 'Error restart interpreter.',
|
||||
message: data.message
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.savePermissions = function() {
|
||||
convertPermissionsToArray();
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/notebook/' + $scope.note.id + '/permissions',
|
||||
$scope.permissions, {withCredentials: true}).
|
||||
success(function(data, status, headers, config) {
|
||||
getPermissions(function() {
|
||||
console.log('Note permissions %o saved', $scope.permissions);
|
||||
BootstrapDialog.alert({
|
||||
closable: true,
|
||||
title: 'Permissions Saved Successfully!!!',
|
||||
message: 'Owners : ' + $scope.permissions.owners + '\n\n' + 'Readers : ' +
|
||||
$scope.permissions.readers + '\n\n' + 'Writers : ' + $scope.permissions.writers
|
||||
$scope.showPermissions = false;
|
||||
});
|
||||
}).
|
||||
|
|
|
|||
|
|
@ -312,3 +312,11 @@
|
|||
min-width: 150px;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
|
||||
.inactivelink {
|
||||
color: darkgrey;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,20 +32,27 @@ limitations under the License.
|
|||
<div class="interpreterSettings"
|
||||
as-sortable="interpreterSelectionListeners" data-ng-model="interpreterBindings">
|
||||
<div data-ng-repeat="item in interpreterBindings" as-sortable-item>
|
||||
<div as-sortable-item-handle
|
||||
ng-click="item.selected = !item.selected"
|
||||
class="btn"
|
||||
ng-class="{'btn-info': item.selected, 'btn-default': !item.selected}">
|
||||
<font style="font-size:16px">{{item.name}}</font>
|
||||
<small>
|
||||
<span style="display:inline-block" ng-repeat="intp in item.interpreters">
|
||||
<span ng-show="!$first">, </span>
|
||||
%<span ng-show="!$parent.$first || $first">{{item.name}}</span
|
||||
><span ng-show="(!$parent.$first || $first) && !$first">.</span
|
||||
><span ng-show="!$first">{{intp.name}}</span>
|
||||
<span ng-show="$parent.$first && $first">(default)</span>
|
||||
</span>
|
||||
</small>
|
||||
<div>
|
||||
<a ng-click="restartInterpreter(item)"
|
||||
ng-class="{'inactivelink': !item.selected}"
|
||||
tooltip="Restart">
|
||||
<span class="glyphicon glyphicon-refresh btn-md"></span>
|
||||
</a> 
|
||||
<div as-sortable-item-handle
|
||||
ng-click="item.selected = !item.selected"
|
||||
class="btn"
|
||||
ng-class="{'btn-info': item.selected, 'btn-default': !item.selected}">
|
||||
<font style="font-size:16px">{{item.name}}</font>
|
||||
<small>
|
||||
<span style="display:inline-block" ng-repeat="intp in item.interpreters">
|
||||
<span ng-show="!$first">, </span>
|
||||
%<span ng-show="!$parent.$first || $first">{{item.name}}</span
|
||||
><span ng-show="(!$parent.$first || $first) && !$first">.</span
|
||||
><span ng-show="!$first">{{intp.name}}</span>
|
||||
<span ng-show="$parent.$first && $first">(default)</span>
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -940,6 +940,25 @@ public class InterpreterFactory implements InterpreterGroupFactory {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean noteIdIsExist(String noteId) {
|
||||
return noteId == null ? false : true;
|
||||
}
|
||||
|
||||
private boolean isNotSharedInterpreter(InterpreterOption intpOption) {
|
||||
return intpOption.isPerNoteSession() || intpOption.isExistingProcess();
|
||||
}
|
||||
|
||||
|
||||
public void restart(String settingId, String noteId) {
|
||||
InterpreterSetting setting = interpreterSettings.get(settingId);
|
||||
|
||||
if (noteIdIsExist(noteId) && isNotSharedInterpreter(setting.getOption())) {
|
||||
removeInterpretersForNote(setting, noteId);
|
||||
return;
|
||||
}
|
||||
restart(settingId);
|
||||
}
|
||||
|
||||
public void restart(String id) {
|
||||
synchronized (interpreterSettings) {
|
||||
InterpreterSetting intpsetting = interpreterSettings.get(id);
|
||||
|
|
|
|||
|
|
@ -715,7 +715,7 @@ public class NotebookTest implements JobListenerFactory{
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testPerSessionInterpreter() throws IOException {
|
||||
public void testInterpreterForNote() throws IOException {
|
||||
// create two notes
|
||||
Note note1 = notebook.createNote(null);
|
||||
Paragraph p1 = note1.addParagraph();
|
||||
|
|
@ -726,7 +726,7 @@ public class NotebookTest implements JobListenerFactory{
|
|||
p1.setText("getId");
|
||||
p2.setText("getId");
|
||||
|
||||
// run per note session disabled
|
||||
// run per note session disabled (shared mode)
|
||||
note1.run(p1.getId());
|
||||
note2.run(p2.getId());
|
||||
|
||||
|
|
@ -736,9 +736,10 @@ public class NotebookTest implements JobListenerFactory{
|
|||
assertEquals(p1.getResult().message(), p2.getResult().message());
|
||||
|
||||
|
||||
// restart interpreter with per note session enabled
|
||||
// restart interpreter with scoped(per note session) mode enabled
|
||||
for (InterpreterSetting setting : notebook.getInterpreterFactory().getInterpreterSettings(note1.getId())) {
|
||||
setting.getOption().setPerNoteSession(true);
|
||||
setting.getOption().setPerNoteProcess(false);
|
||||
notebook.getInterpreterFactory().restart(setting.getId());
|
||||
}
|
||||
|
||||
|
|
@ -751,6 +752,23 @@ public class NotebookTest implements JobListenerFactory{
|
|||
|
||||
assertNotEquals(p1.getResult().message(), p2.getResult().message());
|
||||
|
||||
|
||||
// restart interpreter with isolated(per note process) mode enabled
|
||||
for (InterpreterSetting setting : notebook.getInterpreterFactory().getInterpreterSettings(note1.getId())) {
|
||||
setting.getOption().setPerNoteSession(false);
|
||||
setting.getOption().setPerNoteProcess(true);
|
||||
notebook.getInterpreterFactory().restart(setting.getId());
|
||||
}
|
||||
|
||||
// run per note process enabled
|
||||
note1.run(p1.getId());
|
||||
note2.run(p2.getId());
|
||||
|
||||
while (p1.getStatus() != Status.FINISHED) Thread.yield();
|
||||
while (p2.getStatus() != Status.FINISHED) Thread.yield();
|
||||
|
||||
assertNotEquals(p1.getResult().message(), p2.getResult().message());
|
||||
|
||||
notebook.removeNote(note1.getId(), null);
|
||||
notebook.removeNote(note2.getId(), null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue