From 78d6b34358a595113d0032f6663c1ccb54a29e1c Mon Sep 17 00:00:00 2001 From: cdmikechen Date: Thu, 16 Dec 2021 17:35:48 +0800 Subject: [PATCH 1/6] SUBMARINE-1125. Fix Conda Version match error ### What is this PR for? The Conda version in jupyter-notebook-0.7.0-SNAPSHOT docker image is 4.11.0 now. But in Submarine it still check version from 4.0.1 to 4.10.10, so that when notebook pod start, it report error like this: ![image](https://user-images.githubusercontent.com/12069428/146346285-b30b19f9-927c-412a-8098-c1906ef51fc1.png) ### What type of PR is it? Bug Fix ### Todos * [x] - Replace max version to 4.11 ### What is the Jira issue? https://issues.apache.org/jira/browse/SUBMARINE-1125 ### How should this be tested? Can test in new docker image. ### Screenshots (if appropriate) ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? No Author: cdmikechen Signed-off-by: kuanhsun Closes #835 from cdmikechen/SUBMARINE-1125 and squashes the following commits: 20a37f9f [cdmikechen] SUBMARINE-1125. Fix Conda Version match error --- .../org/apache/submarine/commons/utils/SubmarineConfVars.java | 2 +- .../server/submitter/k8s/ExperimentSpecParserTest.java | 2 +- .../java/org/apache/submarine/rest/ExperimentRestApiIT.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java index 03862b4927..3c5b3976eb 100644 --- a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java +++ b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java @@ -70,7 +70,7 @@ public enum ConfVars { "org.apache.submarine.server.submitter.yarn.YarnRuntimeFactory"), SUBMARINE_SUBMITTER("submarine.submitter", "k8s"), ENVIRONMENT_CONDA_MIN_VERSION("environment.conda.min.version", "4.0.1"), - ENVIRONMENT_CONDA_MAX_VERSION("environment.conda.max.version", "4.10.10"); + ENVIRONMENT_CONDA_MAX_VERSION("environment.conda.max.version", "4.11.10"); private String varName; @SuppressWarnings("rawtypes") 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 0ba80e2098..e9df5f9a0d 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 @@ -255,7 +255,7 @@ public void testValidPyTorchJobSpecWithEnv() + "\"$currentVersion\" | sort -V | head -n2 | tail -1 )\" " + "!= \"$currentVersion\" ]; then echo \"Conda version " + "should be between minVersion=\"4.0.1\"; " + - "and maxVersion=\"4.10.10\";\"; exit 1; else echo " + "and maxVersion=\"4.11.10\";\"; exit 1; else echo " + "\"Conda current version is " + currentVersion + ". " + "Moving forward with env creation and activation.\"; " + "fi && " + 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 0f36cc3c9d..1cbd386407 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 @@ -344,7 +344,7 @@ private void assertK8sResultEquals(Environment env, Experiment experiment) throw + "\"$currentVersion\" | sort -V | head -n2 | tail -1 )\" " + "!= \"$currentVersion\" ]; then echo \"Conda version " + "should be between minVersion=\"4.0.1\"; " + - "and maxVersion=\"4.10.10\";\"; exit 1; else echo " + "and maxVersion=\"4.11.10\";\"; exit 1; else echo " + "\"Conda current version is " + currentVersion + ". " + "Moving forward with env creation and activation.\"; " + "fi && "; From c15baa7fbe7bf314061559a8514be6220b66bb63 Mon Sep 17 00:00:00 2001 From: jeff-901 Date: Sun, 12 Dec 2021 10:31:31 +0800 Subject: [PATCH 2/6] SUBMARINE-1130. New route to serve pod ### What is this PR for? Add a new route to serve pod. new route: http://\{submarine ip}/{model name}/{model version}/api/v1.0/predictions ### What type of PR is it? Feature ### Todos ### What is the Jira issue? https://issues.apache.org/jira/browse/SUBMARINE-1130 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? No Author: jeff-901 Signed-off-by: kuanhsun Closes #829 from jeff-901/SUBMARINE-1130 and squashes the following commits: 2ea9c5a6 [jeff-901] create virtual service for serve pod --- .../artifacts/submarine/submarine-rbac.yaml | 13 ++ .../serve/istio/IstioHTTPDestination.java | 54 +++++++ .../serve/istio/IstioHTTPMatchRequest.java | 39 +++++ .../submarine/serve/istio/IstioHTTPRoute.java | 67 ++++++++ .../serve/istio/IstioVirtualService.java | 153 ++++++++++++++++++ .../submarine/serve/utils/IstioConstants.java | 42 +++++ .../server/submitter/k8s/K8sSubmitter.java | 43 ++++- 7 files changed, 405 insertions(+), 6 deletions(-) create mode 100644 submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java create mode 100644 submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java create mode 100644 submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java create mode 100644 submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java create mode 100644 submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml b/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml index f568daceca..58d826451d 100644 --- a/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml +++ b/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml @@ -67,6 +67,19 @@ rules: - deletecollection - patch - update +- apiGroups: + - networking.istio.io + resources: + - virtualservices + verbs: + - get + - list + - watch + - create + - delete + - deletecollection + - patch + - update - apiGroups: - "" resources: diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java new file mode 100644 index 0000000000..fc375de12d --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java @@ -0,0 +1,54 @@ +/* + * 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.serve.istio; + +import com.google.gson.annotations.SerializedName; +import org.apache.submarine.serve.utils.IstioConstants; + +public class IstioHTTPDestination { + @SerializedName("destination") + private IstioDestination destination; + + public IstioHTTPDestination(String host){ + this.destination = new IstioDestination(host); + } + + + public static class IstioDestination{ + @SerializedName("host") + private String host; + + @SerializedName("port") + private IstioPort port; + + public IstioDestination(String host) { + this.host = host; + this.port = new IstioPort(IstioConstants.DEFAULT_SERVE_POD_PORT); + } + } + + public static class IstioPort { + @SerializedName("number") + private Integer number; + + public IstioPort(Integer port){ + this.number = port; + } + } +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java new file mode 100644 index 0000000000..18e0b6c589 --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java @@ -0,0 +1,39 @@ +/* + * 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.serve.istio; + +import com.google.gson.annotations.SerializedName; + +public class IstioHTTPMatchRequest { + @SerializedName("uri") + private IstioPrefix prefix; + + public IstioHTTPMatchRequest(String prefix) { + this.prefix = new IstioPrefix(prefix); + } + + public static class IstioPrefix { + @SerializedName("prefix") + private String path; + + public IstioPrefix(String path){ + this.path = path; + } + } +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java new file mode 100644 index 0000000000..7f7ff9ab0d --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java @@ -0,0 +1,67 @@ +/* + * 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.serve.istio; + +import com.google.gson.annotations.SerializedName; +import org.apache.submarine.serve.utils.IstioConstants; + +import java.util.ArrayList; +import java.util.List; + +public class IstioHTTPRoute { + @SerializedName("match") + private List match = new ArrayList<>(); + + @SerializedName("route") + private List route = new ArrayList<>(); + + @SerializedName("rewrite") + private IstioRewrite rewrite; + + public IstioHTTPRoute() { + this.rewrite = new IstioRewrite(IstioConstants.REWRITE_URL); + } + + @Override + public String toString() { + return "'rewrite': {'uri': " + rewrite.getRewrite() + "}"; + + } + + public void addHTTPMatchRequest(IstioHTTPMatchRequest match){ + this.match.add(match); + } + + public void addHTTPDestination(IstioHTTPDestination destination){ + this.route.add(destination); + } + public static class IstioRewrite{ + @SerializedName("uri") + private String uri; + + public IstioRewrite(String rewrite){ + this.uri = rewrite; + } + + public String getRewrite() { + return uri; + } + } + +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java new file mode 100644 index 0000000000..dbe90de185 --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java @@ -0,0 +1,153 @@ +/* + * 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.serve.istio; + +import com.google.gson.annotations.SerializedName; +import io.kubernetes.client.models.V1ObjectMeta; +import org.apache.submarine.serve.utils.IstioConstants; + +import java.util.ArrayList; +import java.util.List; + +public class IstioVirtualService { + @SerializedName("apiVersion") + private String apiVersion = IstioConstants.API_VERSION; + + @SerializedName("kind") + private String kind = IstioConstants.KIND; + + @SerializedName("metadata") + private V1ObjectMeta metadata; + + @SerializedName("spec") + private IstioVirtualServiceSpec spec; + + // transient to avoid being serialized + private transient String group = IstioConstants.GROUP; + + private transient String version = IstioConstants.VERSION; + + private transient String plural = IstioConstants.PLURAL; + + public IstioVirtualService(String modelName, Integer modelVersion) { + V1ObjectMeta metadata = new V1ObjectMeta(); + metadata.setName(modelName); + metadata.setNamespace(IstioConstants.DEFAULT_NAMESPACE); + setMetadata(metadata); + setSpec(new IstioVirtualServiceSpec(modelName, modelVersion)); + } + + public String getApiVersion() { + return apiVersion; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public String getKind() { + return kind; + } + + public void setKind(String kind) { + this.kind = kind; + } + + public V1ObjectMeta getMetadata() { + return metadata; + } + + public void setMetadata(V1ObjectMeta metadata) { + this.metadata = metadata; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getPlural() { + return plural; + } + + public void setPlural(String plural) { + this.plural = plural; + } + + public IstioVirtualServiceSpec getSpec() { + return spec; + } + + public void setSpec(IstioVirtualServiceSpec istioVirtualServiceSpec){ + this.spec = istioVirtualServiceSpec; + } + + public static class IstioVirtualServiceSpec { + @SerializedName("hosts") + private List hosts = new ArrayList<>(); + @SerializedName("gateways") + private List gateways = new ArrayList<>(); + @SerializedName("http") + private List httpRoute = new ArrayList<>(); + + public IstioVirtualServiceSpec(String modelName, Integer modelVersion) { + hosts.add(IstioConstants.DEFAULT_INGRESS_HOST); + gateways.add(IstioConstants.DEFAULT_GATEWAY); + IstioHTTPDestination destination = new IstioHTTPDestination( + modelName + "-" + IstioConstants.DEFAULT_NAMESPACE); + IstioHTTPMatchRequest matchRequest = new IstioHTTPMatchRequest("/" + modelName + + "/" + String.valueOf(modelVersion) + "/"); + IstioHTTPRoute httpRoute = new IstioHTTPRoute(); + httpRoute.addHTTPDestination(destination); + httpRoute.addHTTPMatchRequest(matchRequest); + setHTTPRoute(httpRoute); + } + + public List getHosts() { + return this.hosts; + } + + public void addHost(String host) { + hosts.add(host); + } + + public List getGateways() { + return this.gateways; + } + + public void addGateway(String gateway) { + gateways.add(gateway); + } + + public void setHTTPRoute(IstioHTTPRoute istioHTTPRoute){ + this.httpRoute.add(istioHTTPRoute); + } + } +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java b/submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java new file mode 100644 index 0000000000..10ae72d4ce --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java @@ -0,0 +1,42 @@ +/* + * 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.serve.utils; + +public class IstioConstants { + public static final String API_VERSION = "networking.istio.io/v1beta1"; + + public static final String KIND = "VirtualService"; + + public static final String GROUP = "networking.istio.io"; + + public static final String VERSION = "v1beta1"; + + public static final String PLURAL = "virtualservices"; + + public static final String REWRITE_URL = "/"; + + public static final String DEFAULT_NAMESPACE = "default"; + + public static final String DEFAULT_GATEWAY = "istio-system/seldon-gateway"; + + public static final Integer DEFAULT_SERVE_POD_PORT = 8000; + + public static final String DEFAULT_INGRESS_HOST = "*"; + +} diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java index c1e8298ad7..131e927642 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java @@ -57,6 +57,7 @@ import org.apache.submarine.commons.utils.SubmarineConfiguration; import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException; +import org.apache.submarine.serve.istio.IstioVirtualService; import org.apache.submarine.serve.pytorch.SeldonPytorchServing; import org.apache.submarine.serve.seldon.SeldonDeployment; import org.apache.submarine.serve.tensorflow.SeldonTFServing; @@ -117,7 +118,6 @@ public K8sSubmitter() { public void initialize(SubmarineConfiguration conf) { try { String path = System.getenv(KUBECONFIG_ENV); - // path = System.getProperty("user.home") + "/.kube/config"; //TODO(tmp) KubeConfig config = KubeConfig.loadKubeConfig(new FileReader(path)); client = ClientBuilder.kubeconfig(config).build(); } catch (Exception e) { @@ -522,16 +522,39 @@ public List listNotebook(String id) throws SubmarineRuntimeException { public void createServe(ServeSpec spec) throws SubmarineRuntimeException { SeldonDeployment seldonDeployment = parseServeSpec(spec); - + IstioVirtualService istioVirtualService = new IstioVirtualService(spec.getModelName(), + spec.getModelVersion()); try { api.createNamespacedCustomObject(seldonDeployment.getGroup(), - seldonDeployment.getVersion(), + seldonDeployment.getVersion(), + "default", + seldonDeployment.getPlural(), + seldonDeployment, + "true"); + } catch (ApiException e) { + LOG.error(e.getMessage(), e); + throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); + } + try { + api.createNamespacedCustomObject(istioVirtualService.getGroup(), + istioVirtualService.getVersion(), "default", - seldonDeployment.getPlural(), - seldonDeployment, + istioVirtualService.getPlural(), + istioVirtualService, "true"); } catch (ApiException e) { LOG.error(e.getMessage(), e); + try { + api.deleteNamespacedCustomObject(seldonDeployment.getGroup(), + seldonDeployment.getVersion(), + "default", + seldonDeployment.getPlural(), + seldonDeployment.getMetadata().getName(), + new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build(), + null, null, null); + } catch (ApiException e1) { + LOG.error(e1.getMessage(), e1); + } throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); } } @@ -540,7 +563,8 @@ public void createServe(ServeSpec spec) public void deleteServe(ServeSpec spec) throws SubmarineRuntimeException { SeldonDeployment seldonDeployment = parseServeSpec(spec); - + IstioVirtualService istioVirtualService = new IstioVirtualService(spec.getModelName(), + spec.getModelVersion()); try { api.deleteNamespacedCustomObject(seldonDeployment.getGroup(), seldonDeployment.getVersion(), @@ -549,6 +573,13 @@ public void deleteServe(ServeSpec spec) seldonDeployment.getMetadata().getName(), new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build(), null, null, null); + api.deleteNamespacedCustomObject(istioVirtualService.getGroup(), + istioVirtualService.getVersion(), + "default", + istioVirtualService.getPlural(), + istioVirtualService.getMetadata().getName(), + new V1DeleteOptionsBuilder().withApiVersion(istioVirtualService.getApiVersion()).build(), + null, null, null); } catch (ApiException e) { LOG.error(e.getMessage(), e); throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); From 1a7113adf97a4fa4ec5cfcbb431837ef5906ef9d Mon Sep 17 00:00:00 2001 From: jeff-901 Date: Fri, 17 Dec 2021 09:57:12 +0800 Subject: [PATCH 3/6] SUBMARINE-1083. Update model management Api document ### What is this PR for? Add model management RESTApi document. ### What type of PR is it? Documentation ### Todos ### What is the Jira issue? https://issues.apache.org/jira/browse/SUBMARINE-1083 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? No Author: jeff-901 Signed-off-by: kuanhsun Closes #837 from jeff-901/SUBMARINE-1083 and squashes the following commits: 11b6b8d7 [jeff-901] delete other file d26875a1 [jeff-901] add doc 2f4f612e [jeff-901] add client --- website/docs/api/model-version.md | 221 +++++++++++++++++++++++++++ website/docs/api/registered-model.md | 211 +++++++++++++++++++++++++ 2 files changed, 432 insertions(+) create mode 100644 website/docs/api/model-version.md create mode 100644 website/docs/api/registered-model.md diff --git a/website/docs/api/model-version.md b/website/docs/api/model-version.md new file mode 100644 index 0000000000..1addf1e25c --- /dev/null +++ b/website/docs/api/model-version.md @@ -0,0 +1,221 @@ +--- +title: Serve REST API +--- + + + +> Note: The Model Version API is in the alpha stage which is subjected to incompatible changes in future releases. + +### List model versions under a registered model +`GET /api/v1/model-version/{name}` + +**Example Request:** +```sh +curl -X GET http://127.0.0.1:32080/api/v1/model-version/register +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "List all model version instances", + "result" : [ + { + "creationTime" : "2021-12-12 02:27:05", + "currentStage" : "None", + "dataset" : null, + "description" : null, + "experimentId" : "experiment-1639276018590-0001", + "lastUpdatedTime" : "2021-12-12 02:27:05", + "modelType" : "tensorflow", + "name" : "register", + "source" : "s3://submarine/experiment-1639276018590-0001/example/1", + "tags" : [], + "userId" : "", + "version" : 1 + }, + { + "creationTime" : "2021-12-12 02:27:05", + "currentStage" : "None", + "dataset" : null, + "description" : null, + "experimentId" : "experiment-1639276018590-0001", + "lastUpdatedTime" : "2021-12-12 02:27:05", + "modelType" : "tensorflow", + "name" : "register", + "source" : "s3://submarine/experiment-1639276018590-0001/example/2", + "tags" : [], + "userId" : "", + "version" : 2 + }, + { + "creationTime" : "2021-12-12 02:27:05", + "currentStage" : "None", + "dataset" : null, + "description" : null, + "experimentId" : "experiment-1639276018590-0001", + "lastUpdatedTime" : "2021-12-12 02:27:05", + "modelType" : "tensorflow", + "name" : "register", + "source" : "s3://submarine/experiment-1639276018590-0001/example1/1", + "tags" : [], + "userId" : "", + "version" : 3 + }, + { + "creationTime" : "2021-12-12 02:27:06", + "currentStage" : "None", + "dataset" : null, + "description" : null, + "experimentId" : "experiment-1639276018590-0001", + "lastUpdatedTime" : "2021-12-12 02:27:06", + "modelType" : "tensorflow", + "name" : "register", + "source" : "s3://submarine/experiment-1639276018590-0001/example2/1", + "tags" : [], + "userId" : "", + "version" : 4 + }, + ], + "status" : "OK", + "success" : true +} +``` + +### Get a model version +`GET /api/v1/model-version/{name}/{version}` + +**Example Request:** +```sh +curl -X GET http://127.0.0.1:32080/api/v1/model-version/register/1 +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Get the model version instance", + "result" : { + "creationTime" : "2021-12-12 02:27:05", + "currentStage" : "None", + "dataset" : null, + "description" : null, + "experimentId" : "experiment-1639276018590-0001", + "lastUpdatedTime" : "2021-12-12 02:27:05", + "modelType" : "tensorflow", + "name" : "register", + "source" : "s3://submarine/experiment-1639276018590-0001/example/1", + "tags" : [], + "userId" : "", + "version" : 1 + }, + "status" : "OK", + "success" : true +} +``` + +### Patch a model version +`PATCH /api/v1/model-version` + +**Example Request:** +```sh +curl -X PATCH -H "Content-Type: application/json" -d ' +{ + "name": "register", + "version": 1, + "description": "new_description", + "currentStage": "production", + "dataset": "new_dataset" +}' http://127.0.0.1:32080/api/v1/model-version +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Update the model version instance", + "result" : null, + "status" : "OK", + "success" : true +} +``` + +## Delete a model version +`DELETE /api/v1/model-version/{name}/{version}` + +**Example Request** +```sh +curl -X DELETE http://127.0.0.1:32080/api/v1/model-version/register/1 +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Delete the model version instance", + "result" : null, + "status" : "OK", + "success" : true +} +``` + +## Create a model version tag +`POST /api/v1/model-version/tag?name={name}&version={version}&tag={tag}` + +**Example Request** +```sh +curl -X POST http://127.0.0.1:32080/api/v1/model-version/tag?name=register&version=2&tag=789 +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Create a model version tag instance", + "result" : null, + "status" : "OK", + "success" : true +} +``` + +## Delete a model version tag +`DELETE /api/v1/model-version/tag?name={name}&version={version}&tag={tag}` + +**Example Request** +```sh +curl -X DELETE http://127.0.0.1:32080/api/v1/model-version/tag?name=register&version=2&tag=789 +``` + +**Example Response:** +```json +{ + "status":"OK", + "code":200, + "success":true, + "message":"Delete a registered model tag instance", + "result":null, + "attributes":{} +} +``` \ No newline at end of file diff --git a/website/docs/api/registered-model.md b/website/docs/api/registered-model.md new file mode 100644 index 0000000000..6996c8636b --- /dev/null +++ b/website/docs/api/registered-model.md @@ -0,0 +1,211 @@ +--- +title: Serve REST API +--- + + + +> Note: The Registered Model API is in the alpha stage which is subjected to incompatible changes in future releases. + +## Create a registered model +`POST /api/v1/registered-model` + +**Example Request** +```sh +curl -X POST -H "Content-Type: application/json" -d ' +{ + "name": "example_name", + "description": "example_description", + "tags": ["123", "456"] + } +' http://127.0.0.1:32080/api/v1/registered-model +``` + +**Example Response:** +```json +{ + "status":"OK", + "code":200, + "success":true, + "message":"Create a registered model instance", + "result":null, + "attributes":{} +} +``` + +### List registered models +`GET /api/v1/registered-model` + +**Example Request:** +```sh +curl -X GET http://127.0.0.1:32080/api/v1/registered-model +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "List all registered model instances", + "result" : [ + { + "creationTime" : "2021-12-16 10:14:06", + "description" : "example_description", + "lastUpdatedTime" : "2021-12-16 10:14:06", + "name" : "example_name", + "tags" : [ + "123", + "456" + ] + }, + { + "creationTime" : "2021-12-16 10:16:25", + "description" : "example_description", + "lastUpdatedTime" : "2021-12-16 10:16:25", + "name" : "example_name1", + "tags" : [ + "123", + "456" + ] + }, + { + "creationTime" : "2021-12-12 02:27:05", + "description" : null, + "lastUpdatedTime" : "2021-12-14 12:49:33", + "name" : "register", + "tags" : [] + } + ], + "status" : "OK", + "success" : true +} +``` + +### Get a registered model +`GET /api/v1/registered-model/{name}` + +**Example Request:** +```sh +curl -X GET http://127.0.0.1:32080/api/v1/registered-model/example_name +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Get the registered model instance", + "result" : { + "creationTime" : "2021-12-16 10:14:06", + "description" : "example_description", + "lastUpdatedTime" : "2021-12-16 10:14:06", + "name" : "example_name", + "tags" : [ + "123", + "456" + ] + }, + "status" : "OK", + "success" : true +} +``` + +### Patch a registered model +`PATCH /api/v1/registered-model/{name}` + +**Example Request:** +```sh +curl -X PATCH -H "Content-Type: application/json" -d ' +{ + "name": "new_name", + "description": "new_description" +}' http://127.0.0.1:32080/api/v1/registered-model/example_name +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Update the registered model instance", + "result" : null, + "status" : "OK", + "success" : true +} +``` + +## Delete a registered model +`DELETE /api/v1/registered-model/{name}` + +**Example Request** +```sh +curl -X DELETE http://127.0.0.1:32080/api/v1/registered-model/example_name +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Delete the registered model instance", + "result" : null, + "status" : "OK", + "success" : true +} +``` + +## Create a registered model tag +`POST /api/v1/registered-model/tag?name={name}&tag={tag}` + +**Example Request** +```sh +curl -X POST http://127.0.0.1:32080/api/v1/registered-model/tag?name=example_name&tag=789 +``` + +**Example Response:** +```json +{ + "status":"OK", + "code":200, + "success":true, + "message":"Create a registered model tag instance", + "result":null, + "attributes":{} +} +``` + +## Delete a registered model tag +`DELETE /api/v1/registered-model/tag?name={name}&tag={tag}` + +**Example Request** +```sh +curl -X DELETE http://127.0.0.1:32080/api/v1/registered-model/tag?name=example_name&tag=789 +``` + +**Example Response:** +```json +{ + "attributes" : {}, + "code" : 200, + "message" : "Delete a registered model tag instance", + "result" : null, + "status" : "OK", + "success" : true +} +``` \ No newline at end of file From 50f21b5b1e1ab986f1aaaaa0eb3633de97ae14df Mon Sep 17 00:00:00 2001 From: noidname01 Date: Sun, 19 Dec 2021 22:26:17 +0800 Subject: [PATCH 4/6] SUBMARINE-1109. Java k8s client version from 6 upgrade to 11 ### What is this PR for? The version of k8s client we use is almost out of date, and lacks many features, like CustomResources Management, Generic Api and more concise function. ### What type of PR is it? [Improvement] ### Todos None ### What is the Jira issue? SUBMARINE-1109. Java k8s client version from 6 upgrade to 11 ### How should this be tested? None ### Screenshots (if appropriate) None ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? No Author: noidname01 Signed-off-by: kuanhsun Closes #820 from noidname01/SUBMARINE-1109 and squashes the following commits: 68ad9bb5 [noidname01] checkstyle f6bdb9c3 [noidname01] final 7ecf58e3 [noidname01] fix rebasing 551c1a33 [noidname01] fix rebase error ee3fb277 [noidname01] delete comment e2d2a9c6 [noidname01] delete some foolish 5b1abfaa [noidname01] remove redundant import 6fde016f [noidname01] modify import fe1c223e [noidname01] modify import name 5d7949e0 [noidname01] WIP --- pom.xml | 6 +- .../serve/istio/IstioVirtualService.java | 2 +- .../serve/pytorch/SeldonPytorchServing.java | 2 +- .../serve/seldon/SeldonDeployment.java | 2 +- .../serve/tensorflow/SeldonTFServing.java | 2 +- .../server/submitter/k8s/K8sSubmitter.java | 119 +++++++++--------- .../codelocalizer/AbstractCodeLocalizer.java | 12 +- .../codelocalizer/CodeLocalizer.java | 2 +- .../codelocalizer/DummyCodeLocalizer.java | 2 +- .../codelocalizer/GitCodeLocalizer.java | 8 +- .../codelocalizer/HTTPGitCodeLocalizer.java | 4 +- .../codelocalizer/SSHGitCodeLocalizer.java | 16 +-- .../server/submitter/k8s/model/ListMeta.java | 2 +- .../server/submitter/k8s/model/MLJob.java | 4 +- .../submitter/k8s/model/MLJobReplicaSpec.java | 2 +- .../submitter/k8s/model/NotebookCR.java | 2 +- .../submitter/k8s/model/NotebookCRSpec.java | 4 +- .../submitter/k8s/model/NotebookStatus.java | 2 +- .../k8s/model/ingressroute/IngressRoute.java | 2 +- .../k8s/model/middlewares/Middlewares.java | 2 +- .../k8s/parser/ExperimentSpecParser.java | 22 ++-- .../k8s/parser/NotebookSpecParser.java | 18 +-- .../submitter/k8s/parser/ServeSpecParser.java | 26 ++-- .../k8s/parser/VolumeSpecParser.java | 14 +-- .../submitter/k8s/util/MLJobConverter.java | 12 +- .../submitter/k8s/util/NotebookUtils.java | 6 +- .../k8s/util/OwnerReferenceUtils.java | 2 +- .../k8s/ExperimentSpecParserTest.java | 10 +- .../submitter/k8s/K8SJobSubmitterTest.java | 2 +- .../submitter/k8s/MLJobConverterTest.java | 14 +-- .../submitter/k8s/NotebookSpecParserTest.java | 4 +- .../submarine/rest/ExperimentRestApiIT.java | 10 +- .../submarine/rest/NotebookRestApiIT.java | 10 +- 33 files changed, 172 insertions(+), 175 deletions(-) diff --git a/pom.xml b/pom.xml index 333f269b91..26a4d84af2 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 0.4.7 - 2.27 + 2.35 1.13 9.4.35.v20201120 2.1 @@ -127,10 +127,10 @@ 1.3.7 10.15.1.3 0.9.0-preview1 - 5.5.1.201910021850-r + 5.13.0.202109080827-r 3.1.5 - 6.0.1 + 11.0.1 2.27 2.17 diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java index dbe90de185..955e1120e0 100644 --- a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java @@ -19,7 +19,7 @@ package org.apache.submarine.serve.istio; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import org.apache.submarine.serve.utils.IstioConstants; import java.util.ArrayList; diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/pytorch/SeldonPytorchServing.java b/submarine-serve/src/main/java/org/apache/submarine/serve/pytorch/SeldonPytorchServing.java index b7881d6890..3993ee7a82 100644 --- a/submarine-serve/src/main/java/org/apache/submarine/serve/pytorch/SeldonPytorchServing.java +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/pytorch/SeldonPytorchServing.java @@ -18,7 +18,7 @@ */ package org.apache.submarine.serve.pytorch; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import org.apache.submarine.serve.seldon.SeldonDeployment; import org.apache.submarine.serve.seldon.SeldonGraph; import org.apache.submarine.serve.seldon.SeldonPredictor; diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/seldon/SeldonDeployment.java b/submarine-serve/src/main/java/org/apache/submarine/serve/seldon/SeldonDeployment.java index 483d24c2fd..30c29dd302 100644 --- a/submarine-serve/src/main/java/org/apache/submarine/serve/seldon/SeldonDeployment.java +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/seldon/SeldonDeployment.java @@ -19,7 +19,7 @@ package org.apache.submarine.serve.seldon; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import org.apache.submarine.serve.utils.SeldonConstants; import java.util.ArrayList; diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/tensorflow/SeldonTFServing.java b/submarine-serve/src/main/java/org/apache/submarine/serve/tensorflow/SeldonTFServing.java index d63dbaa2f8..91565fd8af 100644 --- a/submarine-serve/src/main/java/org/apache/submarine/serve/tensorflow/SeldonTFServing.java +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/tensorflow/SeldonTFServing.java @@ -18,7 +18,7 @@ */ package org.apache.submarine.serve.tensorflow; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import org.apache.submarine.serve.seldon.SeldonDeployment; import org.apache.submarine.serve.seldon.SeldonGraph; import org.apache.submarine.serve.seldon.SeldonPredictor; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java index 131e927642..1befeca6b7 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java @@ -28,32 +28,31 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; -import com.squareup.okhttp.OkHttpClient; -import io.kubernetes.client.ApiClient; -import io.kubernetes.client.ApiException; -import io.kubernetes.client.Configuration; -import io.kubernetes.client.JSON; -import io.kubernetes.client.apis.AppsV1Api; -import io.kubernetes.client.apis.CoreV1Api; -import io.kubernetes.client.apis.CustomObjectsApi; -import io.kubernetes.client.models.V1DeleteOptionsBuilder; -import io.kubernetes.client.models.V1Deployment; -import io.kubernetes.client.models.V1Event; -import io.kubernetes.client.models.V1EventList; -import io.kubernetes.client.models.V1ObjectMeta; -import io.kubernetes.client.models.V1PersistentVolumeClaim; -import io.kubernetes.client.models.V1Pod; -import io.kubernetes.client.models.V1PodList; -import io.kubernetes.client.models.V1Status; +import okhttp3.OkHttpClient; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.JSON; +import io.kubernetes.client.openapi.apis.AppsV1Api; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.apis.CustomObjectsApi; +import io.kubernetes.client.openapi.models.V1DeleteOptionsBuilder; +import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.CoreV1Event; +import io.kubernetes.client.openapi.models.CoreV1EventList; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1PersistentVolumeClaim; +import io.kubernetes.client.openapi.models.V1Pod; +import io.kubernetes.client.openapi.models.V1PodList; +import io.kubernetes.client.openapi.models.V1Status; +import io.kubernetes.client.util.Watch; import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.KubeConfig; -import io.kubernetes.client.util.Watch; import org.apache.submarine.commons.utils.SubmarineConfiguration; import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException; @@ -130,8 +129,8 @@ public void initialize(SubmarineConfiguration conf) { } } finally { // let watcher can wait until the next change + client.setReadTimeout(0); OkHttpClient httpClient = client.getHttpClient(); - httpClient.setReadTimeout(0, TimeUnit.SECONDS); client.setHttpClient(httpClient); Configuration.setDefaultApiClient(client); } @@ -164,7 +163,7 @@ public Experiment createExperiment(ExperimentSpec spec) throws SubmarineRuntimeE mlJob.getMetadata().setOwnerReferences(OwnerReferenceUtils.getOwnerReference()); Object object = api.createNamespacedCustomObject(mlJob.getGroup(), mlJob.getVersion(), - mlJob.getMetadata().getNamespace(), mlJob.getPlural(), mlJob, "true"); + mlJob.getMetadata().getNamespace(), mlJob.getPlural(), mlJob, "true", null, null); experiment = parseExperimentResponseObject(object, ParseOp.PARSE_OP_RESULT); } catch (InvalidSpecException e) { LOG.error("K8s submitter: parse Job object failed by " + e.getMessage(), e); @@ -206,7 +205,7 @@ public Experiment patchExperiment(ExperimentSpec spec) throws SubmarineRuntimeEx Object object = api.patchNamespacedCustomObject(mlJob.getGroup(), mlJob.getVersion(), mlJob.getMetadata().getNamespace(), mlJob.getPlural(), mlJob.getMetadata().getName(), - mlJob); + mlJob, null, null, false); experiment = parseExperimentResponseObject(object, ParseOp.PARSE_OP_RESULT); } catch (InvalidSpecException e) { throw new SubmarineRuntimeException(200, e.getMessage()); @@ -224,8 +223,8 @@ public Experiment deleteExperiment(ExperimentSpec spec) throws SubmarineRuntimeE mlJob.getMetadata().setNamespace(getServerNamespace()); Object object = api.deleteNamespacedCustomObject(mlJob.getGroup(), mlJob.getVersion(), - mlJob.getMetadata().getNamespace(), mlJob.getPlural(), mlJob.getMetadata().getName(), - MLJobConverter.toDeleteOptionsFromMLJob(mlJob), null, null, null); + mlJob.getMetadata().getNamespace(), mlJob.getPlural(), mlJob.getMetadata().getName(), 0, + false, null, null, MLJobConverter.toDeleteOptionsFromMLJob(mlJob)); experiment = parseExperimentResponseObject(object, ParseOp.PARSE_OP_DELETE); } catch (InvalidSpecException e) { throw new SubmarineRuntimeException(200, e.getMessage()); @@ -261,9 +260,9 @@ public ExperimentLog getExperimentLogName(ExperimentSpec spec, String id) { try { final V1PodList podList = coreApi.listNamespacedPod( getServerNamespace(), - "false", null, null, + "false", false, null, null, getJobLabelSelector(spec), null, null, - null, null); + null, null, null); for (V1Pod pod : podList.getItems()) { String podName = pod.getMetadata().getName(); experimentLog.addPodLog(podName, null); @@ -280,15 +279,15 @@ public ExperimentLog getExperimentLog(ExperimentSpec spec, String id) { experimentLog.setExperimentId(id); try { final V1PodList podList = coreApi.listNamespacedPod( - getServerNamespace(), - "false", null, null, - getJobLabelSelector(spec), null, null, - null, null); + getServerNamespace(), + "false", false, null, null, + getJobLabelSelector(spec), null, null, + null, null, null); for (V1Pod pod : podList.getItems()) { String podName = pod.getMetadata().getName(); String podLog = coreApi.readNamespacedPodLog( - podName, getServerNamespace(), null, Boolean.FALSE, + podName, getServerNamespace(), null, Boolean.FALSE, null, Integer.MAX_VALUE, null, Boolean.FALSE, Integer.MAX_VALUE, null, Boolean.FALSE); @@ -413,7 +412,7 @@ public Notebook createNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti // create notebook custom resource try { Object object = api.createNamespacedCustomObject(notebookCR.getGroup(), notebookCR.getVersion(), - namespace, notebookCR.getPlural(), notebookCR, "true"); + namespace, notebookCR.getPlural(), notebookCR, "true", null, null); notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_CREATE); } catch (JsonSyntaxException e) { LOG.error("K8s submitter: parse response object failed by " + e.getMessage(), e); @@ -459,13 +458,13 @@ public Notebook findNotebook(NotebookSpec spec) throws SubmarineRuntimeException String podLabelSelector = String.format("%s=%s", NotebookCR.NOTEBOOK_ID, spec.getMeta().getLabels().get(NotebookCR.NOTEBOOK_ID).toString()); - V1PodList podList = coreApi.listNamespacedPod(namespace, null, null, null, podLabelSelector, - null, null, null, null); + V1PodList podList = coreApi.listNamespacedPod(namespace, null, null, null, null, + podLabelSelector, null, null, null, null, null); String podName = podList.getItems().get(0).getMetadata().getName(); String fieldSelector = String.format("involvedObject.name=%s", podName); - V1EventList events = coreApi.listNamespacedEvent(namespace, null, null, fieldSelector, - null, null, null, null, null); - V1Event latestEvent = events.getItems().get(events.getItems().size() - 1); + CoreV1EventList events = coreApi.listNamespacedEvent(namespace, null, null, null, fieldSelector, + null, null, null, null, null, null); + CoreV1Event latestEvent = events.getItems().get(events.getItems().size() - 1); if (latestEvent.getReason().equalsIgnoreCase("Pulling")) { notebook.setStatus(Notebook.Status.STATUS_PULLING.getValue()); @@ -489,9 +488,8 @@ public Notebook deleteNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti NotebookCR notebookCR = NotebookSpecParser.parseNotebook(spec); Object object = api.deleteNamespacedCustomObject(notebookCR.getGroup(), notebookCR.getVersion(), namespace, notebookCR.getPlural(), - notebookCR.getMetadata().getName(), - new V1DeleteOptionsBuilder().withApiVersion(notebookCR.getApiVersion()).build(), - null, null, null); + notebookCR.getMetadata().getName(), null, null, null, + null, new V1DeleteOptionsBuilder().withApiVersion(notebookCR.getApiVersion()).build()); notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_DELETE); deleteIngressRoute(namespace, notebookCR.getMetadata().getName()); deletePersistentVolumeClaim(pvcName, namespace); @@ -509,8 +507,8 @@ public List listNotebook(String id) throws SubmarineRuntimeException { try { Object object = api.listNamespacedCustomObject(NotebookCR.CRD_NOTEBOOK_GROUP_V1, NotebookCR.CRD_NOTEBOOK_VERSION_V1, namespace, NotebookCR.CRD_NOTEBOOK_PLURAL_V1, - "true", null, NotebookCR.NOTEBOOK_OWNER_SELECTOR_KEY + "=" + id, - null, null, null); + "true", null, null, NotebookCR.NOTEBOOK_OWNER_SELECTOR_KEY + "=" + id, + null, null, null, null); notebookList = NotebookUtils.parseObjectForList(object); } catch (ApiException e) { throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); @@ -530,7 +528,7 @@ public void createServe(ServeSpec spec) "default", seldonDeployment.getPlural(), seldonDeployment, - "true"); + "true", null, null); } catch (ApiException e) { LOG.error(e.getMessage(), e); throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); @@ -541,7 +539,7 @@ public void createServe(ServeSpec spec) "default", istioVirtualService.getPlural(), istioVirtualService, - "true"); + "true", null, null); } catch (ApiException e) { LOG.error(e.getMessage(), e); try { @@ -550,8 +548,8 @@ public void createServe(ServeSpec spec) "default", seldonDeployment.getPlural(), seldonDeployment.getMetadata().getName(), - new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build(), - null, null, null); + null, null, null, null, + new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build()); } catch (ApiException e1) { LOG.error(e1.getMessage(), e1); } @@ -570,16 +568,15 @@ public void deleteServe(ServeSpec spec) seldonDeployment.getVersion(), "default", seldonDeployment.getPlural(), - seldonDeployment.getMetadata().getName(), - new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build(), - null, null, null); + seldonDeployment.getMetadata().getName(), null, null, null, + null, new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build()); api.deleteNamespacedCustomObject(istioVirtualService.getGroup(), istioVirtualService.getVersion(), "default", istioVirtualService.getPlural(), istioVirtualService.getMetadata().getName(), - new V1DeleteOptionsBuilder().withApiVersion(istioVirtualService.getApiVersion()).build(), - null, null, null); + null, null, null, null, + new V1DeleteOptionsBuilder().withApiVersion(istioVirtualService.getApiVersion()).build()); } catch (ApiException e) { LOG.error(e.getMessage(), e); throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); @@ -602,8 +599,9 @@ public void watchExperiment() throws ApiException{ null, null, null, - Boolean.TRUE, null, + null, + Boolean.TRUE, null ), new TypeToken>() { @@ -644,8 +642,9 @@ public void run() { null, null, null, - Boolean.TRUE, null, + null, + Boolean.TRUE, null ), new TypeToken>() { @@ -697,7 +696,7 @@ public void deletePersistentVolumeClaim(String pvcName, String namespace) throws but it can still work fine and delete the PVC */ try { - V1Status result = coreApi.deleteNamespacedPersistentVolumeClaim( + V1PersistentVolumeClaim result = coreApi.deleteNamespacedPersistentVolumeClaim( pvcName, namespace, "true", null, null, null, null, null @@ -741,7 +740,7 @@ private void createIngressRoute(String namespace, String name) throws ApiExcepti api.createNamespacedCustomObject( ingressRoute.getGroup(), ingressRoute.getVersion(), ingressRoute.getMetadata().getNamespace(), - ingressRoute.getPlural(), ingressRoute, "true"); + ingressRoute.getPlural(), ingressRoute, "true", null, null); } catch (ApiException e) { LOG.error("K8s submitter: Create Traefik custom resource object failed by " + e.getMessage(), e); throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); @@ -755,9 +754,8 @@ private void deleteIngressRoute(String namespace, String name) { try { api.deleteNamespacedCustomObject( IngressRoute.CRD_INGRESSROUTE_GROUP_V1, IngressRoute.CRD_INGRESSROUTE_VERSION_V1, - namespace, IngressRoute.CRD_INGRESSROUTE_PLURAL_V1, name, - new V1DeleteOptionsBuilder().withApiVersion(IngressRoute.CRD_APIVERSION_V1).build(), - null, null, null); + namespace, IngressRoute.CRD_INGRESSROUTE_PLURAL_V1, name, null, null, null, + null, new V1DeleteOptionsBuilder().withApiVersion(IngressRoute.CRD_APIVERSION_V1).build()); } catch (ApiException e) { LOG.error("K8s submitter: Delete Traefik custom resource object failed by " + e.getMessage(), e); throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); @@ -815,9 +813,8 @@ private void rollbackCreationNotebook(NotebookCR notebookCR, String namespace) try { Object object = api.deleteNamespacedCustomObject(notebookCR.getGroup(), notebookCR.getVersion(), namespace, notebookCR.getPlural(), - notebookCR.getMetadata().getName(), - new V1DeleteOptionsBuilder().withApiVersion(notebookCR.getApiVersion()).build(), - null, null, null); + notebookCR.getMetadata().getName(), null, null, null, null, + new V1DeleteOptionsBuilder().withApiVersion(notebookCR.getApiVersion()).build()); } catch (ApiException e) { throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); } 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 index 46b359bd94..ff25f27c88 100644 --- 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 @@ -21,9 +21,9 @@ 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; +import io.kubernetes.client.openapi.models.V1EmptyDirVolumeSource; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1Volume; public abstract class AbstractCodeLocalizer implements CodeLocalizer { @@ -32,18 +32,18 @@ public abstract class AbstractCodeLocalizer implements CodeLocalizer { 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(); diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java index 2e3e7c1241..7c7ca86d74 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/CodeLocalizer.java @@ -19,7 +19,7 @@ package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer; -import io.kubernetes.client.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1PodSpec; public interface CodeLocalizer { diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java index daf682fe8c..4f08f27fc5 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/DummyCodeLocalizer.java @@ -19,7 +19,7 @@ package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer; -import io.kubernetes.client.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1PodSpec; public class DummyCodeLocalizer extends AbstractCodeLocalizer { 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 index f507e0b35d..bded2c3a2d 100644 --- 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 @@ -26,10 +26,10 @@ 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; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1EnvVar; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1VolumeMount; public abstract class GitCodeLocalizer extends AbstractCodeLocalizer { diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java index edb475b1ff..472135f2a9 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/HTTPGitCodeLocalizer.java @@ -19,14 +19,14 @@ package org.apache.submarine.server.submitter.k8s.experiment.codelocalizer; -import io.kubernetes.client.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1PodSpec; public class HTTPGitCodeLocalizer extends GitCodeLocalizer { public HTTPGitCodeLocalizer(String url) { super(url); } - + @Override public void localize(V1PodSpec podSpec) { super.localize(podSpec); diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java index 085ae0bcbc..d49ef3e33e 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/experiment/codelocalizer/SSHGitCodeLocalizer.java @@ -21,11 +21,11 @@ import java.util.List; -import io.kubernetes.client.models.V1Container; -import io.kubernetes.client.models.V1EnvVar; -import io.kubernetes.client.models.V1PodSpec; -import io.kubernetes.client.models.V1SecurityContext; -import io.kubernetes.client.models.V1VolumeMount; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1EnvVar; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1SecurityContext; +import io.kubernetes.client.openapi.models.V1VolumeMount; public class SSHGitCodeLocalizer extends GitCodeLocalizer { @@ -36,7 +36,7 @@ public class SSHGitCodeLocalizer extends GitCodeLocalizer { public static final long GIT_SYNC_USER = 65533L; public static final String GIT_SYNC_SSH_NAME = "GIT_SYNC_SSH"; public static final String GIT_SYNC_SSH_VALUE = "true"; - + public SSHGitCodeLocalizer(String url) { super(url); } @@ -51,14 +51,14 @@ public void localize(V1PodSpec podSpec) { sshEnv.setName(GIT_SYNC_SSH_NAME); sshEnv.setValue(GIT_SYNC_SSH_VALUE); gitSyncEnvVars.add(sshEnv); - + List mounts = container.getVolumeMounts(); V1VolumeMount mount = new V1VolumeMount(); mount.setName(GIT_SECRET_MOUNT_NAME); mount.setMountPath(GIT_SECRET_PATH); mount.setReadOnly(true); mounts.add(mount); - + V1SecurityContext containerSecurityContext = new V1SecurityContext(); containerSecurityContext diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ListMeta.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ListMeta.java index 7ed10f51f0..13b16f4cea 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ListMeta.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ListMeta.java @@ -20,7 +20,7 @@ package org.apache.submarine.server.submitter.k8s.model; import com.google.gson.GsonBuilder; -import io.kubernetes.client.models.V1ListMeta; +import io.kubernetes.client.openapi.models.V1ListMeta; /** * ListMeta describes metadata that synthetic resources must have, including lists and various diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJob.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJob.java index af773651f0..7673836037 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJob.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJob.java @@ -20,8 +20,8 @@ package org.apache.submarine.server.submitter.k8s.model; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1JobStatus; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1JobStatus; +import io.kubernetes.client.openapi.models.V1ObjectMeta; /** * The machine learning job for the CRD job. diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJobReplicaSpec.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJobReplicaSpec.java index 83919e30a1..ad6947e7c1 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJobReplicaSpec.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/MLJobReplicaSpec.java @@ -20,7 +20,7 @@ package org.apache.submarine.server.submitter.k8s.model; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1PodTemplateSpec; import java.math.BigDecimal; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java index c77a1f22d6..143d4a4b19 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCR.java @@ -20,7 +20,7 @@ package org.apache.submarine.server.submitter.k8s.model; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; public class NotebookCR { diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRSpec.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRSpec.java index bd5b1150d0..975172007f 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRSpec.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookCRSpec.java @@ -20,8 +20,8 @@ package org.apache.submarine.server.submitter.k8s.model; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1EnvVar; -import io.kubernetes.client.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1EnvVar; +import io.kubernetes.client.openapi.models.V1PodTemplateSpec; import java.math.BigDecimal; import java.util.List; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java index bc110067f6..9e50523eb7 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/NotebookStatus.java @@ -19,7 +19,7 @@ package org.apache.submarine.server.submitter.k8s.model; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1ContainerState; +import io.kubernetes.client.openapi.models.V1ContainerState; import java.util.List; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ingressroute/IngressRoute.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ingressroute/IngressRoute.java index 72c5fc6da1..35e0aa6186 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ingressroute/IngressRoute.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/ingressroute/IngressRoute.java @@ -20,7 +20,7 @@ package org.apache.submarine.server.submitter.k8s.model.ingressroute; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; public class IngressRoute { public static final String CRD_INGRESSROUTE_GROUP_V1 = "traefik.containo.us"; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/middlewares/Middlewares.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/middlewares/Middlewares.java index 7b3f7318c0..6547fcbf71 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/middlewares/Middlewares.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/model/middlewares/Middlewares.java @@ -20,7 +20,7 @@ package org.apache.submarine.server.submitter.k8s.model.middlewares; import com.google.gson.annotations.SerializedName; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1ObjectMeta; public class Middlewares { // reference: https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions 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 ece4be7366..a5431fb08d 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 @@ -21,17 +21,17 @@ import io.kubernetes.client.custom.Quantity; -import io.kubernetes.client.models.V1Container; -import io.kubernetes.client.models.V1EnvVar; -import io.kubernetes.client.models.V1ObjectMeta; -import io.kubernetes.client.models.V1PersistentVolumeClaimVolumeSource; -import io.kubernetes.client.models.V1PodSecurityContext; -import io.kubernetes.client.models.V1PodSpec; -import io.kubernetes.client.models.V1PodTemplateSpec; -import io.kubernetes.client.models.V1ResourceRequirements; -import io.kubernetes.client.models.V1SecretVolumeSource; -import io.kubernetes.client.models.V1Volume; -import io.kubernetes.client.models.V1VolumeMount; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1EnvVar; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1PersistentVolumeClaimVolumeSource; +import io.kubernetes.client.openapi.models.V1PodSecurityContext; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1ResourceRequirements; +import io.kubernetes.client.openapi.models.V1SecretVolumeSource; +import io.kubernetes.client.openapi.models.V1Volume; +import io.kubernetes.client.openapi.models.V1VolumeMount; import org.apache.submarine.commons.utils.SubmarineConfVars; import org.apache.submarine.commons.utils.SubmarineConfiguration; import org.apache.submarine.server.api.environment.Environment; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java index b6ac27670b..0ed30b111c 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java @@ -20,15 +20,15 @@ package org.apache.submarine.server.submitter.k8s.parser; import io.kubernetes.client.custom.Quantity; -import io.kubernetes.client.models.V1Container; -import io.kubernetes.client.models.V1EnvVar; -import io.kubernetes.client.models.V1ObjectMeta; -import io.kubernetes.client.models.V1PodTemplateSpec; -import io.kubernetes.client.models.V1PodSpec; -import io.kubernetes.client.models.V1ResourceRequirements; -import io.kubernetes.client.models.V1Volume; -import io.kubernetes.client.models.V1VolumeMount; -import io.kubernetes.client.models.V1PersistentVolumeClaimVolumeSource; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1EnvVar; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1ResourceRequirements; +import io.kubernetes.client.openapi.models.V1Volume; +import io.kubernetes.client.openapi.models.V1VolumeMount; +import io.kubernetes.client.openapi.models.V1PersistentVolumeClaimVolumeSource; import org.apache.submarine.commons.utils.SubmarineConfVars; import org.apache.submarine.commons.utils.SubmarineConfiguration; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ServeSpecParser.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ServeSpecParser.java index a901419c5e..0e42568429 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ServeSpecParser.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/ServeSpecParser.java @@ -27,19 +27,19 @@ import org.apache.submarine.server.submitter.k8s.model.middlewares.StripPrefix; import io.kubernetes.client.custom.IntOrString; -import io.kubernetes.client.models.V1Container; -import io.kubernetes.client.models.V1ContainerPort; -import io.kubernetes.client.models.V1Deployment; -import io.kubernetes.client.models.V1DeploymentSpec; -import io.kubernetes.client.models.V1HTTPGetAction; -import io.kubernetes.client.models.V1LabelSelector; -import io.kubernetes.client.models.V1ObjectMeta; -import io.kubernetes.client.models.V1PodSpec; -import io.kubernetes.client.models.V1PodTemplateSpec; -import io.kubernetes.client.models.V1Probe; -import io.kubernetes.client.models.V1Service; -import io.kubernetes.client.models.V1ServicePort; -import io.kubernetes.client.models.V1ServiceSpec; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1ContainerPort; +import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.V1DeploymentSpec; +import io.kubernetes.client.openapi.models.V1HTTPGetAction; +import io.kubernetes.client.openapi.models.V1LabelSelector; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1Probe; +import io.kubernetes.client.openapi.models.V1Service; +import io.kubernetes.client.openapi.models.V1ServicePort; +import io.kubernetes.client.openapi.models.V1ServiceSpec; import java.util.ArrayList; import java.util.Arrays; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/VolumeSpecParser.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/VolumeSpecParser.java index cde0ccecd7..ebd080fda5 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/VolumeSpecParser.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/VolumeSpecParser.java @@ -20,13 +20,13 @@ package org.apache.submarine.server.submitter.k8s.parser; import io.kubernetes.client.custom.Quantity; -import io.kubernetes.client.models.V1HostPathVolumeSource; -import io.kubernetes.client.models.V1ObjectMeta; -import io.kubernetes.client.models.V1PersistentVolume; -import io.kubernetes.client.models.V1PersistentVolumeClaim; -import io.kubernetes.client.models.V1PersistentVolumeClaimSpec; -import io.kubernetes.client.models.V1PersistentVolumeSpec; -import io.kubernetes.client.models.V1ResourceRequirements; +import io.kubernetes.client.openapi.models.V1HostPathVolumeSource; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1PersistentVolume; +import io.kubernetes.client.openapi.models.V1PersistentVolumeClaim; +import io.kubernetes.client.openapi.models.V1PersistentVolumeClaimSpec; +import io.kubernetes.client.openapi.models.V1PersistentVolumeSpec; +import io.kubernetes.client.openapi.models.V1ResourceRequirements; import java.util.Collections; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/MLJobConverter.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/MLJobConverter.java index 93f9deb181..f6e4e8c190 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/MLJobConverter.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/MLJobConverter.java @@ -20,12 +20,12 @@ package org.apache.submarine.server.submitter.k8s.util; import java.util.List; -import io.kubernetes.client.models.V1DeleteOptions; -import io.kubernetes.client.models.V1DeleteOptionsBuilder; -import io.kubernetes.client.models.V1JobCondition; -import io.kubernetes.client.models.V1JobStatus; -import io.kubernetes.client.models.V1Status; -import io.kubernetes.client.models.V1StatusDetails; +import io.kubernetes.client.openapi.models.V1DeleteOptions; +import io.kubernetes.client.openapi.models.V1DeleteOptionsBuilder; +import io.kubernetes.client.openapi.models.V1JobCondition; +import io.kubernetes.client.openapi.models.V1JobStatus; +import io.kubernetes.client.openapi.models.V1Status; +import io.kubernetes.client.openapi.models.V1StatusDetails; import org.apache.submarine.server.api.experiment.Experiment; import org.apache.submarine.server.submitter.k8s.model.MLJob; import org.joda.time.DateTime; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java index 60e57ab31c..c567520f4e 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java @@ -21,9 +21,9 @@ import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; -import io.kubernetes.client.JSON; -import io.kubernetes.client.models.V1ContainerState; -import io.kubernetes.client.models.V1Status; +import io.kubernetes.client.openapi.JSON; +import io.kubernetes.client.openapi.models.V1ContainerState; +import io.kubernetes.client.openapi.models.V1Status; import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException; import org.apache.submarine.server.api.notebook.Notebook; import org.apache.submarine.server.submitter.k8s.model.NotebookCR; diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/OwnerReferenceUtils.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/OwnerReferenceUtils.java index 4a319d1221..3951ac3177 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/OwnerReferenceUtils.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/OwnerReferenceUtils.java @@ -21,7 +21,7 @@ import java.util.ArrayList; -import io.kubernetes.client.models.V1OwnerReference; +import io.kubernetes.client.openapi.models.V1OwnerReference; public class OwnerReferenceUtils { private static final String SUBMARINE_APIVERSION = "SUBMARINE_APIVERSION"; 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 e9df5f9a0d..b2c732e20a 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 @@ -24,8 +24,8 @@ import java.util.ArrayList; import java.util.List; -import io.kubernetes.client.models.V1ObjectMeta; -import io.kubernetes.client.models.V1Volume; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1Volume; import org.apache.submarine.commons.utils.SubmarineConfVars; import org.apache.submarine.commons.utils.SubmarineConfiguration; @@ -49,9 +49,9 @@ import org.apache.submarine.server.submitter.k8s.experiment.codelocalizer.SSHGitCodeLocalizer; 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; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1EmptyDirVolumeSource; +import io.kubernetes.client.openapi.models.V1EnvVar; public class ExperimentSpecParserTest extends SpecBuilder { diff --git a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/K8SJobSubmitterTest.java b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/K8SJobSubmitterTest.java index 64678fcc26..8e25cc67e0 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/K8SJobSubmitterTest.java +++ b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/K8SJobSubmitterTest.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.net.URISyntaxException; -import io.kubernetes.client.ApiException; +import io.kubernetes.client.openapi.ApiException; import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException; import org.apache.submarine.server.api.experiment.Experiment; import org.apache.submarine.server.api.experiment.TensorboardInfo; diff --git a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/MLJobConverterTest.java b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/MLJobConverterTest.java index 851f6588f1..4e9942ede3 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/MLJobConverterTest.java +++ b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/MLJobConverterTest.java @@ -24,13 +24,13 @@ import java.util.ArrayList; import java.util.List; -import io.kubernetes.client.models.V1DeleteOptions; -import io.kubernetes.client.models.V1JobCondition; -import io.kubernetes.client.models.V1JobConditionBuilder; -import io.kubernetes.client.models.V1JobStatus; -import io.kubernetes.client.models.V1JobStatusBuilder; -import io.kubernetes.client.models.V1Status; -import io.kubernetes.client.models.V1StatusBuilder; +import io.kubernetes.client.openapi.models.V1DeleteOptions; +import io.kubernetes.client.openapi.models.V1JobCondition; +import io.kubernetes.client.openapi.models.V1JobConditionBuilder; +import io.kubernetes.client.openapi.models.V1JobStatus; +import io.kubernetes.client.openapi.models.V1JobStatusBuilder; +import io.kubernetes.client.openapi.models.V1Status; +import io.kubernetes.client.openapi.models.V1StatusBuilder; import org.apache.submarine.server.api.exception.InvalidSpecException; import org.apache.submarine.server.api.experiment.Experiment; import org.apache.submarine.server.api.spec.ExperimentSpec; diff --git a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/NotebookSpecParserTest.java b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/NotebookSpecParserTest.java index a0d680b077..471301a7fa 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/NotebookSpecParserTest.java +++ b/submarine-server/server-submitter/submitter-k8s/src/test/java/org/apache/submarine/server/submitter/k8s/NotebookSpecParserTest.java @@ -19,8 +19,8 @@ package org.apache.submarine.server.submitter.k8s; -import io.kubernetes.client.models.V1EnvVar; -import io.kubernetes.client.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1EnvVar; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import org.apache.submarine.server.api.spec.NotebookMeta; import org.apache.submarine.server.api.spec.NotebookPodSpec; import org.apache.submarine.server.api.spec.NotebookSpec; 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 1cbd386407..e9aa2307c0 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 @@ -57,11 +57,11 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import io.kubernetes.client.ApiClient; -import io.kubernetes.client.ApiException; -import io.kubernetes.client.Configuration; -import io.kubernetes.client.JSON; -import io.kubernetes.client.apis.CustomObjectsApi; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.JSON; +import io.kubernetes.client.openapi.apis.CustomObjectsApi; import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.KubeConfig; diff --git a/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java b/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java index ada557fe9e..2f882050c5 100644 --- a/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java +++ b/submarine-test/test-k8s/src/test/java/org/apache/submarine/rest/NotebookRestApiIT.java @@ -24,11 +24,11 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import io.kubernetes.client.ApiClient; -import io.kubernetes.client.ApiException; -import io.kubernetes.client.Configuration; -import io.kubernetes.client.JSON; -import io.kubernetes.client.apis.CustomObjectsApi; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.JSON; +import io.kubernetes.client.openapi.apis.CustomObjectsApi; import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.KubeConfig; import org.apache.commons.httpclient.methods.DeleteMethod; From a0f5a49d74f01f00929c9d4e5048161c6bee23d8 Mon Sep 17 00:00:00 2001 From: cdmikechen Date: Thu, 16 Dec 2021 17:17:55 +0800 Subject: [PATCH 5/6] SUBMARINE-1126. Let Jupyter Notebook save user setting after pod restarted. ### What is this PR for? Jupyter Notebook have created a workspace volume `/home/jovyan/workspace` , but the user settings are saved in `/home/jovyan/.jupyter/lab/user-settings/jupyterlab/`. So that after pod restart, submarine will lost user settings. I think we should add a new volume to save user settings in `/home/jovyan/.jupyter/`. ### What type of PR is it? Improvement ### Todos * [x] - Add a new PVC named `notebook-pvc-user-*` when creating notebook pod CRD ### What is the Jira issue? https://issues.apache.org/jira/browse/SUBMARINE-1126 ### How should this be tested? There are no new test cases right now. ### Screenshots (if appropriate) ![image](https://user-images.githubusercontent.com/12069428/146344069-5c92950b-cbd0-41d9-bc01-69625e9945a0.png) ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? Maybe No Author: cdmikechen Signed-off-by: Kevin Closes #834 from cdmikechen/SUBMARINE-1126 and squashes the following commits: 5696a8cb [cdmikechen] SUBMARINE-1126. Let Jupyter Notebook save user setting after pod restarted. --- .../server/submitter/k8s/K8sSubmitter.java | 29 +++++++---- .../k8s/parser/NotebookSpecParser.java | 52 +++++++++++++------ .../submitter/k8s/util/NotebookUtils.java | 7 +-- 3 files changed, 58 insertions(+), 30 deletions(-) diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java index 1befeca6b7..8ee8439f14 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java @@ -383,8 +383,8 @@ public Notebook createNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti final String name = spec.getMeta().getName(); final String scName = NotebookUtils.SC_NAME; final String host = NotebookUtils.HOST_PATH; - final String storage = NotebookUtils.STORAGE; - final String pvcName = NotebookUtils.PVC_PREFIX + name; + final String workspacePvc = String.format("%s-%s", NotebookUtils.PVC_PREFIX, name); + final String userPvc = String.format("%s-user-%s", NotebookUtils.PVC_PREFIX, name); String namespace = getServerNamespace(); // parse notebook custom resource @@ -401,7 +401,10 @@ public Notebook createNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti // create persistent volume claim try { - createPersistentVolumeClaim(pvcName, namespace, scName, storage); + // workspace + createPersistentVolumeClaim(workspacePvc, namespace, scName, NotebookUtils.STORAGE); + // user setting + createPersistentVolumeClaim(userPvc, namespace, scName, NotebookUtils.DEFAULT_USER_STORAGE); } catch (ApiException e) { LOG.error("K8s submitter: Create persistent volume claim for Notebook object failed by " + e.getMessage(), e); @@ -416,11 +419,11 @@ public Notebook createNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_CREATE); } catch (JsonSyntaxException e) { LOG.error("K8s submitter: parse response object failed by " + e.getMessage(), e); - rollbackCreationPVC(pvcName, namespace); + rollbackCreationPVC(namespace, workspacePvc, userPvc); throw new SubmarineRuntimeException(500, "K8s Submitter parse upstream response failed."); } catch (ApiException e) { LOG.error("K8s submitter: parse Notebook object failed by " + e.getMessage(), e); - rollbackCreationPVC(pvcName, namespace); + rollbackCreationPVC(namespace, workspacePvc, userPvc); throw new SubmarineRuntimeException(e.getCode(), "K8s submitter: parse Notebook object failed by " + e.getMessage()); } @@ -432,7 +435,7 @@ public Notebook createNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti LOG.error("K8s submitter: Create ingressroute for Notebook object failed by " + e.getMessage(), e); rollbackCreationNotebook(notebookCR, namespace); - rollbackCreationPVC(pvcName, namespace); + rollbackCreationPVC(namespace, workspacePvc, userPvc); throw new SubmarineRuntimeException(e.getCode(), "K8s submitter: ingressroute for Notebook " + "object failed by " + e.getMessage()); } @@ -481,7 +484,6 @@ public Notebook findNotebook(NotebookSpec spec) throws SubmarineRuntimeException public Notebook deleteNotebook(NotebookSpec spec) throws SubmarineRuntimeException { Notebook notebook; final String name = spec.getMeta().getName(); - final String pvcName = NotebookUtils.PVC_PREFIX + name; String namespace = getServerNamespace(); try { @@ -492,7 +494,12 @@ public Notebook deleteNotebook(NotebookSpec spec) throws SubmarineRuntimeExcepti null, new V1DeleteOptionsBuilder().withApiVersion(notebookCR.getApiVersion()).build()); notebook = NotebookUtils.parseObject(object, NotebookUtils.ParseOpt.PARSE_OPT_DELETE); deleteIngressRoute(namespace, notebookCR.getMetadata().getName()); - deletePersistentVolumeClaim(pvcName, namespace); + + // delete pvc + // workspace pvc + deletePersistentVolumeClaim(String.format("%s-%s", NotebookUtils.PVC_PREFIX, name), namespace); + // user set pvc + deletePersistentVolumeClaim(String.format("%s-user-%s", NotebookUtils.PVC_PREFIX, name), namespace); } catch (ApiException e) { throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); } @@ -799,9 +806,11 @@ private SeldonDeployment parseServeSpec(ServeSpec spec) throws SubmarineRuntimeE return seldonDeployment; } - private void rollbackCreationPVC(String pvcName, String namespace) { + private void rollbackCreationPVC(String namespace, String ... pvcNames) { try { - deletePersistentVolumeClaim(pvcName, namespace); + for (String pvcName : pvcNames) { + deletePersistentVolumeClaim(pvcName, namespace); + } } catch (ApiException e) { LOG.error("K8s submitter: delete persistent volume claim failed by {}, may cause some dirty data", e.getMessage()); diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java index 0ed30b111c..2067364095 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/parser/NotebookSpecParser.java @@ -49,7 +49,12 @@ public class NotebookSpecParser { - private static SubmarineConfiguration conf = + // jupyter workspace path + private static final String DEFAULT_WORKSPACE_MOUNT_PATH = "/home/jovyan/workspace"; + // jupyter user setting path, avoid losing user setting after pod restarted + private static final String DEFAULT_USER_SET_MOUNT_PATH = "/home/jovyan/.jupyter"; + + private static final SubmarineConfiguration conf = SubmarineConfiguration.getInstance(); @@ -75,13 +80,15 @@ private static NotebookCRSpec parseNotebookCRSpec(NotebookSpec spec) { } private static V1PodTemplateSpec parseTemplateSpec(NotebookSpec notebookSpec) { + String name = notebookSpec.getMeta().getName(); + NotebookPodSpec notebookPodSpec = notebookSpec.getSpec(); V1PodTemplateSpec podTemplateSpec = new V1PodTemplateSpec(); V1PodSpec podSpec = new V1PodSpec(); // Set container List containers = new ArrayList<>(); V1Container container = new V1Container(); - container.setName(notebookSpec.getMeta().getName()); + container.setName(name); // Environment variables if (notebookPodSpec.getEnvVars() != null) { @@ -147,13 +154,17 @@ private static V1PodTemplateSpec parseTemplateSpec(NotebookSpec notebookSpec) { } // Volume spec - final String DEFAULT_MOUNT_PATH = "/home/jovyan/workspace"; - List volumeMountList = new ArrayList<>(); - V1VolumeMount volumeMount = new V1VolumeMount(); - volumeMount.setMountPath(DEFAULT_MOUNT_PATH); - volumeMount.setName(NotebookUtils.STORAGE_PREFIX + notebookSpec.getMeta().getName()); - volumeMountList.add(volumeMount); + // workspace path + V1VolumeMount workspace = new V1VolumeMount(); + workspace.setMountPath(DEFAULT_WORKSPACE_MOUNT_PATH); + workspace.setName(String.format("%s-%s", NotebookUtils.STORAGE_PREFIX, name)); + volumeMountList.add(workspace); + // user setting path + V1VolumeMount userSetting = new V1VolumeMount(); + userSetting.setMountPath(DEFAULT_USER_SET_MOUNT_PATH); + userSetting.setName(String.format("%s-user-%s", NotebookUtils.STORAGE_PREFIX, name)); + volumeMountList.add(userSetting); container.setVolumeMounts(volumeMountList); containers.add(container); @@ -161,17 +172,24 @@ private static V1PodTemplateSpec parseTemplateSpec(NotebookSpec notebookSpec) { // create volume object for persistent volume List volumeList = new ArrayList<>(); - V1Volume volume = new V1Volume(); - String volumeName = NotebookUtils.STORAGE_PREFIX + notebookSpec.getMeta().getName(); - V1PersistentVolumeClaimVolumeSource persistentVolumeClaim = new V1PersistentVolumeClaimVolumeSource(); - String claimName = NotebookUtils.PVC_PREFIX + notebookSpec.getMeta().getName(); - persistentVolumeClaim.setClaimName(claimName); - volume.setName(volumeName); - volume.setPersistentVolumeClaim(persistentVolumeClaim); - volumeList.add(volume); - podSpec.setVolumes(volumeList); + // workspace + V1Volume workspaceVolume = new V1Volume(); + workspaceVolume.setName(String.format("%s-%s", NotebookUtils.STORAGE_PREFIX, name)); + V1PersistentVolumeClaimVolumeSource workspacePvc = new V1PersistentVolumeClaimVolumeSource(); + workspacePvc.setClaimName(String.format("%s-%s", NotebookUtils.PVC_PREFIX, name)); + workspaceVolume.setPersistentVolumeClaim(workspacePvc); + volumeList.add(workspaceVolume); + // user setting + V1Volume userVolume = new V1Volume(); + userVolume.setName(String.format("%s-user-%s", NotebookUtils.STORAGE_PREFIX, name)); + V1PersistentVolumeClaimVolumeSource userPvc = new V1PersistentVolumeClaimVolumeSource(); + userPvc.setClaimName(String.format("%s-user-%s", NotebookUtils.PVC_PREFIX, name)); + userVolume.setPersistentVolumeClaim(userPvc); + volumeList.add(userVolume); + podSpec.setVolumes(volumeList); podTemplateSpec.setSpec(podSpec); + return podTemplateSpec; } diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java index c567520f4e..8805997834 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/util/NotebookUtils.java @@ -44,10 +44,11 @@ public class NotebookUtils { private static final Logger LOG = LoggerFactory.getLogger(NotebookUtils.class); public static final String STORAGE = "10Gi"; + public static final String DEFAULT_USER_STORAGE = "100Mi"; public static final String SC_NAME = "submarine-storageclass"; - public static final String STORAGE_PREFIX = "notebook-storage-"; - public static final String PV_PREFIX = "notebook-pv-"; - public static final String PVC_PREFIX = "notebook-pvc-"; + public static final String STORAGE_PREFIX = "notebook-storage"; + public static final String PV_PREFIX = "notebook-pv"; + public static final String PVC_PREFIX = "notebook-pvc"; public static final String HOST_PATH = "/mnt"; public enum ParseOpt { From a1436e3dda20f1bfc4a94ff233c284aa51202a9a Mon Sep 17 00:00:00 2001 From: Kevin Su Date: Mon, 20 Dec 2021 13:07:04 +0800 Subject: [PATCH 6/6] SUBMARINE-1149. Sonar: Fix reliability issues in submarine-server Signed-off-by: Kevin Su ### What is this PR for? Try to fix the issues on the sonarcloud. https://sonarcloud.io/project/issues?id=apache_submarine&resolved=false&sinceLeakPeriod=true&types=BUG ### What type of PR is it? [Bug Fix] ### Todos * [ ] - Task ### What is the Jira issue? https://issues.apache.org/jira/browse/SUBMARINE-1149 ### How should this be tested? pass the cis ### Screenshots (if appropriate) ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? No Author: Kevin Su Signed-off-by: Kevin Closes #841 from pingsutw/SUBMARINE-1149 and squashes the following commits: 65519363 [Kevin Su] Sonar: Fix reliability issues in submarine-server --- .../apache/submarine/server/model/ModelManager.java | 2 +- .../workbench/database/utils/MybatisGenerator.java | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/model/ModelManager.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/model/ModelManager.java index 3a6aa6590c..09bc136d7c 100644 --- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/model/ModelManager.java +++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/model/ModelManager.java @@ -36,7 +36,7 @@ public class ModelManager { private static final Logger LOG = LoggerFactory.getLogger(ModelManager.class); - private static volatile ModelManager manager; + private static ModelManager manager; private final Submitter submitter; diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java index 20f8d1bac7..ef98f3ae2a 100644 --- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java +++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java @@ -47,27 +47,26 @@ public static void main(String[] args) { Configuration config = null; try { config = cp.parseConfiguration(configFile); - } catch (IOException e) { - LOG.error(e.getMessage(), e); - } catch (XMLParserException e) { + } catch (IOException | XMLParserException e) { LOG.error(e.getMessage(), e); } DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = null; try { + assert config != null; myBatisGenerator = new MyBatisGenerator(config, callback, warnings); } catch (InvalidConfigurationException e) { LOG.error(e.getMessage(), e); } try { + assert myBatisGenerator != null; myBatisGenerator.generate(null); - } catch (SQLException e) { - LOG.error(e.getMessage(), e); - } catch (IOException e) { + } catch (SQLException | IOException e) { LOG.error(e.getMessage(), e); } catch (InterruptedException e) { LOG.error(e.getMessage(), e); + throw new RuntimeException(e); } } }