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

zhouquan 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 6f0b152  SUBMARINE-326. Hook REST and JobManager to accept TFJob
6f0b152 is described below

commit 6f0b152f3fb4d17f751be1e8b6ecd625a3e27203
Author: Wanqiang Ji <[email protected]>
AuthorDate: Wed Jan 1 12:33:16 2020 +0800

    SUBMARINE-326. Hook REST and JobManager to accept TFJob
    
    ### What is this PR for?
    Implements submit the TF job to K8s cluster by REST
    
    ### What type of PR is it?
    Feature
    
    ### Todos
    Implements the job RUD operates when 0.4.0 released
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-326
    
    ### How should this be tested?
    unit test
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Wanqiang Ji <[email protected]>
    
    Closes #138 from jiwq/SUBMARINE-326 and squashes the following commits:
    
    c99ac2d [Wanqiang Ji] SUBMARINE-326. Hook REST and JobManager to accept 
TFJob
---
 .../commons/utils/SubmarineConfiguration.java      |   7 +-
 submarine-server/server-api/pom.xml                |   2 +-
 .../org/apache/submarine/server/api/job/JobId.java |  18 +++
 .../submarine/server/api/spec/JobLibrarySpec.java  |   4 +
 .../apache/submarine/server/api/spec/JobSpec.java  |   6 +
 .../server/api/spec/JobSubmitterSpec.java          |   4 +
 .../submarine/server/api/spec/JobTaskSpec.java     |   7 +-
 .../org/apache/submarine/server/JobManager.java    |  12 +-
 .../server/jobserver/rest/JobServerRestApi.java    |  93 ----------------
 .../submarine/server/json/JobIdDeserializer.java   |  37 +++++++
 .../submarine/server/json/JobIdSerializer.java     |  35 ++++++
 .../submarine/server/response/JsonResponse.java    |   8 +-
 .../submarine/server/rest/JobManagerRestApi.java   | 121 +++++++++++++++++++++
 .../provider/YamlEntityProvider.java               |   2 +-
 .../JobManagerRestApiTest.java}                    |  46 +++++---
 .../src/test/resources/tf-mnist-req.json           |  31 ++++++
 .../src/test/resources/tf-mnist-req.yaml           |  23 ++++
 17 files changed, 336 insertions(+), 120 deletions(-)

diff --git 
a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfiguration.java
 
