This is an automated email from the ASF dual-hosted git repository.

pingsutw 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 72be805  SUBMARINE-851. Dirty notebook status is persisted in DB when 
notebook operation is failed
72be805 is described below

commit 72be805fc4672f7f29c96cca95e16d59358d4dd2
Author: Lisa <[email protected]>
AuthorDate: Thu Jul 15 11:11:42 2021 +0800

    SUBMARINE-851. Dirty notebook status is persisted in DB when notebook 
operation is failed
    
    ### What is this PR for?
    Maintain atomicity while creating notebook.
    
    ### What type of PR is it?
    [Bug Fix]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-851
    
    ### How should this be tested?
    Try to get error in notebook creation, and then create a new notebook with 
same name.
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Do the license files need updating? No
    * Are there breaking changes for older versions? No
    * Does this need new documentation? No
    
    Author: Lisa <[email protected]>
    
    Signed-off-by: Kevin <[email protected]>
    
    Closes #655 from aeioulisa/SUBMARINE-851 and squashes the following commits:
    
    6c3634a7 [Lisa] edit function name
    6c637a4f [Lisa] edit function name
    bf6285a4 [Lisa] edit log and try-block
    3916827e [Lisa] Let notebook creation maintain Atomicity
---
 .../server/submitter/k8s/K8sSubmitter.java         | 78 +++++++++++++++++-----
 1 file changed, 61 insertions(+), 17 deletions(-)

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 0e7accf..a530d16 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
@@ -88,7 +88,7 @@ public class K8sSubmitter implements Submitter {
 
   private static final String TF_JOB_SELECTOR_KEY = "tf-job-name=";
   private static final String PYTORCH_JOB_SELECTOR_KEY = "pytorch-job-name=";
-  
+
   private static final String ENV_NAMESPACE = "ENV_NAMESPACE";
 
   // K8s API client for CRD
@@ -361,32 +361,50 @@ public class K8sSubmitter implements Submitter {
     final String storage = NotebookUtils.STORAGE;
     final String pvcName = NotebookUtils.PVC_PREFIX + name;
     String namespace = "default";
-    
+    NotebookCR notebookCR;
+
     if (System.getenv(ENV_NAMESPACE) != null) {
       namespace = System.getenv(ENV_NAMESPACE);
     }
-    
+
     try {
       // create notebook custom resource
-      NotebookCR notebookCR = NotebookSpecParser.parseNotebook(spec);
+      notebookCR = NotebookSpecParser.parseNotebook(spec);
       Map<String, String> labels = new HashMap<>();
       labels.put(NotebookCR.NOTEBOOK_OWNER_SELECTOR_KET, 
spec.getMeta().getOwnerId());
       notebookCR.getMetadata().setLabels(labels);
       notebookCR.getMetadata().setNamespace(namespace);
-      
+
       // create persistent volume
       createPersistentVolume(pvName, host, storage);
+    } catch (ApiException e) {
+      LOG.error("K8s submitter: Create persistent volume for Notebook object 
failed by " + e.getMessage(), e);
+      throw new SubmarineRuntimeException(e.getCode(), "K8s submitter: Create 
persistent volume for " +
+          "Notebook object failed by " + e.getMessage());
+    } 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.");
+    }
 
-      // create persistent volume claim
+    // create persistent volume claim
+    try {
       createPersistentVolumeClaim(pvcName, namespace, pvName, storage);
+    } catch (ApiException e) {
+      LOG.error("K8s submitter: Create persistent volume claim for Notebook 
object failed by " +
+          e.getMessage(), e);
+      rollbackCreationPV(pvName);
+      throw new SubmarineRuntimeException(e.getCode(), "K8s submitter: Create 
persistent volume claim for " +
+          "Notebook object failed by " + e.getMessage());
+    }
 
-      // bind persistent volume claim
+    // bind persistent volume claim
+    try {
       V1PersistentVolumeClaimVolumeSource pvcSource = new 
V1PersistentVolumeClaimVolumeSource()
-              .claimName(pvcName);
+          .claimName(pvcName);
       
notebookCR.getSpec().getTemplate().getSpec().getVolumes().get(0).persistentVolumeClaim(pvcSource);
 
       Object object = api.createNamespacedCustomObject(notebookCR.getGroup(), 
notebookCR.getVersion(),
-              namespace, notebookCR.getPlural(), notebookCR, "true");
+          namespace, notebookCR.getPlural(), notebookCR, "true");
       notebook = NotebookUtils.parseObject(object, 
NotebookUtils.ParseOpt.PARSE_OPT_CREATE);
 
       // create Traefik custom resource
@@ -394,9 +412,11 @@ public class K8sSubmitter implements Submitter {
 
     } catch (JsonSyntaxException e) {
       LOG.error("K8s submitter: parse response object failed by " + 
e.getMessage(), e);
+      rollbackCreationPVC(pvName, pvcName, namespace);
       throw new SubmarineRuntimeException(500, "K8s Submitter parse upstream 
response failed.");
     } catch (ApiException e) {
       LOG.error("K8s submitter: parse Notebook object failed by " + 
e.getMessage(), e);
+      rollbackCreationPVC(pvName, pvcName, namespace);
       throw new SubmarineRuntimeException(e.getCode(), "K8s submitter: parse 
Notebook object failed by " +
           e.getMessage());
     }
@@ -407,12 +427,12 @@ public class K8sSubmitter implements Submitter {
   public Notebook findNotebook(NotebookSpec spec) throws 
SubmarineRuntimeException {
     Notebook notebook;
     String namespace = "default";
-    
+
     if (System.getenv(ENV_NAMESPACE) != null) {
       namespace = System.getenv(ENV_NAMESPACE);
     }
-    
-    try { 
+
+    try {
       NotebookCR notebookCR = NotebookSpecParser.parseNotebook(spec);
       Object object = api.getNamespacedCustomObject(notebookCR.getGroup(), 
notebookCR.getVersion(),
               namespace,
@@ -431,11 +451,11 @@ public class K8sSubmitter implements Submitter {
     final String pvName = NotebookUtils.PV_PREFIX + name;
     final String pvcName = NotebookUtils.PVC_PREFIX + name;
     String namespace = "default";
-    
+
     if (System.getenv(ENV_NAMESPACE) != null) {
       namespace = System.getenv(ENV_NAMESPACE);
     }
-    
+
     try {
       NotebookCR notebookCR = NotebookSpecParser.parseNotebook(spec);
       Object object = api.deleteNamespacedCustomObject(notebookCR.getGroup(), 
notebookCR.getVersion(),
@@ -469,7 +489,7 @@ public class K8sSubmitter implements Submitter {
   }
 
   @Override
-  public ServeResponse createServe(ServeRequest spec) 
+  public ServeResponse createServe(ServeRequest spec)
       throws SubmarineRuntimeException {
     String modelName = spec.getModelName();
     String modelVersion = spec.getModelVersion();
@@ -490,7 +510,7 @@ public class K8sSubmitter implements Submitter {
             middleware.getGroup(), middleware.getVersion(),
             middleware.getMetadata().getNamespace(),
             middleware.getPlural(), middleware, "true");
-            
+
       api.createNamespacedCustomObject(
             ingressRoute.getGroup(), ingressRoute.getVersion(),
             ingressRoute.getMetadata().getNamespace(),
@@ -502,7 +522,7 @@ public class K8sSubmitter implements Submitter {
   }
 
   @Override
-  public ServeResponse deleteServe(ServeRequest spec) 
+  public ServeResponse deleteServe(ServeRequest spec)
       throws SubmarineRuntimeException {
     String modelName = spec.getModelName();
     String modelVersion = spec.getModelVersion();
@@ -683,6 +703,30 @@ public class K8sSubmitter implements Submitter {
     return spec;
   }
 
+  private void rollbackCreationPV(String pvName) {
+    try {
+      deletePersistentVolume(pvName);
+    } catch (ApiException e) {
+      LOG.error("K8s submitter: delete persistent volume failed by {}, may 
cause some dirty data",
+          e.getMessage());
+    }
+  }
+
+  private void rollbackCreationPVC(String pvName, String pvcName, String 
namespace) {
+    try {
+      deletePersistentVolumeClaim(pvcName, namespace);
+    } catch (ApiException e) {
+      LOG.error("K8s submitter: delete persistent volume claim failed by {}, 
may cause some dirty data",
+          e.getMessage());
+    }
+    try {
+      deletePersistentVolume(pvName);
+    } catch (ApiException e) {
+      LOG.error("K8s submitter: delete persistent volume failed by {}, may 
cause some dirty data",
+          e.getMessage());
+    }
+  }
+
   private enum ParseOp {
     PARSE_OP_RESULT,
     PARSE_OP_DELETE

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to