ZEPPELIN-507 Expand "run paragraph" of REST API to specify params

* Modified "run paragraph" to specify params
  * which means we want to update dynamic form's value
* Added unit test to test this feature
* Updated rest-notebook.md to reflect new json request
This commit is contained in:
Jungtaek Lim 2015-12-16 17:12:40 +09:00
parent 42100550f3
commit 8dcf02c0cf
4 changed files with 117 additions and 11 deletions

View file

@ -290,6 +290,18 @@ limitations under the License.
<td> Fail code</td>
<td> 500 </td>
</tr>
<tr>
<td> sample JSON input (optional, only needed when if you want to update dynamic form's value) </td>
<td><pre>
{
"name": "name of new notebook",
"params": {
"formLabel1": "value1",
"formLabel2": "value2"
}
}
</pre></td>
</tr>
<tr>
<td> sample JSON response </td>
<td><pre>{"status":"OK"}</pre></td>

View file

@ -26,14 +26,13 @@ import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils;
import org.apache.zeppelin.display.Input;
import org.apache.zeppelin.interpreter.InterpreterSetting;
import org.apache.zeppelin.notebook.Note;
import org.apache.zeppelin.notebook.Notebook;
import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.rest.message.CronRequest;
import org.apache.zeppelin.rest.message.InterpreterSettingListForNoteBind;
import org.apache.zeppelin.rest.message.NewInterpreterSettingRequest;
import org.apache.zeppelin.rest.message.NewNotebookRequest;
import org.apache.zeppelin.rest.message.*;
import org.apache.zeppelin.server.JsonResponse;
import org.apache.zeppelin.server.ZeppelinServer;
import org.apache.zeppelin.socket.NotebookServer;
@ -255,26 +254,41 @@ public class NotebookRestApi {
/**
* Run paragraph job REST API
* @param
* @param message - JSON with params if user wants to update dynamic form's value
* null, empty string, empty json if user doesn't want to update
* @return JSON with status.OK
* @throws IOException, IllegalArgumentException
*/
@POST
@Path("job/{notebookId}/{paragraphId}")
public Response runParagraph(@PathParam("notebookId") String notebookId,
@PathParam("paragraphId") String paragraphId) throws
@PathParam("paragraphId") String paragraphId,
String message) throws
IOException, IllegalArgumentException {
logger.info("run paragraph job {} {} ", notebookId, paragraphId);
logger.info("run paragraph job {} {} {}", notebookId, paragraphId, message);
Note note = notebook.getNote(notebookId);
if (note == null) {
return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
}
if (note.getParagraph(paragraphId) == null) {
Paragraph paragraph = note.getParagraph(paragraphId);
if (paragraph == null) {
return new JsonResponse(Status.NOT_FOUND, "paragraph not found.").build();
}
note.run(paragraphId);
// handle params if presented
if (!StringUtils.isEmpty(message)) {
RunParagraphWithParametersRequest request = gson.fromJson(message,
RunParagraphWithParametersRequest.class);
Map<String, Object> paramsForUpdating = request.getParams();
if (paramsForUpdating != null) {
paragraph.settings.getParams().putAll(paramsForUpdating);
note.persist();
}
}
note.run(paragraph.getId());
return new JsonResponse(Status.OK).build();
}

View file

@ -0,0 +1,35 @@
/*
* 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;
import java.util.Map;
/**
* RunParagraphWithParametersRequest rest api request message
*/
public class RunParagraphWithParametersRequest {
Map<String, Object> params;
public RunParagraphWithParametersRequest() {
}
public Map<String, Object> getParams() {
return params;
}
}

View file

@ -362,7 +362,52 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
//cleanup
ZeppelinServer.notebook.removeNote(note.getId());
}
@Test
public void testRunParagraphWithParams() throws IOException, InterruptedException {
LOG.info("testRunParagraphWithParams");
// Create note to run test.
Note note = ZeppelinServer.notebook.createNote();
assertNotNull("can't create new note", note);
note.setName("note for run test");
Paragraph paragraph = note.addParagraph();
Map config = paragraph.getConfig();
config.put("enabled", true);
paragraph.setConfig(config);
paragraph.setText("%spark\nval param = z.input(\"param\").toString\nprintln(param)");
note.persist();
String noteID = note.getId();
note.runAll();
// wait until job is finished or timeout.
int timeout = 1;
while (!paragraph.isTerminated()) {
Thread.sleep(1000);
if (timeout++ > 30) {
LOG.info("testRunParagraphWithParams timeout job.");
break;
}
}
// Call Run paragraph REST API
PostMethod postParagraph = httpPost("/notebook/job/" + noteID + "/" + paragraph.getId(),
"{\"params\": {\"param\": \"hello\", \"param2\": \"world\"}}");
assertThat("test paragraph run:", postParagraph, isAllowed());
postParagraph.releaseConnection();
Thread.sleep(1000);
Note retrNote = ZeppelinServer.notebook.getNote(noteID);
Paragraph retrParagraph = retrNote.getParagraph(paragraph.getId());
Map<String, Object> params = retrParagraph.settings.getParams();
assertEquals("hello", params.get("param"));
assertEquals("world", params.get("param2"));
//cleanup
ZeppelinServer.notebook.removeNote(note.getId());
}
@Test
public void testCronJobs() throws InterruptedException, IOException{
// create a note and a paragraph