b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfiguration.java
index 5d6b4c2..396f088 100644
--- 
a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfiguration.java
+++ 
b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfiguration.java
@@ -320,7 +320,7 @@ public class SubmarineConfiguration extends 
XMLConfiguration {
   public List<String> listSubmitter() {
     List<String> values = new ArrayList<>();
 
-    String submitters = getString(ConfVars.SUBMARINE_SUBMITTERS.getVarName());
+    String submitters = getString(ConfVars.SUBMARINE_SUBMITTERS);
     if (submitters != null) {
       final String delim = ",";
       StringTokenizer tokenizer = new StringTokenizer(submitters, delim);
@@ -338,7 +338,7 @@ public class SubmarineConfiguration extends 
XMLConfiguration {
    * @return class name
    */
   public String getSubmitterEntry(String name) {
-    return 
getString(String.format(ConfVars.SUBMARINE_SUBMITTERS_ENTRY.getVarName(), 
name));
+    return 
getStringValue(String.format(ConfVars.SUBMARINE_SUBMITTERS_ENTRY.getVarName(), 
name), "");
   }
 
   /**
@@ -347,7 +347,8 @@ public class SubmarineConfiguration extends 
XMLConfiguration {
    * @return classpath
    */
   public String getSubmitterClassPath(String name) {
-    return 
getString(String.format(ConfVars.SUBMARINE_SUBMITTERS_CLASSPATH.getVarName(), 
name));
+    return 
getStringValue(String.format(ConfVars.SUBMARINE_SUBMITTERS_CLASSPATH.getVarName(),
+        name), "");
   }
 
   private String getStringValue(String name, String d) {
diff --git a/submarine-server/server-api/pom.xml 
b/submarine-server/server-api/pom.xml
index 84adc7f..a786965 100644
--- a/submarine-server/server-api/pom.xml
+++ b/submarine-server/server-api/pom.xml
@@ -31,4 +31,4 @@
   <artifactId>server-api</artifactId>
   <name>Submarine: Server API</name>
 
-</project>
\ No newline at end of file
+</project>
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/job/JobId.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/job/JobId.java
index bb0a4b6..7026ed0 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/job/JobId.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/job/JobId.java
@@ -29,9 +29,26 @@ public class JobId implements Comparable<JobId> {
   private static final int JOB_ID_MIN_DIGITS = 4;
 
   private int id;
+
   private long serverTimestamp;
 
   /**
+   * Get the object of JobId.
+   * @param jobId job id string
+   * @return object
+   */
+  public static JobId fromString(String jobId) {
+    if (jobId == null) {
+      return null;
+    }
+    String[] components = jobId.split("\\_");
+    if (components.length != 3) {
+      return null;
+    }
+    return JobId.newInstance(Long.parseLong(components[1]), 
Integer.parseInt(components[2]));
+  }
+
+  /**
    * Ge the object of JobId.
    * @param serverTimestamp the timestamp when the server start
    * @param id count
@@ -39,6 +56,7 @@ public class JobId implements Comparable<JobId> {
    */
   public static JobId newInstance(long serverTimestamp, int id) {
     JobId jobId = new JobId();
+    jobId.setServerTimestamp(serverTimestamp);
     jobId.setId(id);
     return jobId;
   }
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobLibrarySpec.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobLibrarySpec.java
index 236c138..96dcdae 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobLibrarySpec.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobLibrarySpec.java
@@ -116,4 +116,8 @@ public class JobLibrarySpec {
   public void setEnvVars(Map<String, String> envVars) {
     this.envVars = envVars;
   }
+
+  public boolean validate() {
+    return name != null && image != null && cmd != null;
+  }
 }
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSpec.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSpec.java
index bb88004..f792825 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSpec.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSpec.java
@@ -101,6 +101,12 @@ public class JobSpec {
     this.taskSpecs = taskSpecs;
   }
 
+  public boolean validate() {
+    return librarySpec != null && librarySpec.validate()
+        && submitterSpec != null && submitterSpec.validate()
+        && taskSpecs != null;
+  }
+
   /**
    * This could be file/directory which contains multiple python scripts.
    * We should solve dependencies distribution in k8s or yarn.
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSubmitterSpec.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSubmitterSpec.java
index d012a26..5dd7066 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSubmitterSpec.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobSubmitterSpec.java
@@ -111,4 +111,8 @@ public class JobSubmitterSpec {
   public void setApiVersion(String apiVersion) {
     this.apiVersion = apiVersion;
   }
+
+  public boolean validate() {
+    return type != null && namespace != null;
+  }
 }
diff --git 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobTaskSpec.java
 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobTaskSpec.java
index 586f3ee..f2964c0 100644
--- 
a/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobTaskSpec.java
+++ 
b/submarine-server/server-api/src/main/java/org/apache/submarine/server/api/spec/JobTaskSpec.java
@@ -27,7 +27,7 @@ import java.util.Map;
  */
 public class JobTaskSpec {
   /**
-   * The job task name, the range is [Chief, Ps, Worker, Evaluator, Master]
+   * The job task name, if not specify using the library name
    */
   private String name;
 
@@ -72,7 +72,7 @@ public class JobTaskSpec {
   }
 
   /**
-   * Get the task name which range is [Chief, Ps, Worker, Evaluator, Master]
+   * Get the task name, if not specify using the library name
    * @return task name
    */
   public String getName() {
@@ -81,7 +81,7 @@ public class JobTaskSpec {
 
   /**
    * Set the task name
-   * @param name task name which range is [Chief, Ps, Worker, Evaluator, 
Master]
+   * @param name task name
    */
   public void setName(String name) {
     this.name = name;
@@ -216,4 +216,5 @@ public class JobTaskSpec {
   public String getGpu() {
     return resourceMap.get("nvidia.com/gpu");
   }
+
 }
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/JobManager.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/JobManager.java
index 03c386d..0311378 100644
--- 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/JobManager.java
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/JobManager.java
@@ -73,12 +73,20 @@ public class JobManager implements JobHandler {
 
   @Override
   public Job submitJob(JobSpec spec) throws UnsupportedJobTypeException {
+    if (!spec.validate()) {
+      return null;
+    }
+
+    JobSubmitter submitter = submitterManager.getSubmitterByType(
+        spec.getSubmitterSpec().getType());
+    if (submitter == null) {
+      throw new UnsupportedJobTypeException();
+    }
+
     Job job = new Job();
     job.setJobId(generateJobId());
     executorService.submit(() -> {
       try {
-        JobSubmitter submitter = submitterManager.getSubmitterByType(
-            spec.getSubmitterSpec().getType());
         jobs.putIfAbsent(job.getJobId(), submitter.submitJob(spec));
       } catch (UnsupportedJobTypeException e) {
         LOG.warn(e.getMessage(), e);
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/JobServerRestApi.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/JobServerRestApi.java
deleted file mode 100644
index e853fef..0000000
--- 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/JobServerRestApi.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.jobserver.rest;
-
-import org.apache.submarine.server.rest.RestConstants;
-import org.apache.submarine.server.api.spec.JobSpec;
-import org.apache.submarine.server.response.JsonResponse;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-/**
- * ML job rest API v1. It can accept MLJobSpec to create a job.
- * To create a job:
- * POST    /api/v1/jobs
- *
- * To list the jobs
- * GET     /api/v1/jobs
- *
- * To get a specific job
- * GET     /api/v1/jobs/{id}
- *
- * To delete a job by id
- * DELETE  /api/v1/jobs/{id}
- * */
-@Path(RestConstants.V1 + "/" + RestConstants.JOBS)
-@Produces({MediaType.APPLICATION_JSON + "; " + RestConstants.CHARSET_UTF8})
-public class JobServerRestApi {
-
-  // A ping test to verify the job server is up.
-  @Path(RestConstants.PING)
-  @GET
-  @Consumes(MediaType.APPLICATION_JSON)
-  public Response ping() {
-    return new JsonResponse.Builder<String>(Response.Status.OK)
-        .success(true).result("Pong").build();
-  }
-
-  @POST
-  @Consumes({RestConstants.MEDIA_TYPE_YAML, MediaType.APPLICATION_JSON})
-  public Response submitJob(JobSpec jobSpec) {
-    // Submit the job spec through submitter
-    return new JsonResponse.Builder<JobSpec>(Response.Status.ACCEPTED)
-        .success(true).result(jobSpec).build();
-  }
-
-  @GET
-  @Path("{" + RestConstants.JOB_ID + "}")
-  public Response listJob(@PathParam(RestConstants.JOB_ID) String id) {
-    // Query the job status though submitter
-    return new JsonResponse.Builder<String>(Response.Status.OK)
-        .success(true).result(id).build();
-  }
-
-  @GET
-  public Response listAllJob() {
-    // Query all the job status though submitter
-    return new JsonResponse.Builder<JobSpec>(Response.Status.OK)
-        .success(true).build();
-  }
-
-  @DELETE
-  @Path("{" + RestConstants.JOB_ID + "}")
-  public Response deleteJob(@PathParam(RestConstants.JOB_ID) String id) {
-    // Delete the job though submitter
-    return new JsonResponse.Builder<String>(Response.Status.OK)
-        .success(true).result(id).build();
-  }
-
-}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/json/JobIdDeserializer.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/json/JobIdDeserializer.java
new file mode 100644
index 0000000..0e1fdc4
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/json/JobIdDeserializer.java
@@ -0,0 +1,37 @@
+/*
+ * 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.json;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import org.apache.submarine.server.api.job.JobId;
+
+import java.lang.reflect.Type;
+
+public class JobIdDeserializer implements JsonDeserializer<JobId> {
+
+  @Override
+  public JobId deserialize(JsonElement json, Type typeOfT, 
JsonDeserializationContext context)
+      throws JsonParseException {
+    return JobId.fromString(json.getAsJsonPrimitive().getAsString());
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/json/JobIdSerializer.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/json/JobIdSerializer.java
new file mode 100644
index 0000000..362bc47
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/json/JobIdSerializer.java
@@ -0,0 +1,35 @@
+/*
+ * 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.json;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import org.apache.submarine.server.api.job.JobId;
+
+import java.lang.reflect.Type;
+
+public class JobIdSerializer implements JsonSerializer<JobId> {
+  @Override
+  public JsonElement serialize(JobId src, Type typeOfSrc, 
JsonSerializationContext context) {
+    return new JsonPrimitive(src.toString());
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
index 304c324..72d4c2b 100644
--- 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
@@ -23,6 +23,9 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.TypeAdapter;
+import org.apache.submarine.server.api.job.JobId;
+import org.apache.submarine.server.json.JobIdDeserializer;
+import org.apache.submarine.server.json.JobIdSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -161,7 +164,10 @@ public class JsonResponse<T> {
 
       safeGson = new GsonBuilder()
           .registerTypeAdapter(Date.class, safeDateTypeAdapter)
-          .serializeNulls().create();
+          .registerTypeAdapter(JobId.class, new JobIdSerializer())
+          .registerTypeAdapter(JobId.class, new JobIdDeserializer())
+          .serializeNulls()
+          .create();
     }
 
     boolean haveDictAnnotation = false;
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java
new file mode 100644
index 0000000..fae7be8
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java
@@ -0,0 +1,121 @@
+/*
+ * 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.rest;
+
+import org.apache.submarine.server.JobManager;
+import org.apache.submarine.server.api.exception.UnsupportedJobTypeException;
+import org.apache.submarine.server.api.job.Job;
+import org.apache.submarine.server.api.job.JobId;
+import org.apache.submarine.server.api.spec.JobSpec;
+import org.apache.submarine.server.response.JsonResponse;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link JobManager}'s REST API v1. It can accept {@link JobSpec} to create a 
job.
+ */
+@Path(RestConstants.V1 + "/" + RestConstants.JOBS)
+@Produces({MediaType.APPLICATION_JSON + "; " + RestConstants.CHARSET_UTF8})
+public class JobManagerRestApi {
+
+  /**
+   * Return the Pong message for test the connectivity
+   * @return Pong message
+   */
+  @GET
+  @Path(RestConstants.PING)
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response ping() {
+    return new JsonResponse.Builder<String>(Response.Status.OK)
+        .success(true).result("Pong").build();
+  }
+
+  /**
+   * Returns the contents of {@link Job} that submitted by user.
+   * @param jobSpec job spec
+   * @return the contents of job
+   */
+  @POST
+  @Consumes({RestConstants.MEDIA_TYPE_YAML, MediaType.APPLICATION_JSON})
+  public Response submitJob(JobSpec jobSpec) {
+    if (!jobSpec.validate()) {
+      return new JsonResponse.Builder<String>(Response.Status.ACCEPTED)
+          .success(true).result("Invalid params.").build();
+    }
+
+    try {
+      Job job = JobManager.getInstance().submitJob(jobSpec);
+      return new JsonResponse.Builder<Job>(Response.Status.ACCEPTED)
+          .success(true).result(job).build();
+    } catch (UnsupportedJobTypeException e) {
+      return new JsonResponse.Builder<String>(Response.Status.ACCEPTED)
+          .success(true).result(e.getMessage()).build();
+    }
+  }
+
+  /**
+   * List all job for the user
+   * @return job list
+   */
+  @GET
+  public Response listJob() {
+    // TODO(jiwq): Hook JobManager when 0.4.0 released
+    return new JsonResponse.Builder<List<Job>>(Response.Status.OK)
+        .success(true).result(new ArrayList<>()).build();
+  }
+
+  /**
+   * Returns the job detailed info by specified job id
+   * @param id job id
+   * @return the detailed info of job
+   */
+  @GET
+  @Path("{" + RestConstants.JOB_ID + "}")
+  public Response getJob(@PathParam(RestConstants.JOB_ID) String id) {
+    // TODO(jiwq): Hook JobManager when 0.4.0 released
+    Job job = new Job();
+    job.setJobId(JobId.fromString(id));
+    return new JsonResponse.Builder<Job>(Response.Status.OK)
+        .success(true).result(job).build();
+  }
+
+  /**
+   * Returns the job that deleted
+   * @param id job id
+   * @return the detailed info about deleted job
+   */
+  @DELETE
+  @Path("{" + RestConstants.JOB_ID + "}")
+  public Response deleteJob(@PathParam(RestConstants.JOB_ID) String id) {
+    // TODO(jiwq): Hook JobManager when 0.4.0 released
+    return new JsonResponse.Builder<Job>(Response.Status.OK)
+        .success(true).result(new Job()).build();
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/provider/YamlEntityProvider.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/provider/YamlEntityProvider.java
similarity index 98%
rename from 
submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/provider/YamlEntityProvider.java
rename to 
submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/provider/YamlEntityProvider.java
index 902dc03..bce9b7b 100644
--- 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/provider/YamlEntityProvider.java
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/provider/YamlEntityProvider.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.submarine.server.jobserver.provider;
+package org.apache.submarine.server.rest.provider;
 
 import org.yaml.snakeyaml.Yaml;
 
diff --git 
a/submarine-server/server-core/src/test/java/org/apache/submarine/server/jobserver/JobServerRestApiTest.java
 
b/submarine-server/server-core/src/test/java/org/apache/submarine/server/rest/JobManagerRestApiTest.java
similarity index 76%
rename from 
submarine-server/server-core/src/test/java/org/apache/submarine/server/jobserver/JobServerRestApiTest.java
rename to 
submarine-server/server-core/src/test/java/org/apache/submarine/server/rest/JobManagerRestApiTest.java
index d580e9d..52d52b7 100644
--- 
a/submarine-server/server-core/src/test/java/org/apache/submarine/server/jobserver/JobServerRestApiTest.java
+++ 
b/submarine-server/server-core/src/test/java/org/apache/submarine/server/rest/JobManagerRestApiTest.java
@@ -17,14 +17,20 @@
  * under the License.
  */
 
-package org.apache.submarine.server.jobserver;
+package org.apache.submarine.server.rest;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
 import org.apache.commons.httpclient.methods.DeleteMethod;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.io.FileUtils;
 import org.apache.submarine.server.AbstractSubmarineServerTest;
-import org.apache.submarine.server.rest.RestConstants;
+import org.apache.submarine.server.api.job.Job;
+import org.apache.submarine.server.api.job.JobId;
+import org.apache.submarine.server.json.JobIdDeserializer;
+import org.apache.submarine.server.json.JobIdSerializer;
 import org.apache.submarine.server.response.JsonResponse;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -33,16 +39,19 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.core.Response;
+import java.io.File;
 import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
 
 import static org.junit.Assert.assertEquals;
 
-public class JobServerRestApiTest extends AbstractSubmarineServerTest {
-  private static final Logger LOG = 
LoggerFactory.getLogger(JobServerRestApiTest.class);
+public class JobManagerRestApiTest extends AbstractSubmarineServerTest {
+  private static final Logger LOG = 
LoggerFactory.getLogger(JobManagerRestApiTest.class);
 
   @BeforeClass
   public static void init() throws Exception {
-    
AbstractSubmarineServerTest.startUp(JobServerRestApiTest.class.getSimpleName());
+    
AbstractSubmarineServerTest.startUp(JobManagerRestApiTest.class.getSimpleName());
   }
 
   @AfterClass
@@ -69,17 +78,18 @@ public class JobServerRestApiTest extends 
AbstractSubmarineServerTest {
 
   // Test job created with correct JSON input
   @Test
-  public void testCreateJobWhenJsonInputIsCorrectThenResponseCodeAccepted() 
throws IOException {
-    String jobSpec = "{\"name\": \"mnist\"}";
+  public void testCreateJobWhenJsonInputIsCorrectThenResponseCodeAccepted() 
throws Exception {
+    URL fileUrl = this.getClass().getResource("/tf-mnist-req.json");
+    String jobSpec = FileUtils.readFileToString(new File(fileUrl.toURI()), 
StandardCharsets.UTF_8);
 
     PostMethod response = httpPost("/api/" + RestConstants.V1 + "/" + 
RestConstants.JOBS, jobSpec);
     LOG.info(response.toString());
 
-    String requestBody = response.getResponseBodyAsString();
-    LOG.info(requestBody);
+    String responseBodyAsString = response.getResponseBodyAsString();
+    LOG.info(responseBodyAsString);
 
     Gson gson = new Gson();
-    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    JsonResponse jsonResponse = gson.fromJson(responseBodyAsString, 
JsonResponse.class);
     assertEquals("Response code should be 202 ",
         Response.Status.ACCEPTED.getStatusCode(), jsonResponse.getCode());
   }
@@ -113,20 +123,24 @@ public class JobServerRestApiTest extends 
AbstractSubmarineServerTest {
   // Test get job by id
   @Test
   public void testGetJobById() throws IOException {
-    String jobId = "job1";
+    String jobId = "job_1577810970_0001";
     GetMethod response = httpGet("/api/" + RestConstants.V1 + "/"
         + RestConstants.JOBS + "/" + jobId);
     LOG.info(response.toString());
 
-    String requestBody = response.getResponseBodyAsString();
-    LOG.info(requestBody);
+    String responseBodyAsString = response.getResponseBodyAsString();
+    LOG.info(responseBodyAsString);
 
-    Gson gson = new Gson();
-    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    Gson gson = new GsonBuilder()
+        .registerTypeAdapter(JobId.class, new JobIdSerializer())
+        .registerTypeAdapter(JobId.class, new JobIdDeserializer())
+        .create();
+    JsonResponse<Job> jsonResponse = gson.fromJson(responseBodyAsString,
+        new TypeToken<JsonResponse<Job>>(){}.getType());
     assertEquals("Response code should be 200 ",
         Response.Status.OK.getStatusCode(), jsonResponse.getCode());
     assertEquals("Job id should be " + jobId, jobId,
-        jsonResponse.getResult().toString());
+        jsonResponse.getResult().getJobId().toString());
   }
 
   // Test delete job by id
diff --git a/submarine-server/server-core/src/test/resources/tf-mnist-req.json 
b/submarine-server/server-core/src/test/resources/tf-mnist-req.json
new file mode 100644
index 0000000..0850e54
--- /dev/null
+++ b/submarine-server/server-core/src/test/resources/tf-mnist-req.json
@@ -0,0 +1,31 @@
+{
+  "name": "mnist",
+  "librarySpec": {
+    "name": "TensorFlow",
+    "version": "2.1.0",
+    "image": "gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0",
+    "cmd": "python /var/tf_mnist/mnist_with_summaries.py --log_dir=/train/log 
--learning_rate=0.01 --batch_size=150",
+    "envVars": {
+      "ENV_1": "ENV1"
+    }
+  },
+  "submitterSpec": {
+    "type": "k8s",
+    "configPath": null,
+    "namespace": "submarine",
+    "kind": "TFJob",
+    "apiVersion": "kubeflow.org/v1"
+  },
+  "taskSpecs": {
+    "Ps": {
+      "name": "tensorflow",
+      "replicas": 2,
+      "resources": "cpu=4,memory=2048M,nvidia.com/gpu=1"
+    },
+    "Worker": {
+      "name": "tensorflow",
+      "replicas": 2,
+      "resources": "cpu=4,memory=2048M,nvidia.com/gpu=1"
+    }
+  }
+}
\ No newline at end of file
diff --git a/submarine-server/server-core/src/test/resources/tf-mnist-req.yaml 
b/submarine-server/server-core/src/test/resources/tf-mnist-req.yaml
new file mode 100644
index 0000000..02e2125
--- /dev/null
+++ b/submarine-server/server-core/src/test/resources/tf-mnist-req.yaml
@@ -0,0 +1,23 @@
+name: "mnist"
+librarySpec:
+  name: "TensorFlow"
+  version: "2.1.0"
+  image: "gcr.io/kubeflow-ci/tf-mnist-with-summaries:1.0"
+  cmd: "python /var/tf_mnist/mnist_with_summaries.py --log_dir=/train/log 
--learning_rate=0.01 --batch_size=150"
+  envVars:
+    ENV_1: "ENV1"
+submitterSpec:
+  type: "k8s"
+  configPath:
+  namespace: "submarine"
+  kind: "TFJob"
+  apiVersion: "kubeflow.org/v1"
+taskSpecs:
+  Ps:
+    name: tensorflow
+    replicas: 2
+    resources: "cpu=4,memory=2048M,nvidia.com/gpu=1"
+  Worker:
+    name: tensorflow
+    replicas: 2
+    resources: "cpu=4,memory=2048M,nvidia.com/gpu=1"


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

Reply via email to