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]