You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by ji...@apache.org on 2020/12/16 15:35:48 UTC
[submarine] branch master updated: SUBMARINE-675. Sync the status
of notebook
This is an automated email from the ASF dual-hosted git repository.
jiwq pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git
The following commit(s) were added to refs/heads/master by this push:
new d104080 SUBMARINE-675. Sync the status of notebook
d104080 is described below
commit d104080a926d30bcc45ccd740f9489dd7365d0b5
Author: Ryan Lo <lo...@gmail.com>
AuthorDate: Thu Dec 3 12:45:32 2020 +0800
SUBMARINE-675. Sync the status of notebook
### What is this PR for?
1. The notebook REST api will return four states of notebook (creating/waiting/running/terminating) and its reason.
- creating : Users submitted the request to create notebook and its pod haven't been created.
- waiting : Still running the operations it requires in order to complete start up: for example, pulling the container image.
- running : The container is executing without issues and readyReplicas equals to 1
- terminating : Users submitted the request to delete notebook
2. Refactoring K8sSubmitter
3. Update userdocs/k8s/api/notebook.md
### What type of PR is it?
[Improvement | Documentation | Refactoring]
### Todos
* [kobe860219 ] - Front-end : Using RxJS to do polling the status of notebook instance and adding spinner when notebook status is creating/waiting.
### What is the Jira issue?
[SUBMARINE-675](https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-675)
### How should this be tested?
[Travis CI](https://travis-ci.org/github/lowc1012/submarine/builds/747154671)
### Screenshots (if appropriate)
<img width="1189" alt="image" src="https://user-images.githubusercontent.com/52355146/100850958-8209a480-34bf-11eb-83b3-cef183a893cd.png">
### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No
Author: Ryan Lo <lo...@gmail.com>
Closes #468 from lowc1012/SUBMARINE-675 and squashes the following commits:
0dfe1a1 [Ryan Lo] convert to static methods
d4f89b9 [Ryan Lo] SUBMARINE-675. update
a9a4717 [Ryan Lo] SUBMARINE-675. Sync the status of notebook
---
docs/userdocs/k8s/api/notebook.md | 20 ++-
.../submarine/server/api/notebook/Notebook.java | 18 ++-
.../submarine/server/notebook/NotebookManager.java | 2 +
.../server/submitter/k8s/K8sSubmitter.java | 74 +---------
.../server/submitter/k8s/model/NotebookCR.java | 10 ++
.../server/submitter/k8s/model/NotebookCRList.java | 38 -----
...{NotebookCRList.java => NotebookCondition.java} | 52 ++-----
.../{NotebookCRList.java => NotebookStatus.java} | 51 ++-----
.../server/submitter/k8s/util/NotebookUtils.java | 161 +++++++++++++++++++++
.../apache/submarine/rest/NotebookRestApiIT.java | 5 +-
10 files changed, 234 insertions(+), 197 deletions(-)
diff --git a/docs/userdocs/k8s/api/notebook.md b/docs/userdocs/k8s/api/notebook.md
index ca40e48..2f6db82 100644
--- a/docs/userdocs/k8s/api/notebook.md
+++ b/docs/userdocs/k8s/api/notebook.md
@@ -43,7 +43,7 @@ curl -X POST -H "Content-Type: application/json" -d '
"resources": "cpu=1,memory=1.0Gi"
}
}
-' http://127.0.0.1:8080/api/v1/notebook
+' http://127.0.0.1:32080/api/v1/notebook
```
**Example Response:**
@@ -58,7 +58,8 @@ curl -X POST -H "Content-Type: application/json" -d '
"name":"test-nb",
"uid":"5a94c01d-6a92-4222-bc66-c610c277546d",
"url":"/notebook/default/test-nb/",
- "status":"Created",
+ "status":"creating",
+ "reason":"The notebook instance is creating",
"createdTime":"2020-08-20T21:58:27.000+08:00",
"deletedTime":null,
"spec":{
@@ -99,7 +100,7 @@ curl -X POST -H "Content-Type: application/json" -d '
**Example Request:**
```sh
-curl -X GET http://127.0.0.1:8080/api/v1/notebook?id={user_id}
+curl -X GET http://127.0.0.1:32080/api/v1/notebook?id={user_id}
```
**Example Response:**
@@ -115,7 +116,8 @@ curl -X GET http://127.0.0.1:8080/api/v1/notebook?id={user_id}
"name":"test-nb",
"uid":"5a94c01d-6a92-4222-bc66-c610c277546d",
"url":"/notebook/default/test-nb/",
- "status":"Created",
+ "status": "running",
+ "reason": "The notebook instance is running",
"createdTime":"2020-08-20T21:58:27.000+08:00",
"deletedTime":null,
"spec":{
@@ -157,7 +159,7 @@ curl -X GET http://127.0.0.1:8080/api/v1/notebook?id={user_id}
**Example Request:**
```sh
-curl -X GET http://127.0.0.1:8080/api/v1/notebook/{id}
+curl -X GET http://127.0.0.1:32080/api/v1/notebook/{id}
```
**Example Response:**
@@ -172,7 +174,8 @@ curl -X GET http://127.0.0.1:8080/api/v1/notebook/{id}
"name":"test-nb",
"uid":"5a94c01d-6a92-4222-bc66-c610c277546d",
"url":"/notebook/default/test-nb/",
- "status":"Created",
+ "status":"running",
+ "reason":"The notebook instance is running",
"createdTime":"2020-08-20T21:58:27.000+08:00",
"deletedTime":null,
"spec":{
@@ -213,7 +216,7 @@ curl -X GET http://127.0.0.1:8080/api/v1/notebook/{id}
**Example Request:**
```sh
-curl -X DELETE http://127.0.0.1:8080/api/v1/notebook/{id}
+curl -X DELETE http://127.0.0.1:32080/api/v1/notebook/{id}
```
**Example Response:**
@@ -228,7 +231,8 @@ curl -X DELETE http://127.0.0.1:8080/api/v1/notebook/{id}
"name": "test-nb",
"uid": "5a94c01d-6a92-4222-bc66-c610c277546d",
"url": "/notebook/default/test-nb/",
- "status": "Deleted",
+ "status": "terminating",
+ "reason": "The notebook instance is terminating",
"createdTime": "2020-08-22T14:03:19.000+08:00",
"deletedTime": "2020-08-22T14:46:28+0800",
"spec": {
diff --git a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/notebook/Notebook.java b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/notebook/Notebook.java
index 1e0ea36..1902cca 100644
--- a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/notebook/Notebook.java
+++ b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/notebook/Notebook.java
@@ -30,6 +30,7 @@ public class Notebook {
private String uid;
private String url;
private String status;
+ private String reason;
private String createdTime;
private String deletedTime;
private NotebookSpec spec;
@@ -74,6 +75,14 @@ public class Notebook {
this.status = status;
}
+ public String getReason() {
+ return reason;
+ }
+
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+
public String getCreatedTime() {
return createdTime;
}
@@ -99,8 +108,10 @@ public class Notebook {
}
public enum Status {
- STATUS_CREATED("Created"),
- STATUS_DELETED("Deleted");
+ STATUS_CREATING("creating"),
+ STATUS_RUNNING("running"),
+ STATUS_WAITING("waiting"),
+ STATUS_TERMINATING("terminating");
private String value;
Status(String value) {
@@ -134,6 +145,9 @@ public class Notebook {
if (notebook.getStatus() != null) {
this.setStatus(notebook.getStatus());
}
+ if (notebook.getReason() != null) {
+ this.setReason(notebook.getReason());
+ }
if (notebook.getCreatedTime() != null) {
this.setCreatedTime(notebook.getCreatedTime());
}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/notebook/NotebookManager.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/notebook/NotebookManager.java
index 92dbfed..da23c9c 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/notebook/NotebookManager.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/notebook/NotebookManager.java
@@ -84,6 +84,8 @@ public class NotebookManager {
Notebook notebook = submitter.createNotebook(spec);
notebook.setNotebookId(generateNotebookId());
notebook.setSpec(spec);
+
+ // environment information
NotebookSpec notebookSpec = notebook.getSpec();
EnvironmentManager environmentManager = EnvironmentManager.getInstance();
Environment environment = environmentManager.getEnvironment(spec.getEnvironment().getName());
diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java
index 78a427e..a97aa63 100644
--- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java
+++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java
@@ -21,14 +21,11 @@ package org.apache.submarine.server.submitter.k8s;
import java.io.FileReader;
import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.List;
-import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
@@ -57,14 +54,13 @@ import org.apache.submarine.server.api.spec.ExperimentSpec;
import org.apache.submarine.server.api.spec.NotebookSpec;
import org.apache.submarine.server.submitter.k8s.model.MLJob;
import org.apache.submarine.server.submitter.k8s.model.NotebookCR;
-import org.apache.submarine.server.submitter.k8s.model.NotebookCRList;
import org.apache.submarine.server.submitter.k8s.model.ingressroute.IngressRoute;
import org.apache.submarine.server.submitter.k8s.model.ingressroute.IngressRouteSpec;
import org.apache.submarine.server.submitter.k8s.model.ingressroute.SpecRoute;
import org.apache.submarine.server.submitter.k8s.parser.ExperimentSpecParser;
import org.apache.submarine.server.submitter.k8s.parser.NotebookSpecParser;
import org.apache.submarine.server.submitter.k8s.util.MLJobConverter;
-import org.joda.time.DateTime;
+import org.apache.submarine.server.submitter.k8s.util.NotebookUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -260,7 +256,7 @@ public class K8sSubmitter implements Submitter {
notebookCR.getMetadata().setLabels(labels);
Object object = api.createNamespacedCustomObject(notebookCR.getGroup(), notebookCR.getVersion(),
notebookCR.getMetadata().getNamespace(), notebookCR.getPlural(), notebookCR, "true");
- notebook = parseNotebookResponseObject(object);
+ notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_CREATE);
// create Traefik custom resource
createIngressRoute(notebookCR.getMetadata().getNamespace(), notebookCR.getMetadata().getName());
@@ -284,7 +280,7 @@ public class K8sSubmitter implements Submitter {
Object object = api.getNamespacedCustomObject(notebookCR.getGroup(), notebookCR.getVersion(),
notebookCR.getMetadata().getNamespace(),
notebookCR.getPlural(), notebookCR.getMetadata().getName());
- notebook = parseNotebookResponseObject(object);
+ notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_GET);
} catch (ApiException e) {
throw new SubmarineRuntimeException(e.getCode(), e.getMessage());
}
@@ -301,7 +297,7 @@ public class K8sSubmitter implements Submitter {
notebookCR.getMetadata().getName(),
new V1DeleteOptionsBuilder().withApiVersion(notebookCR.getApiVersion()).build(),
null, null, null);
- notebook = parseNotebookResponseObject(object);
+ notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_DELETE);
deleteIngressRoute(notebookCR.getMetadata().getNamespace(), notebookCR.getMetadata().getName());
} catch (ApiException e) {
throw new SubmarineRuntimeException(e.getCode(), e.getMessage());
@@ -317,73 +313,13 @@ public class K8sSubmitter implements Submitter {
NotebookCR.CRD_NOTEBOOK_VERSION_V1, NotebookCR.CRD_NOTEBOOK_PLURAL_V1,
"true", null, NotebookCR.NOTEBOOK_OWNER_SELECTOR_KET + "=" + id,
null, null, null);
- notebookList = parseNotebookListResponseObject(object);
+ notebookList = NotebookUtils.parseObjectForList(object);
} catch (ApiException e) {
throw new SubmarineRuntimeException(e.getCode(), e.getMessage());
}
return notebookList;
}
- private Notebook parseNotebookResponseObject(Object obj) throws SubmarineRuntimeException {
- Gson gson = new JSON().getGson();
- String jsonString = gson.toJson(obj);
- LOG.info("Upstream response JSON: {}", jsonString);
- Notebook notebook;
- try {
- NotebookCR notebookCR = gson.fromJson(jsonString, NotebookCR.class);
- if (notebookCR.getMetadata().getName() != null) {
- notebook = buildNotebookResponse(notebookCR);
- // notebook is deleted
- } else {
- notebook = new Notebook();
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
- Date current = new Date();
- notebook.setDeletedTime(dateFormat.format(current));
- notebook.setStatus(Notebook.Status.STATUS_DELETED.toString());
- }
-
- } catch (JsonSyntaxException e) {
- LOG.error("K8s submitter: parse response object failed by " + e.getMessage(), e);
- throw new SubmarineRuntimeException(500, "K8s Submitter parse upstream response failed.");
- }
- return notebook;
- }
-
- private List<Notebook> parseNotebookListResponseObject(Object object) {
- Gson gson = new JSON().getGson();
- String jsonString = gson.toJson(object);
- LOG.info("Upstream response JSON: {}", jsonString);
-
- Notebook notebook;
- List<Notebook> notebookList = new ArrayList<>();
- try {
- NotebookCRList notebookCRList = gson.fromJson(jsonString, NotebookCRList.class);
- for (NotebookCR notebookCR : notebookCRList.getItems()) {
- notebook = buildNotebookResponse(notebookCR);
- notebookList.add(notebook);
- }
- } catch (JsonSyntaxException e) {
- LOG.error("K8s submitter: parse response object failed by " + e.getMessage(), e);
- throw new SubmarineRuntimeException(500, "K8s Submitter parse upstream response failed.");
- }
- return notebookList;
- }
-
- private Notebook buildNotebookResponse(NotebookCR notebookCR) {
- Notebook notebook = new Notebook();
- notebook.setUid(notebookCR.getMetadata().getUid());
- notebook.setName(notebookCR.getMetadata().getName());
- // notebook url
- notebook.setUrl("/notebook/" + notebookCR.getMetadata().getNamespace() + "/" +
- notebookCR.getMetadata().getName() + "/");
- DateTime createdTime = notebookCR.getMetadata().getCreationTimestamp();
- if (createdTime != null) {
- notebook.setCreatedTime(createdTime.toString());
- notebook.setStatus(Notebook.Status.STATUS_CREATED.getValue());
- }
- return notebook;
- }
-
private String getJobLabelSelector(ExperimentSpec experimentSpec) {
// TODO(JohnTing): SELECTOR_KEY should be obtained from individual models in MLJOB
if (experimentSpec.getMeta().getFramework()
diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java
index 69d9fcc..c93e189 100644
--- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java
+++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java
@@ -49,6 +49,9 @@ public class NotebookCR {
@SerializedName("spec")
private NotebookCRSpec spec;
+ @SerializedName("status")
+ private NotebookStatus status;
+
public NotebookCR() {
setApiVersion(CRD_APIVERSION_V1);
setKind(CRD_NOTEBOOK_KIND_V1);
@@ -113,4 +116,11 @@ public class NotebookCR {
this.spec = spec;
}
+ public NotebookStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(NotebookStatus status) {
+ this.status = status;
+ }
}
diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
index 0fa78b2..ccdca63 100644
--- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
+++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
@@ -20,53 +20,15 @@
package org.apache.submarine.server.submitter.k8s.model;
import com.google.gson.annotations.SerializedName;
-import io.kubernetes.client.models.V1ListMeta;
import java.util.List;
public class NotebookCRList {
- @SerializedName("apiVersion")
- private String apiVersion;
-
@SerializedName("items")
private List<NotebookCR> items;
- @SerializedName("kind")
- private String kind;
-
- @SerializedName("metadata")
- private V1ListMeta metadata;
-
- public String getApiVersion() {
- return apiVersion;
- }
-
- public void setApiVersion(String apiVersion) {
- this.apiVersion = apiVersion;
- }
-
public List<NotebookCR> getItems() {
return items;
}
-
- public void setItems(List<NotebookCR> items) {
- this.items = items;
- }
-
- public String getKind() {
- return kind;
- }
-
- public void setKing(String kind) {
- this.kind = kind;
- }
-
- public V1ListMeta getMetadata() {
- return metadata;
- }
-
- public void setMetadata(V1ListMeta metadata) {
- this.metadata = metadata;
- }
}
diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCondition.java
similarity index 51%
copy from submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
copy to submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCondition.java
index 0fa78b2..d16802f 100644
--- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
+++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCondition.java
@@ -16,57 +16,27 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.submarine.server.submitter.k8s.model;
import com.google.gson.annotations.SerializedName;
-import io.kubernetes.client.models.V1ListMeta;
-
-import java.util.List;
-
-public class NotebookCRList {
-
- @SerializedName("apiVersion")
- private String apiVersion;
-
- @SerializedName("items")
- private List<NotebookCR> items;
-
- @SerializedName("kind")
- private String kind;
-
- @SerializedName("metadata")
- private V1ListMeta metadata;
+import org.joda.time.DateTime;
- public String getApiVersion() {
- return apiVersion;
- }
+public class NotebookCondition {
- public void setApiVersion(String apiVersion) {
- this.apiVersion = apiVersion;
- }
+ public NotebookCondition() {
- public List<NotebookCR> getItems() {
- return items;
}
- public void setItems(List<NotebookCR> items) {
- this.items = items;
- }
+ @SerializedName("type")
+ private String type;
- public String getKind() {
- return kind;
- }
+ @SerializedName("lastProbeTime")
+ private DateTime lastProbeTime;
- public void setKing(String kind) {
- this.kind = kind;
- }
+ @SerializedName("reason")
+ private String reason;
- public V1ListMeta getMetadata() {
- return metadata;
- }
+ @SerializedName("message")
+ private String message;
- public void setMetadata(V1ListMeta metadata) {
- this.metadata = metadata;
- }
}
diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java
similarity index 53%
copy from submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
copy to submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java
index 0fa78b2..bc11006 100644
--- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRList.java
+++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java
@@ -16,57 +16,36 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.submarine.server.submitter.k8s.model;
import com.google.gson.annotations.SerializedName;
-import io.kubernetes.client.models.V1ListMeta;
+import io.kubernetes.client.models.V1ContainerState;
import java.util.List;
-public class NotebookCRList {
-
- @SerializedName("apiVersion")
- private String apiVersion;
-
- @SerializedName("items")
- private List<NotebookCR> items;
-
- @SerializedName("kind")
- private String kind;
-
- @SerializedName("metadata")
- private V1ListMeta metadata;
+public class NotebookStatus {
- public String getApiVersion() {
- return apiVersion;
- }
+ @SerializedName("conditions")
+ private List<NotebookCondition> conditions;
- public void setApiVersion(String apiVersion) {
- this.apiVersion = apiVersion;
- }
+ @SerializedName("readyReplicas")
+ private int readyReplicas;
- public List<NotebookCR> getItems() {
- return items;
- }
-
- public void setItems(List<NotebookCR> items) {
- this.items = items;
- }
+ @SerializedName("containerState")
+ private V1ContainerState containerState;
- public String getKind() {
- return kind;
+ NotebookStatus() {
}
- public void setKing(String kind) {
- this.kind = kind;
+ public int getReadyReplicas() {
+ return readyReplicas;
}
- public V1ListMeta getMetadata() {
- return metadata;
+ public V1ContainerState getContainerState() {
+ return containerState;
}
- public void setMetadata(V1ListMeta metadata) {
- this.metadata = metadata;
+ public List<NotebookCondition> getConditions() {
+ return conditions;
}
}
diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java
new file mode 100644
index 0000000..cf33ff7
--- /dev/null
+++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java
@@ -0,0 +1,161 @@
+/*
+ * 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.submarine.server.submitter.k8s.util;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import io.kubernetes.client.JSON;
+import io.kubernetes.client.models.V1ContainerState;
+import io.kubernetes.client.models.V1Status;
+import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException;
+import org.apache.submarine.server.api.notebook.Notebook;
+import org.apache.submarine.server.submitter.k8s.model.NotebookCR;
+import org.apache.submarine.server.submitter.k8s.model.NotebookCRList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utils for building response of k8s (notebook) submitter
+ */
+public class NotebookUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NotebookUtils.class);
+
+ public enum ParseOpt {
+ PARSE_OPT_CREATE,
+ PARSE_OPT_GET,
+ PARSE_OPT_DELETE;
+ }
+
+ public static Notebook parseObject(Object obj, ParseOpt opt) throws SubmarineRuntimeException {
+ Gson gson = new JSON().getGson();
+ String jsonString = gson.toJson(obj);
+ LOG.info("Upstream response JSON: {}", jsonString);
+ try {
+ if (opt == ParseOpt.PARSE_OPT_DELETE) {
+ V1Status status = gson.fromJson(jsonString, V1Status.class);
+ return buildNotebookResponseFromStatus(status);
+ } else {
+ NotebookCR notebookCR = gson.fromJson(jsonString, NotebookCR.class);
+ return buildNotebookResponse(notebookCR);
+ }
+ } catch (JsonSyntaxException e) {
+ LOG.error("K8s submitter: parse response object failed by " + e.getMessage(), e);
+ }
+ throw new SubmarineRuntimeException(500, "K8s Submitter parse upstream response failed.");
+ }
+
+ public static List<Notebook> parseObjectForList(Object object) throws SubmarineRuntimeException {
+ Gson gson = new JSON().getGson();
+ String jsonString = gson.toJson(object);
+ LOG.info("Upstream response JSON: {}", jsonString);
+
+ try {
+ List<Notebook> notebookList = new ArrayList<>();
+ NotebookCRList notebookCRList = gson.fromJson(jsonString, NotebookCRList.class);
+ for (NotebookCR notebookCR : notebookCRList.getItems()) {
+ Notebook notebook = buildNotebookResponse(notebookCR);
+ notebookList.add(notebook);
+ }
+ return notebookList;
+ } catch (JsonSyntaxException e) {
+ LOG.error("K8s submitter: parse response object failed by " + e.getMessage(), e);
+ }
+ throw new SubmarineRuntimeException(500, "K8s Submitter parse upstream response failed.");
+ }
+
+ private static Notebook buildNotebookResponse(NotebookCR notebookCR) {
+ Notebook notebook = new Notebook();
+ notebook.setUid(notebookCR.getMetadata().getUid());
+ notebook.setName(notebookCR.getMetadata().getName());
+ notebook.setCreatedTime(notebookCR.getMetadata().getCreationTimestamp().toString());
+ // notebook url
+ notebook.setUrl("/notebook/" + notebookCR.getMetadata().getNamespace() + "/" +
+ notebookCR.getMetadata().getName() + "/");
+
+ // process status
+ Map<String, String> statusMap = processStatus(notebookCR);
+ notebook.setStatus(statusMap.get("status"));
+ notebook.setReason(statusMap.get("reason"));
+
+ if (notebookCR.getMetadata().getDeletionTimestamp() != null) {
+ notebook.setDeletedTime(notebookCR.getMetadata().getDeletionTimestamp().toString());
+ }
+ return notebook;
+ }
+
+ private static Map<String, String> processStatus(NotebookCR notebookCR) {
+ Map<String, String> statusMap = new HashMap<>();
+ // if the notebook instance is deleted
+ if (notebookCR.getMetadata().getDeletionTimestamp() != null) {
+ statusMap = createStatusMap(Notebook.Status.STATUS_TERMINATING.toString(),
+ "The notebook instance is terminating");
+ }
+
+ if (notebookCR.getStatus() == null) {
+ // if the notebook pod has not been created
+ statusMap = createStatusMap(Notebook.Status.STATUS_CREATING.toString(),
+ "The notebook instance is creating");
+ } else {
+ // if the notebook instance is ready(Running)
+ int replicas = notebookCR.getStatus().getReadyReplicas();
+ if (replicas == 1) {
+ statusMap = createStatusMap(Notebook.Status.STATUS_RUNNING.toString(),
+ "The notebook instance is running");
+ }
+
+ // if the notebook instance is waiting
+ V1ContainerState containerState = notebookCR.getStatus().getContainerState();
+ if (containerState.getWaiting() != null) {
+ statusMap = createStatusMap(Notebook.Status.STATUS_WAITING.toString(),
+ containerState.getWaiting().getReason());
+ }
+ }
+
+ return statusMap;
+ }
+
+ private static Map<String, String> createStatusMap(String status, String reason) {
+ Map<String, String> statusMap = new HashMap<>();
+ statusMap.put("status", status);
+ statusMap.put("reason", reason);
+ return statusMap;
+ }
+
+ private static Notebook buildNotebookResponseFromStatus(V1Status status) {
+ Notebook notebook = new Notebook();
+ if (status.getStatus().toLowerCase().equals("success")) {
+ notebook.setStatus(Notebook.Status.STATUS_TERMINATING.toString());
+ notebook.setReason("The notebook instance is terminating");
+ }
+
+ if (status.getDetails() != null) {
+ notebook.setUid(status.getDetails().getUid());
+ notebook.setName(status.getDetails().getName());
+ }
+ return notebook;
+ }
+}
diff --git a/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java b/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java
index 4351bac..d47adcf 100644
--- a/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java
+++ b/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java
@@ -37,7 +37,6 @@ import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.submarine.server.AbstractSubmarineServerTest;
import org.apache.submarine.server.api.environment.Environment;
import org.apache.submarine.server.api.environment.EnvironmentId;
-import org.apache.submarine.server.api.experiment.Experiment;
import org.apache.submarine.server.api.notebook.Notebook;
import org.apache.submarine.server.api.notebook.NotebookId;
import org.apache.submarine.server.gson.EnvironmentIdDeserializer;
@@ -263,7 +262,7 @@ public class NotebookRestApiIT extends AbstractSubmarineServerTest {
private void verifyCreateNotebookApiResult(Notebook createdNotebook) {
Assert.assertNotNull(createdNotebook.getUid());
Assert.assertNotNull(createdNotebook.getCreatedTime());
- Assert.assertEquals(Experiment.Status.STATUS_CREATED.getValue(), createdNotebook.getStatus());
+ Assert.assertEquals(Notebook.Status.STATUS_CREATING.toString(), createdNotebook.getStatus());
}
private void verifyGetNotebookApiResult(Notebook createdNotebook,
@@ -278,7 +277,7 @@ public class NotebookRestApiIT extends AbstractSubmarineServerTest {
private void verifyDeleteNotebookApiResult(Notebook createdNotebook,
Notebook deletedNotebook) {
Assert.assertEquals(createdNotebook.getName(), deletedNotebook.getName());
- Assert.assertEquals(Notebook.Status.STATUS_DELETED.getValue(), deletedNotebook.getStatus());
+ Assert.assertEquals(Notebook.Status.STATUS_TERMINATING.getValue(), deletedNotebook.getStatus());
assertDeleteK8sResult(deletedNotebook);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org