You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by bz...@apache.org on 2015/12/10 12:35:19 UTC
incubator-zeppelin git commit: Add job operation API
Repository: incubator-zeppelin
Updated Branches:
refs/heads/master c5c92ed1f -> 664a13a2f
Add job operation API
This PR is related to https://issues.apache.org/jira/browse/ZEPPELIN-137.
I added some notebook job operations.
Here is the examples.
* Get notebook job status.
```
]# curl -XGET http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA
{"status":"OK","body":[{"id":"20151121-212654_766735423","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:39 KST 2015"},{"id":"20151121-212657_730976687","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"},{"id":"20151121-235508_752057578","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"},{"id":"20151121-235900_1491052248","status":"FINISHED","finished":"Tue Nov 24 14:21:41 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"},{"id":"20151121-235909_1520022794","status":"RUNNING","finished":"Tue Nov 24 02:53:51 KST 2015","started":"Tue Nov 24 14:21:41 KST 2015"}]}
```
* Run notebook job.
```
]# curl -XDELETE http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA
{"status":"ACCEPTED"}
```
* Stop(Delete) notebook job.
```
]# curl -XDELETE http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA
{"status":"ACCEPTED"}
```
* Run requested paragraph job.
```
]# curl -XPOST http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA/20151121-212654_766735423
{"status":"ACCEPTED"}
```
* Stop(Delete) requested paragraph job.
```
]# curl -XDELETE http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA/20151121-212654_766735423
{"status":"ACCEPTED"}
```
Author: astroshim <hs...@nflabs.com>
Author: root <root@ktadm002.(none)>
Closes #465 from astroshim/improve/addApis and squashes the following commits:
c668ed9 [astroshim] update REST API docs
a83289e [astroshim] fix restapi testcase(status code).
d0afd18 [astroshim] fix http status code.
775e7c8 [astroshim] update testcase.
fe8d5eb [astroshim] check if note config null.
dbd2d03 [astroshim] update note.java to find error.
861f652 [astroshim] fix indent error.
2989096 [astroshim] add generateParagraphsInfo method to Note.java
cb99391 [astroshim] merge with master
8002cd5 [astroshim] change restapi testcase to find build problem.
5bb2c5e [astroshim] fix getCronJob response code.
73f3b2b [astroshim] add cron job api's
3e2ea3d [astroshim] update testcase.
722f05b [astroshim] merge seperated job testcase.
2bff6c9 [root] add job run and stop testcase.
6103c42 [astroshim] fix LineLength build error.
e5f7103 [astroshim] fix whitespace build error.
7a7f993 [astroshim] fix indentation build error.
6c1acf3 [astroshim] fix result message.
1255674 [astroshim] add job operation api
Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/664a13a2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/664a13a2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/664a13a2
Branch: refs/heads/master
Commit: 664a13a2f69498fdd4ce4c1a29d970d9fb40f882
Parents: c5c92ed
Author: astroshim <hs...@nflabs.com>
Authored: Thu Dec 10 00:19:49 2015 +0900
Committer: Alexander Bezzubov <bz...@apache.org>
Committed: Thu Dec 10 20:35:03 2015 +0900
----------------------------------------------------------------------
docs/rest-api/rest-notebook.md | 256 +++++++++++++++++++
.../apache/zeppelin/rest/NotebookRestApi.java | 196 +++++++++++++-
.../zeppelin/rest/message/CronRequest.java | 38 +++
.../zeppelin/rest/AbstractTestRestApi.java | 4 +
.../zeppelin/rest/ZeppelinRestApiTest.java | 106 +++++++-
.../java/org/apache/zeppelin/notebook/Note.java | 15 ++
6 files changed, 613 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/docs/rest-api/rest-notebook.md
----------------------------------------------------------------------
diff --git a/docs/rest-api/rest-notebook.md b/docs/rest-api/rest-notebook.md
index ffee95a..1bb0e53 100644
--- a/docs/rest-api/rest-notebook.md
+++ b/docs/rest-api/rest-notebook.md
@@ -169,3 +169,259 @@ limitations under the License.
</tr>
</table>
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Run notebook job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```POST``` method run all paragraph in the given notebook id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK"}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Stop notebook job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```DELETE``` method stop all paragraph in the given notebook id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK"}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Get notebook job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```GET``` method get all paragraph status by the given notebook id.
+ The body field of the returned JSON contains of the array that compose of the paragraph id, paragraph status, paragraph finish date, paragraph started date.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK","body":[{"id":"20151121-212654_766735423","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:39 KST 2015"},{"id":"20151121-212657_730976687","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"}]}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Run paragraph job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```POST``` method run the paragraph by given notebook and paragraph id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]/[paragraphId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK"}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Stop paragraph job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```DELETE``` method stop the paragraph by given notebook and paragraph id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]/[paragraphId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK"}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Add cron job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```POST``` method add cron job by the given notebook id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[notebookId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON input </td>
+ <td><pre>{"cron": "cron expression of notebook"}</pre></td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK"}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Remove cron job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```DELETE``` method remove cron job by the given notebook id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[notebookId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK"}</pre></td>
+ </tr>
+ </table>
+
+<br/>
+
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <th>Get clone job</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>This ```GET``` method get cron job expression of given notebook id.
+ The body field of the returned JSON contain the cron expression.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[notebookId]```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td> Fail code</td>
+ <td> 500 </td>
+ </tr>
+ <tr>
+ <td> sample JSON response </td>
+ <td><pre>{"status":"OK","body":"* * * * * ?"}</pre></td>
+ </tr>
+ </table>
+
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/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 2b98633..b3f912e 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
@@ -29,12 +29,15 @@ import javax.ws.rs.core.Response.Status;
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.server.JsonResponse;
import org.apache.zeppelin.server.ZeppelinServer;
import org.apache.zeppelin.socket.NotebookServer;
+import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -166,11 +169,12 @@ public class NotebookRestApi {
notebookServer.broadcastNoteList();
return new JsonResponse(Status.OK, "").build();
}
+
/**
* Clone note REST API
* @param
* @return JSON with status.CREATED
- * @throws IOException
+ * @throws IOException, CloneNotSupportedException, IllegalArgumentException
*/
@POST
@Path("{notebookId}")
@@ -185,4 +189,194 @@ public class NotebookRestApi {
notebookServer.broadcastNoteList();
return new JsonResponse(Status.CREATED, "", newNote.getId()).build();
}
+
+ /**
+ * Run notebook jobs REST API
+ * @param
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @POST
+ @Path("job/{notebookId}")
+ public Response runNoteJobs(@PathParam("notebookId") String notebookId) throws
+ IOException, IllegalArgumentException {
+ logger.info("run notebook jobs {} ", notebookId);
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ note.runAll();
+ return new JsonResponse(Status.OK).build();
+ }
+
+ /**
+ * Stop(delete) notebook jobs REST API
+ * @param
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @DELETE
+ @Path("job/{notebookId}")
+ public Response stopNoteJobs(@PathParam("notebookId") String notebookId) throws
+ IOException, IllegalArgumentException {
+ logger.info("stop notebook jobs {} ", notebookId);
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ for (Paragraph p : note.getParagraphs()) {
+ if (!p.isTerminated()) {
+ p.abort();
+ }
+ }
+ return new JsonResponse(Status.OK).build();
+ }
+
+ /**
+ * Get notebook job status REST API
+ * @param
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @GET
+ @Path("job/{notebookId}")
+ public Response getNoteJobStatus(@PathParam("notebookId") String notebookId) throws
+ IOException, IllegalArgumentException {
+ logger.info("get notebook job status.");
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ return new JsonResponse(Status.OK, null, note.generateParagraphsInfo()).build();
+ }
+
+ /**
+ * Run paragraph job REST API
+ * @param
+ * @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
+ IOException, IllegalArgumentException {
+ logger.info("run paragraph job {} {} ", notebookId, paragraphId);
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ if (note.getParagraph(paragraphId) == null) {
+ return new JsonResponse(Status.NOT_FOUND, "paragraph not found.").build();
+ }
+
+ note.run(paragraphId);
+ return new JsonResponse(Status.OK).build();
+ }
+
+ /**
+ * Stop(delete) paragraph job REST API
+ * @param
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @DELETE
+ @Path("job/{notebookId}/{paragraphId}")
+ public Response stopParagraph(@PathParam("notebookId") String notebookId,
+ @PathParam("paragraphId") String paragraphId) throws
+ IOException, IllegalArgumentException {
+ logger.info("stop paragraph job {} ", notebookId);
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ Paragraph p = note.getParagraph(paragraphId);
+ if (p == null) {
+ return new JsonResponse(Status.NOT_FOUND, "paragraph not found.").build();
+ }
+ p.abort();
+ return new JsonResponse(Status.OK).build();
+ }
+
+ /**
+ * Register cron job REST API
+ * @param message - JSON with cron expressions.
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @POST
+ @Path("cron/{notebookId}")
+ public Response registerCronJob(@PathParam("notebookId") String notebookId, String message) throws
+ IOException, IllegalArgumentException {
+ logger.info("Register cron job note={} request cron msg={}", notebookId, message);
+
+ CronRequest request = gson.fromJson(message,
+ CronRequest.class);
+
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ if (!CronExpression.isValidExpression(request.getCronString())) {
+ return new JsonResponse(Status.BAD_REQUEST, "wrong cron expressions.").build();
+ }
+
+ Map<String, Object> config = note.getConfig();
+ config.put("cron", request.getCronString());
+ note.setConfig(config);
+ notebook.refreshCron(note.id());
+
+ return new JsonResponse(Status.OK).build();
+ }
+
+ /**
+ * Remove cron job REST API
+ * @param
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @DELETE
+ @Path("cron/{notebookId}")
+ public Response removeCronJob(@PathParam("notebookId") String notebookId) throws
+ IOException, IllegalArgumentException {
+ logger.info("Remove cron job note {}", notebookId);
+
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ Map<String, Object> config = note.getConfig();
+ config.put("cron", null);
+ note.setConfig(config);
+ notebook.refreshCron(note.id());
+
+ return new JsonResponse(Status.OK).build();
+ }
+
+ /**
+ * Get cron job REST API
+ * @param
+ * @return JSON with status.OK
+ * @throws IOException, IllegalArgumentException
+ */
+ @GET
+ @Path("cron/{notebookId}")
+ public Response getCronJob(@PathParam("notebookId") String notebookId) throws
+ IOException, IllegalArgumentException {
+ logger.info("Get cron job note {}", notebookId);
+
+ Note note = notebook.getNote(notebookId);
+ if (note == null) {
+ return new JsonResponse(Status.NOT_FOUND, "note not found.").build();
+ }
+
+ return new JsonResponse(Status.OK, note.getConfig().get("cron")).build();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java
new file mode 100644
index 0000000..5a33931
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import org.apache.zeppelin.interpreter.InterpreterOption;
+
+/**
+ * CronRequest rest api request message
+ *
+ */
+public class CronRequest {
+ String cron;
+
+ public CronRequest (){
+
+ }
+
+ public String getCronString() {
+ return cron;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
index 1895e16..db7affe 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
@@ -393,6 +393,10 @@ public abstract class AbstractTestRestApi {
protected Matcher<? super HttpMethodBase> isCreated() { return responsesWith(201); }
+ protected Matcher<? super HttpMethodBase> isBadRequest() { return responsesWith(400); }
+
+ protected Matcher<? super HttpMethodBase> isNotFound() { return responsesWith(404); }
+
protected Matcher<? super HttpMethodBase> isNotAllowed() {
return responsesWith(405);
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/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 8468de2..0a58fb0 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
@@ -264,7 +264,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
LOG.info("testCloneNotebook");
// Create note to clone
Note note = ZeppelinServer.notebook.createNote();
- assertNotNull("cant create new note", note);
+ assertNotNull("can't create new note", note);
note.setName("source note for clone");
Paragraph paragraph = note.addParagraph();
Map config = paragraph.getConfig();
@@ -308,5 +308,109 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
get.releaseConnection();
}
+ @Test
+ public void testNoteJobs() throws IOException, InterruptedException {
+ LOG.info("testNoteJobs");
+ // 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("%md This is test paragraph.");
+ 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++ > 10) {
+ LOG.info("testNoteJobs timeout job.");
+ break;
+ }
+ }
+
+ // Call Run Notebook Jobs REST API
+ PostMethod postNoteJobs = httpPost("/notebook/job/" + noteID, "");
+ assertThat("test notebook jobs run:", postNoteJobs, isAllowed());
+ postNoteJobs.releaseConnection();
+
+ // Call Stop Notebook Jobs REST API
+ DeleteMethod deleteNoteJobs = httpDelete("/notebook/job/" + noteID);
+ assertThat("test notebook stop:", deleteNoteJobs, isAllowed());
+ deleteNoteJobs.releaseConnection();
+ Thread.sleep(1000);
+
+ // Call Run paragraph REST API
+ PostMethod postParagraph = httpPost("/notebook/job/" + noteID + "/" + paragraph.getId(), "");
+ assertThat("test paragraph run:", postParagraph, isAllowed());
+ postParagraph.releaseConnection();
+ Thread.sleep(1000);
+
+ // Call Stop paragraph REST API
+ DeleteMethod deleteParagraph = httpDelete("/notebook/job/" + noteID + "/" + paragraph.getId());
+ assertThat("test paragraph stop:", deleteParagraph, isAllowed());
+ deleteParagraph.releaseConnection();
+ Thread.sleep(1000);
+
+ //cleanup
+ ZeppelinServer.notebook.removeNote(note.getId());
+ }
+
+ @Test
+ public void testCronJobs() throws InterruptedException, IOException{
+ // create a note and a paragraph
+ Note note = ZeppelinServer.notebook.createNote();
+
+ note.setName("note for run test");
+ Paragraph paragraph = note.addParagraph();
+ paragraph.setText("%md This is test paragraph.");
+
+ Map config = paragraph.getConfig();
+ config.put("enabled", true);
+ paragraph.setConfig(config);
+
+ note.runAll();
+ // wait until job is finished or timeout.
+ int timeout = 1;
+ while (!paragraph.isTerminated()) {
+ Thread.sleep(1000);
+ if (timeout++ > 10) {
+ LOG.info("testNoteJobs timeout job.");
+ break;
+ }
+ }
+
+ String jsonRequest = "{\"cron\":\"* * * * * ?\" }";
+ // right cron expression but not exist note.
+ PostMethod postCron = httpPost("/notebook/cron/notexistnote", jsonRequest);
+ assertThat("", postCron, isNotFound());
+ postCron.releaseConnection();
+
+ // right cron expression.
+ postCron = httpPost("/notebook/cron/" + note.getId(), jsonRequest);
+ assertThat("", postCron, isAllowed());
+ postCron.releaseConnection();
+ Thread.sleep(1000);
+
+ // wrong cron expression.
+ jsonRequest = "{\"cron\":\"a * * * * ?\" }";
+ postCron = httpPost("/notebook/cron/" + note.getId(), jsonRequest);
+ assertThat("", postCron, isBadRequest());
+ postCron.releaseConnection();
+ Thread.sleep(1000);
+
+ // remove cron job.
+ DeleteMethod deleteCron = httpDelete("/notebook/cron/" + note.getId());
+ assertThat("", deleteCron, isAllowed());
+ deleteCron.releaseConnection();
+ ZeppelinServer.notebook.removeNote(note.getId());
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
index 66a63c8..93dcec5 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
@@ -293,6 +293,21 @@ public class Note implements Serializable, JobListener {
return paragraphs.get(paragraphs.size() - 1);
}
}
+
+ public List<Map<String, String>> generateParagraphsInfo (){
+ List<Map<String, String>> paragraphsInfo = new LinkedList<>();
+ synchronized (paragraphs) {
+ for (Paragraph p : paragraphs) {
+ Map<String, String> info = new HashMap<>();
+ info.put("id", p.getId());
+ info.put("status", p.getStatus().toString());
+ info.put("started", p.getDateStarted().toString());
+ info.put("finished", p.getDateFinished().toString());
+ paragraphsInfo.add(info);
+ }
+ }
+ return paragraphsInfo;
+ }
/**
* Run all paragraphs sequentially.