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

ztang 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 3060ef7  SUBMARINE-570. Support run experiment/notebook with synced 
code
3060ef7 is described below

commit 3060ef754d26b7d1e514cd0e2836cf55ab5e8ab2
Author: Manikandan R <[email protected]>
AuthorDate: Thu Aug 13 20:52:06 2020 +0530

    SUBMARINE-570. Support run experiment/notebook with synced code
    
    ### What is this PR for?
    https://issues.apache.org/jira/browse/SUBMARINE-570
    
    ### What type of PR is it?
    Feature
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-570
    
    ### How should this be tested?
    * First time? Setup Travis CI as described on 
https://submarine.apache.org/contribution/contributions.html#continuous-integration
    * Strongly recommended: add automated unit tests for any new or changed 
behavior
    * Outline any manual steps to test the PR here.
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? Yes/No
    * Is there breaking changes for older versions? Yes/No
    * Does this needs documentation? Yes/No
    
    Author: Manikandan R <[email protected]>
    
    Closes #362 from manirajv06/SUBMARINE-570 and squashes the following 
commits:
    
    3e1c1b7 [Manikandan R] Set code directory as environment varibale of actual 
container
    9a6dd65 [Manikandan R] Fixed review comments
    b59109c [Manikandan R] Addressed review comments
    5d8595e [Manikandan R] Fixed review comments
    79de5dc [Manikandan R] Fixed license issue
    460d909 [Manikandan R] Fixed license issues
    89d1bfe [Manikandan R] Fixed checkstyle errors
    d6c4211 [Manikandan R] Implemented SUBMARINE-570 with unit test cases. 
Support run experiment/notebook with synced code Need to verify integration 
test cases.
---
 .../spec/{ExperimentSpec.java => CodeSpec.java}    |  44 +++-----
 .../submarine/server/api/spec/ExperimentSpec.java  |   9 ++
 .../codelocalizer/AbstractCodeLocalizer.java       |  78 ++++++++++++++
 .../experiment/codelocalizer/CodeLocalizer.java}   |  42 ++------
 .../codelocalizer/DummyCodeLocalizer.java}         |  41 ++-----
 .../experiment/codelocalizer/GitCodeLocalizer.java | 119 +++++++++++++++++++++
 .../codelocalizer/HTTPGitCodeLocalizer.java}       |  42 ++------
 .../codelocalizer/SSHGitCodeLocalizer.java}        |  40 ++-----
 .../submitter/k8s/parser/ExperimentSpecParser.java |  41 ++++++-
 .../submitter/k8s/ExperimentSpecParserTest.java    |  50 +++++++++
 .../server/submitter/k8s/SpecBuilder.java          |   2 +
 .../pytorch_job_req_http_git_code_localizer.json   |  30 ++++++
 .../apache/submarine/rest/ExperimentRestApiIT.java |   7 ++
 .../tf-mnist-with-http-git-code-localizer-req.json |  28 +++++
 14 files changed, 408 insertions(+), 165 deletions(-)

diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/CodeSpec.java
similarity index 54%
copy from 
submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
copy to 
submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/CodeSpec.java
index 88acaa2..71585e1 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/CodeSpec.java
@@ -19,41 +19,25 @@
 
 package org.apache.submarine.server.api.spec;
 
