Repository: incubator-zeppelin Updated Branches: refs/heads/master 1ba6e2a59 -> 9fec2598c
ZEPPELIN-507 Expand "run paragraph" of REST API to update dynamic form's value ### What is this PR for? To update dynamic form's value (via params) when running paragraph via REST API ### What type of PR is it? Improvement ### Todos ### Is there a relevant Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-507 ### How should this be tested? * Create a new notebook with one paragraph which contains ``` %spark val form1 = z.input("form1").toString ``` * Get paragraph ID via websocket (I think we should add a new REST API to get it easily.) * Request ```http://<zeppelin host>:<zeppelin port>/api/notebook/job/<notebook id>/<paragraph id>``` with POST method including JSON payload, ``` { "params": { "form1": "value1" } } ``` * Confirm that paragraph has run and input text of form1 is filled with "value1" (from the UI) ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? (No) * Is there breaking changes for older versions? (No, additonal json payload is optional.) * Does this needs documentation? (Yes, I've addressed it.) Author: Jungtaek Lim <[email protected]> Closes #541 from HeartSaVioR/ZEPPELIN-507 and squashes the following commits: 814664e [Jungtaek Lim] ZEPPELIN-507 Increase timeout for initializing spark interpreter 8dcf02c [Jungtaek Lim] ZEPPELIN-507 Expand "run paragraph" of REST API to specify params Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/9fec2598 Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/9fec2598 Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/9fec2598 Branch: refs/heads/master Commit: 9fec2598ca36578517aed6d776fef8060df42755 Parents: 1ba6e2a Author: Jungtaek Lim <[email protected]> Authored: Mon Dec 21 10:15:12 2015 +0900 Committer: Lee moon soo <[email protected]> Committed: Tue Dec 22 04:28:25 2015 +0900 ---------------------------------------------------------------------- docs/rest-api/rest-notebook.md | 12 +++++ .../apache/zeppelin/rest/NotebookRestApi.java | 29 +++++++++--- .../RunParagraphWithParametersRequest.java | 35 +++++++++++++++ .../zeppelin/rest/ZeppelinRestApiTest.java | 47 +++++++++++++++++++- 4 files changed, 116 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/9fec2598/docs/rest-api/rest-notebook.md ---------------------------------------------------------------------- diff --git a/docs/rest-api/rest-notebook.md b/docs/rest-api/rest-notebook.md index bbecc5c..0739bcb 100644 --- a/docs/rest-api/rest-notebook.md +++ b/docs/rest-api/rest-notebook.md @@ -309,6 +309,18 @@ limitations under the License. <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> </tr> http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/9fec2598/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java index 4f1dd01..29c5c29 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java @@ -26,6 +26,8 @@ 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; @@ -260,26 +262,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(); } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/9fec2598/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/RunParagraphWithParametersRequest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/RunParagraphWithParametersRequest.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/RunParagraphWithParametersRequest.java new file mode 100644 index 0000000..7d8095f --- /dev/null +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/RunParagraphWithParametersRequest.java @@ -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; + } +} http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/9fec2598/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java index 3111807..cee36b4 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java @@ -405,7 +405,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++ > 120) { + 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