-import java.util.Map;
-
-/**
- * Specification of the desired behavior of an experiment.
- */
-public class ExperimentSpec {
-  private ExperimentMeta meta;
-  private EnvironmentSpec environment;
-  private Map<String, ExperimentTaskSpec> spec;
-
-  public ExperimentSpec() {
-
-  }
-
-  public ExperimentMeta getMeta() {
-    return meta;
-  }
-
-  public void setMeta(ExperimentMeta meta) {
-    this.meta = meta;
-  }
-
-  public EnvironmentSpec getEnvironment() {
-    return environment;
+public class CodeSpec {
+  
+  private String syncMode;
+  
+  private String url;
+  
+  public String getSyncMode() {
+    return syncMode;
   }
 
-  public void setEnvironment(EnvironmentSpec environmentSpec) {
-    this.environment = environmentSpec;
+  public void setSyncMode(String syncMode) {
+    this.syncMode = syncMode;
   }
 
-  public Map<String, ExperimentTaskSpec> getSpec() {
-    return spec;
+  public String getUrl() {
+    return url;
   }
 
-  public void setSpec(Map<String, ExperimentTaskSpec> spec) {
-    this.spec = spec;
+  public void setUrl(String url) {
+    this.url = url;
   }
 }
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
index 88acaa2..2a43f28 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
@@ -28,6 +28,7 @@ public class ExperimentSpec {
   private ExperimentMeta meta;
   private EnvironmentSpec environment;
   private Map<String, ExperimentTaskSpec> spec;
+  private CodeSpec code;
 
   public ExperimentSpec() {
 
@@ -56,4 +57,12 @@ public class ExperimentSpec {
   public void setSpec(Map<String, ExperimentTaskSpec> spec) {
     this.spec = spec;
   }
+  
+  public CodeSpec getCode() {
+    return code;
+  }
+
+  public void setCode(CodeSpec code) {
+    this.code = code;
+  }
 }
diff --git 
a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/AbstractCodeLocalizer.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/AbstractCodeLocalizer.java
new file mode 100644
index 0000000..46b359b
--- /dev/null
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/AbstractCodeLocalizer.java
@@ -0,0 +1,78 @@
+/*
+ * 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.experiment.codelocalizer;
+
+import org.apache.submarine.server.api.exception.InvalidSpecException;
+
+import io.kubernetes.client.models.V1EmptyDirVolumeSource;
+import io.kubernetes.client.models.V1PodSpec;
+import io.kubernetes.client.models.V1Volume;
+
+public abstract class AbstractCodeLocalizer implements CodeLocalizer {
+
+  public static final String CODE_LOCALIZER_PATH = "/code";
+  public static final String CODE_LOCALIZER_MOUNT_NAME = "code-dir";
+  public static final String CODE_LOCALIZER_INIT_CONTAINER_NAME = 
"code-localizer";
+  public static final String CODE_LOCALIZER_PATH_ENV_VAR = "CODE_PATH";
+  private String url;
+  
+  public AbstractCodeLocalizer(String url) {
+    this.url = url;
+  }
+  
+  /**
+   * @return the url
+   */
+  public String getUrl() {
+    return url;
+  }
+  
+  @Override
+  public void localize(V1PodSpec podSpec) {
+    V1Volume volume = new V1Volume();
+    volume.setName(CODE_LOCALIZER_MOUNT_NAME);
+    volume.setEmptyDir(new V1EmptyDirVolumeSource());
+    podSpec.addVolumesItem(volume);
+  }
+
+  public static CodeLocalizer getCodeLocalizer(String syncMode, String url)
+      throws InvalidSpecException {
+    if (syncMode.equals(CodeLocalizerModes.GIT.getMode())) {
+      return GitCodeLocalizer.getGitCodeLocalizer(url);
+    } else {
+      return new DummyCodeLocalizer(url);
+    }
+  }
+
+  public enum CodeLocalizerModes {
+
+    GIT("git"), HDFS("hdfs"), NFS("nfs"), S3("s3");
+
+    private final String mode;
+
+    CodeLocalizerModes(String mode) {
+      this.mode = mode;
+    }
+
+    public String getMode() {
+      return this.mode;
+    }
+  }
+}
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java
similarity index 50%
copy from 
submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
copy to 
submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java
index 88acaa2..2e3e7c1 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java
@@ -17,43 +17,15 @@
  * under the License.
  */
 
-package org.apache.submarine.server.api.spec;
+package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer;
 
-import java.util.Map;
+import io.kubernetes.client.models.V1PodSpec;
 
-/**
- * Specification of the desired behavior of an experiment.
- */
-public class ExperimentSpec {
-  private ExperimentMeta meta;
-  private EnvironmentSpec environment;
-  private Map<String, ExperimentTaskSpec> spec;
-
-  public ExperimentSpec() {
-
-  }
-
-  public ExperimentMeta getMeta() {
-    return meta;
-  }
-
-  public void setMeta(ExperimentMeta meta) {
-    this.meta = meta;
-  }
-
-  public EnvironmentSpec getEnvironment() {
-    return environment;
-  }
-
-  public void setEnvironment(EnvironmentSpec environmentSpec) {
-    this.environment = environmentSpec;
-  }
+public interface CodeLocalizer {
 
-  public Map<String, ExperimentTaskSpec> getSpec() {
-    return spec;
-  }
+  /**
+   * Create K8's Init container to sync the code
+   */
+  void localize(V1PodSpec podSpec);
 
-  public void setSpec(Map<String, ExperimentTaskSpec> spec) {
-    this.spec = spec;
-  }
 }
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java
similarity index 51%
copy from 
submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
copy to 
submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java
index 88acaa2..daf682f 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java
@@ -17,43 +17,18 @@
  * under the License.
  */
 
-package org.apache.submarine.server.api.spec;
+package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer;
 
-import java.util.Map;
+import io.kubernetes.client.models.V1PodSpec;
 
-/**
- * Specification of the desired behavior of an experiment.
- */
-public class ExperimentSpec {
-  private ExperimentMeta meta;
-  private EnvironmentSpec environment;
-  private Map<String, ExperimentTaskSpec> spec;
-
-  public ExperimentSpec() {
-
-  }
-
-  public ExperimentMeta getMeta() {
-    return meta;
-  }
-
-  public void setMeta(ExperimentMeta meta) {
-    this.meta = meta;
-  }
-
-  public EnvironmentSpec getEnvironment() {
-    return environment;
-  }
-
-  public void setEnvironment(EnvironmentSpec environmentSpec) {
-    this.environment = environmentSpec;
-  }
+public class DummyCodeLocalizer extends AbstractCodeLocalizer {
 
-  public Map<String, ExperimentTaskSpec> getSpec() {
-    return spec;
+  public DummyCodeLocalizer(String url) {
+    super(url);
   }
 
-  public void setSpec(Map<String, ExperimentTaskSpec> spec) {
-    this.spec = spec;
+  @Override
+  public void localize(V1PodSpec podSpec) {
+    // Noop
   }
 }
diff --git 
a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/GitCodeLocalizer.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/GitCodeLocalizer.java
new file mode 100644
index 0000000..ddb3c78
--- /dev/null
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/GitCodeLocalizer.java
@@ -0,0 +1,119 @@
+/*
+ * 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.experiment.codelocalizer;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.submarine.server.api.exception.InvalidSpecException;
+
+import io.kubernetes.client.models.V1Container;
+import io.kubernetes.client.models.V1EnvVar;
+import io.kubernetes.client.models.V1PodSpec;
+import io.kubernetes.client.models.V1VolumeMount;
+
+public abstract class GitCodeLocalizer extends AbstractCodeLocalizer {
+
+  public static final String GIT_SYNC_IMAGE = "k8s.gcr.io/git-sync:v3.1.6";
+  
+  public GitCodeLocalizer(String url) {
+    super(url);
+  }
+
+  public void localize(V1PodSpec podSpec) {
+    
+    V1Container container = new V1Container();
+    container.setName(CODE_LOCALIZER_INIT_CONTAINER_NAME);
+    container.setImage(GIT_SYNC_IMAGE);
+    
+    V1EnvVar repoEnv = new V1EnvVar();
+    repoEnv.setName("GIT_SYNC_REPO");
+    repoEnv.setValue(this.getUrl());
+    
+    V1EnvVar rootEnv = new V1EnvVar();
+    rootEnv.setName("GIT_SYNC_ROOT");
+    rootEnv.setValue(CODE_LOCALIZER_PATH);
+    
+    V1EnvVar destEnv = new V1EnvVar();
+    destEnv.setName("GIT_SYNC_DEST");
+    destEnv.setValue("current");
+    
+    V1EnvVar oneTimeEnv = new V1EnvVar();
+    oneTimeEnv.setName("GIT_SYNC_ONE_TIME");
+    oneTimeEnv.setValue("true");
+    
+    List<V1EnvVar> gitSyncEnvVars = new ArrayList<V1EnvVar>();
+    gitSyncEnvVars.add(repoEnv);
+    gitSyncEnvVars.add(rootEnv);
+    gitSyncEnvVars.add(destEnv);
+    gitSyncEnvVars.add(oneTimeEnv);
+    container.setEnv(gitSyncEnvVars);
+    
+    V1VolumeMount mount = new V1VolumeMount();
+    mount.setName(CODE_LOCALIZER_MOUNT_NAME);
+    mount.setMountPath(CODE_LOCALIZER_PATH);
+    
+    List<V1VolumeMount> volumeMounts = new ArrayList<V1VolumeMount>();
+    volumeMounts.add(mount);
+    
+    container.setVolumeMounts(volumeMounts);
+    
+    podSpec.addInitContainersItem(container);
+    
+    super.localize(podSpec);
+  }
+  
+  public static CodeLocalizer getGitCodeLocalizer(String url)
+      throws InvalidSpecException {
+
+    try {
+      URL urlParser = new URL(url);
+      String protocol = urlParser.getProtocol();
+      if (protocol.equals(GitCodeLocalizerModes.HTTP.getMode())) {
+        return new HTTPGitCodeLocalizer(url);
+      } else if (protocol.equals(GitCodeLocalizerModes.SSH.getMode())) {
+        return new SSHGitCodeLocalizer(url);
+      } else {
+        return new DummyCodeLocalizer(url);
+      }
+    } catch (MalformedURLException e) {
+      throw new InvalidSpecException(
+          "Invalid Code Spec: URL is malformed. " + url);
+    }
+  }
+
+  public enum GitCodeLocalizerModes {
+
+    HTTP("https"), SSH("ssh");
+
+    private final String mode;
+
+    GitCodeLocalizerModes(String mode) {
+      this.mode = mode;
+    }
+
+    public String getMode() {
+      return this.mode;
+    }
+  };
+
+}
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java
similarity index 51%
copy from 
submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
copy to 
submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java
index 88acaa2..edb475b 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java
@@ -17,43 +17,19 @@
  * under the License.
  */
 
-package org.apache.submarine.server.api.spec;
+package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer;
 
-import java.util.Map;
+import io.kubernetes.client.models.V1PodSpec;
 
-/**
- * Specification of the desired behavior of an experiment.
- */
-public class ExperimentSpec {
-  private ExperimentMeta meta;
-  private EnvironmentSpec environment;
-  private Map<String, ExperimentTaskSpec> spec;
-
-  public ExperimentSpec() {
-
-  }
-
-  public ExperimentMeta getMeta() {
-    return meta;
-  }
+public class HTTPGitCodeLocalizer extends GitCodeLocalizer {
 
-  public void setMeta(ExperimentMeta meta) {
-    this.meta = meta;
+  public HTTPGitCodeLocalizer(String url) {
+    super(url);
   }
-
-  public EnvironmentSpec getEnvironment() {
-    return environment;
-  }
-
-  public void setEnvironment(EnvironmentSpec environmentSpec) {
-    this.environment = environmentSpec;
+  
+  @Override
+  public void localize(V1PodSpec podSpec) {
+    super.localize(podSpec);
   }
 
-  public Map<String, ExperimentTaskSpec> getSpec() {
-    return spec;
-  }
-
-  public void setSpec(Map<String, ExperimentTaskSpec> spec) {
-    this.spec = spec;
-  }
 }
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java
similarity index 51%
copy from 
submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
copy to 
submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java
index 88acaa2..1a8de83 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/ExperimentSpec.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java
@@ -17,43 +17,19 @@
  * under the License.
  */
 
-package org.apache.submarine.server.api.spec;
+package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer;
 
-import java.util.Map;
+import io.kubernetes.client.models.V1PodSpec;
 
-/**
- * Specification of the desired behavior of an experiment.
- */
-public class ExperimentSpec {
-  private ExperimentMeta meta;
-  private EnvironmentSpec environment;
-  private Map<String, ExperimentTaskSpec> spec;
-
-  public ExperimentSpec() {
-
-  }
-
-  public ExperimentMeta getMeta() {
-    return meta;
-  }
+public class SSHGitCodeLocalizer extends GitCodeLocalizer {
 
-  public void setMeta(ExperimentMeta meta) {
-    this.meta = meta;
+  public SSHGitCodeLocalizer(String url) {
+    super(url);
   }
 
-  public EnvironmentSpec getEnvironment() {
-    return environment;
+  @Override
+  public void localize(V1PodSpec podSpec) {
+    // Code SSH based logic here
   }
 
-  public void setEnvironment(EnvironmentSpec environmentSpec) {
-    this.environment = environmentSpec;
-  }
-
-  public Map<String, ExperimentTaskSpec> getSpec() {
-    return spec;
-  }
-
-  public void setSpec(Map<String, ExperimentTaskSpec> spec) {
-    this.spec = spec;
-  }
 }
diff --git 
a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ExperimentSpecParser.java
 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ExperimentSpecParser.java
index ee745a9..eb19e04 100644
--- 
a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ExperimentSpecParser.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ExperimentSpecParser.java
@@ -26,6 +26,7 @@ import io.kubernetes.client.models.V1ObjectMeta;
 import io.kubernetes.client.models.V1PodSpec;
 import io.kubernetes.client.models.V1PodTemplateSpec;
 import io.kubernetes.client.models.V1ResourceRequirements;
+import io.kubernetes.client.models.V1VolumeMount;
 
 import org.apache.submarine.commons.utils.SubmarineConfVars;
 import org.apache.submarine.commons.utils.SubmarineConfiguration;
@@ -36,6 +37,8 @@ import org.apache.submarine.server.api.spec.ExperimentSpec;
 import org.apache.submarine.server.api.spec.ExperimentTaskSpec;
 import org.apache.submarine.server.api.spec.EnvironmentSpec;
 import org.apache.submarine.server.environment.EnvironmentManager;
+import 
org.apache.submarine.server.submitter.k8s.experiment.codelocalizer.AbstractCodeLocalizer;
+import 
org.apache.submarine.server.submitter.k8s.experiment.codelocalizer.CodeLocalizer;
 import org.apache.submarine.server.submitter.k8s.model.MLJob;
 import org.apache.submarine.server.submitter.k8s.model.MLJobReplicaSpec;
 import org.apache.submarine.server.submitter.k8s.model.MLJobReplicaType;
@@ -142,7 +145,7 @@ public class ExperimentSpecParser {
   }
 
   private static V1PodTemplateSpec parseTemplateSpec(
-      ExperimentTaskSpec taskSpec, ExperimentSpec experimentSpec) {
+      ExperimentTaskSpec taskSpec, ExperimentSpec experimentSpec) throws 
InvalidSpecException {
     V1PodTemplateSpec templateSpec = new V1PodTemplateSpec();
     V1PodSpec podSpec = new V1PodSpec();
     List<V1Container> containers = new ArrayList<>();
@@ -167,9 +170,43 @@ public class ExperimentSpecParser {
     resources.setLimits(parseResources(taskSpec));
     container.setResources(resources);
     container.setEnv(parseEnvVars(taskSpec, 
experimentSpec.getMeta().getEnvVars()));
+    
+    /**
+     * Init Git localize Container
+     */
+    if (experimentSpec.getCode() != null) {
+      CodeLocalizer localizer = AbstractCodeLocalizer.getCodeLocalizer(
+          experimentSpec.getCode().getSyncMode(),
+          experimentSpec.getCode().getUrl());
+      localizer.localize(podSpec);
+
+      if (podSpec.getInitContainers() != null
+          && podSpec.getInitContainers().size() > 0) {
+        String volumeName = 
podSpec.getInitContainers().get(0).getVolumeMounts()
+            .get(0).getName();
+        String path = podSpec.getInitContainers().get(0).getVolumeMounts()
+            .get(0).getMountPath();
+
+        V1VolumeMount mount = new V1VolumeMount();
+        mount.setName(volumeName);
+        mount.setMountPath(path);
+
+        List<V1VolumeMount> volumeMounts = new ArrayList<V1VolumeMount>();
+        volumeMounts.add(mount);
+        container.setVolumeMounts(volumeMounts);
+        
+        V1EnvVar codeEnvVar = new V1EnvVar();
+        codeEnvVar.setName(AbstractCodeLocalizer.CODE_LOCALIZER_PATH_ENV_VAR);
+        codeEnvVar.setValue(AbstractCodeLocalizer.CODE_LOCALIZER_PATH);
+        List<V1EnvVar> envVars = container.getEnv();
+        envVars.add(codeEnvVar);
+        container.setEnv(envVars);
+      }
+    }
+
     containers.add(container);
     podSpec.setContainers(containers);
-
+      
     /**
      * Init Containers
      */
diff --git 
a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/ExperimentSpecParserTest.java
 
b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/ExperimentSpecParserTest.java
index c44bec9..18347dd 100644
--- 
a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/ExperimentSpecParserTest.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/ExperimentSpecParserTest.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import io.kubernetes.client.models.V1ObjectMeta;
+import io.kubernetes.client.models.V1Volume;
 
 import org.apache.submarine.commons.utils.SubmarineConfVars;
 import org.apache.submarine.commons.utils.SubmarineConfiguration;
@@ -43,9 +44,13 @@ import 
org.apache.submarine.server.submitter.k8s.model.pytorchjob.PyTorchJobRepl
 import org.apache.submarine.server.submitter.k8s.model.tfjob.TFJob;
 import org.apache.submarine.server.submitter.k8s.model.tfjob.TFJobReplicaType;
 import org.apache.submarine.server.submitter.k8s.parser.ExperimentSpecParser;
+import 
org.apache.submarine.server.submitter.k8s.experiment.codelocalizer.AbstractCodeLocalizer;
+import 
org.apache.submarine.server.submitter.k8s.experiment.codelocalizer.GitCodeLocalizer;
 import org.junit.Assert;
 import org.junit.Test;
 import io.kubernetes.client.models.V1Container;
+import io.kubernetes.client.models.V1EmptyDirVolumeSource;
+import io.kubernetes.client.models.V1EnvVar;
 
 
 public class ExperimentSpecParserTest extends SpecBuilder {
@@ -260,4 +265,49 @@ public class ExperimentSpecParserTest extends SpecBuilder {
 
     environmentManager.deleteEnvironment(envName);
   }
+  
+  @Test
+  public void testValidPyTorchJobSpecWithHTTPGitCodeLocalizer()
+      throws IOException, URISyntaxException, InvalidSpecException {
+    ExperimentSpec jobSpec =
+        (ExperimentSpec) buildFromJsonFile(ExperimentSpec.class,
+            pytorchJobWithHTTPGitCodeLocalizerFile);
+    PyTorchJob pyTorchJob = (PyTorchJob) 
ExperimentSpecParser.parseJob(jobSpec);
+
+    MLJobReplicaSpec mlJobReplicaSpec = pyTorchJob.getSpec().getReplicaSpecs()
+        .get(PyTorchJobReplicaType.Master);
+    Assert.assertEquals(1,
+        mlJobReplicaSpec.getTemplate().getSpec().getInitContainers().size());
+    V1Container initContainer =
+        mlJobReplicaSpec.getTemplate().getSpec().getInitContainers().get(0);
+    Assert.assertEquals(
+        AbstractCodeLocalizer.CODE_LOCALIZER_INIT_CONTAINER_NAME,
+        initContainer.getName());
+    Assert.assertEquals(GitCodeLocalizer.GIT_SYNC_IMAGE,
+        initContainer.getImage());
+    Assert.assertEquals(AbstractCodeLocalizer.CODE_LOCALIZER_MOUNT_NAME,
+        initContainer.getVolumeMounts().get(0).getName());
+    Assert.assertEquals(AbstractCodeLocalizer.CODE_LOCALIZER_PATH,
+        initContainer.getVolumeMounts().get(0).getMountPath());
+
+    V1Container container =
+        mlJobReplicaSpec.getTemplate().getSpec().getContainers().get(0);
+    Assert.assertEquals(AbstractCodeLocalizer.CODE_LOCALIZER_MOUNT_NAME,
+        container.getVolumeMounts().get(0).getName());
+    Assert.assertEquals(AbstractCodeLocalizer.CODE_LOCALIZER_PATH,
+        container.getVolumeMounts().get(0).getMountPath());
+    for (V1EnvVar env : container.getEnv()) {
+      if (env.getName()
+          .equals(AbstractCodeLocalizer.CODE_LOCALIZER_PATH_ENV_VAR)) {
+        Assert.assertEquals(AbstractCodeLocalizer.CODE_LOCALIZER_PATH,
+            env.getValue());
+      }
+    }
+
+    V1Volume V1Volume =
+        mlJobReplicaSpec.getTemplate().getSpec().getVolumes().get(0);
+    Assert.assertEquals(new V1EmptyDirVolumeSource(), V1Volume.getEmptyDir());
+    Assert.assertEquals(AbstractCodeLocalizer.CODE_LOCALIZER_MOUNT_NAME,
+        V1Volume.getName());
+  }
 }
diff --git 
a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/SpecBuilder.java
 
b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/SpecBuilder.java
index 11546ab..0584276 100644
--- 
a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/SpecBuilder.java
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/SpecBuilder.java
@@ -40,6 +40,8 @@ public abstract class SpecBuilder {
   protected final String pytorchJobWithInvalidEnvReqFile =
       "/pytorch_job_req_invalid_env.json";
   protected final String notebookReqFile = "/notebook_req.json";
+  protected final String pytorchJobWithHTTPGitCodeLocalizerFile =
+      "/pytorch_job_req_http_git_code_localizer.json";
 
   protected Object buildFromJsonFile(Object obj, String filePath) throws 
IOException,
       URISyntaxException {
diff --git 
a/submarine-server/server-submitter/submitter-k8s/src/test/resources/pytorch_job_req_http_git_code_localizer.json
 
b/submarine-server/server-submitter/submitter-k8s/src/test/resources/pytorch_job_req_http_git_code_localizer.json
new file mode 100644
index 0000000..408fea0
--- /dev/null
+++ 
b/submarine-server/server-submitter/submitter-k8s/src/test/resources/pytorch_job_req_http_git_code_localizer.json
@@ -0,0 +1,30 @@
+{
+  "meta": {
+    "name": "pytorch-dist-mnist",
+    "namespace": "submarine",
+    "framework": "PyTorch",
+    "cmd": "python /var/mnist.py --backend gloo",
+    "envVars": {
+      "ENV_1": "ENV1"
+    }
+  },
+  "environment": {
+    "image": "apache/submarine:pytorch-dist-mnist-1.0"
+  },
+  "spec": {
+    "Master": {
+      "name": "master",
+      "replicas": 1,
+      "resources": "cpu=2,memory=2048M"
+    },
+    "Worker": {
+      "name": "worker",
+      "replicas": 2,
+      "resources": "cpu=1,memory=1024M"
+    }
+  },
+  "code": {
+    "syncMode": "git",
+    "url" : "https://github.com/apache/submarine.git";
+  }
+}
diff --git 
a/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/ExperimentRestApiIT.java
 
b/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/ExperimentRestApiIT.java
index 3738ebd..ebc108e 100644
--- 
a/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/ExperimentRestApiIT.java
+++ 
b/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/ExperimentRestApiIT.java
@@ -163,6 +163,13 @@ public class ExperimentRestApiIT extends 
AbstractSubmarineServerTest {
     String patchBody = loadContent("pytorch/pt-mnist-patch-req.yaml");
     run(body, patchBody, "application/yaml");
   }
+  
+  @Test
+  public void testTensorFlowUsingCodeWithJsonSpec() throws Exception {
+    String body = 
loadContent("tensorflow/tf-mnist-with-http-git-code-localizer-req.json");
+    String patchBody = 
loadContent("tensorflow/tf-mnist-with-http-git-code-localizer-req.json");
+    run(body, patchBody, "application/json");
+  }
 
   private void run(String body, String patchBody, String contentType) throws 
Exception {
     // create
diff --git 
a/submarine-test/test-k8s/src/test/resources/tensorflow/tf-mnist-with-http-git-code-localizer-req.json
 
b/submarine-test/test-k8s/src/test/resources/tensorflow/tf-mnist-with-http-git-code-localizer-req.json
new file mode 100644
index 0000000..0ee5c6b
--- /dev/null
+++ 
b/submarine-test/test-k8s/src/test/resources/tensorflow/tf-mnist-with-http-git-code-localizer-req.json
@@ -0,0 +1,28 @@
+{
+  "meta": {
+    "name": "tf-mnist-json",
+    "namespace": "default",
+    "framework": "TensorFlow",
+    "cmd": "python /var/tf_mnist/mnist_with_summaries.py --log_dir=/train/log 
--learning_rate=0.01 --batch_size=150",
+    "envVars": {
+      "ENV_1": "ENV1"
+    }
+  },
+  "environment": {
+       "image": "gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0"
+  },
+  "spec": {
+    "Ps": {
+      "replicas": 1,
+      "resources": "cpu=1,memory=512M"
+    },
+    "Worker": {
+      "replicas": 1,
+      "resources": "cpu=1,memory=512M"
+    }
+  },
+  "code": {
+    "syncMode": "git",
+    "url" : "https://github.com/apache/submarine.git";
+  }
+}


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

Reply via email to