You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by pi...@apache.org on 2022/01/15 17:24:31 UTC
[submarine] branch master updated: SUBMARINE-1134. Connect API for CLI Environment
This is an automated email from the ASF dual-hosted git repository.
pingsutw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git
The following commit(s) were added to refs/heads/master by this push:
new 2ed83e2 SUBMARINE-1134. Connect API for CLI Environment
2ed83e2 is described below
commit 2ed83e277aa3466959a06aa44ebea1ecd5ec9415
Author: atosystem <at...@hotmail.com>
AuthorDate: Thu Jan 13 11:27:44 2022 +0800
SUBMARINE-1134. Connect API for CLI Environment
### What is this PR for?
Implement the following commands for submarine cli
* `submarine list environment`
* `submarine get environment <name>`
* `submarine delete environment <name>`
Some java API code is fixed
### What type of PR is it?
[Feature]
### Todos
None
### What is the Jira issue?
https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-1134
### How should this be tested?
e2e test is implemented
### 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? Yes
Author: atosystem <at...@hotmail.com>
Signed-off-by: Kevin <pi...@apache.org>
Closes #867 from atosystem/SUBMARINE-1134 and squashes the following commits:
702e8ed8 [atosystem] SUBMARINE-1134. fix github action
40eb5339 [atosystem] SUBMARINE-1134. lint
a06dcd38 [atosystem] SUBMARINE-1134. implement environment cli
---
.github/workflows/python.yml | 2 +-
dev-support/pysubmarine/swagger_config.json | 4 +-
.../submarine/cli/environment/command.py | 119 ++++++-
.../pysubmarine/submarine/client/__init__.py | 3 -
.../pysubmarine/submarine/client/api/__init__.py | 1 -
.../submarine/client/api/environment_api.py | 344 ++++++++++++++++++-
.../submarine/client/api/environment_client.py | 136 ++++++++
.../submarine/client/api/environments_api.py | 382 ---------------------
.../submarine/client/models/__init__.py | 2 -
.../submarine/client/models/environment_id.py | 158 ---------
.../models/{environment.py => serve_request.py} | 98 ++++--
.../pysubmarine/tests/cli/test_environment.py | 67 +++-
.../tests/environment/test_environment_client.py | 42 +++
.../submarine/server/rest/EnvironmentRestApi.java | 16 +-
14 files changed, 754 insertions(+), 620 deletions(-)
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index b7ac163..f2369ff 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -125,4 +125,4 @@ jobs:
kubectl describe nodes
kubectl get pods
kubectl -n default get events --sort-by='{.lastTimestamp}'
- if: ${{ failure() }}
+ if: ${{ failure() }}
\ No newline at end of file
diff --git a/dev-support/pysubmarine/swagger_config.json b/dev-support/pysubmarine/swagger_config.json
index 3e16d23..f462645 100644
--- a/dev-support/pysubmarine/swagger_config.json
+++ b/dev-support/pysubmarine/swagger_config.json
@@ -1,5 +1,5 @@
{
- "packageName" : "submarine.experiment",
- "projectName" : "submarine.experiment",
+ "packageName" : "submarine.client",
+ "projectName" : "submarine.client",
"packageVersion": "0.7.0-SNAPSHOT"
}
diff --git a/submarine-sdk/pysubmarine/submarine/cli/environment/command.py b/submarine-sdk/pysubmarine/submarine/cli/environment/command.py
index 85c620f..a545e98 100644
--- a/submarine-sdk/pysubmarine/submarine/cli/environment/command.py
+++ b/submarine-sdk/pysubmarine/submarine/cli/environment/command.py
@@ -15,24 +15,129 @@
under the License.
"""
+import json
+import time
+
import click
+from rich.console import Console
+from rich.json import JSON as richJSON
+from rich.panel import Panel
+from rich.table import Table
+
+from submarine.cli.config.config import loadConfig
+from submarine.client.api.environment_client import EnvironmentClient
+from submarine.client.exceptions import ApiException
+
+submarineCliConfig = loadConfig()
+if submarineCliConfig is None:
+ exit(1)
+environmentClient = EnvironmentClient(
+ host="http://{}:{}".format(
+ submarineCliConfig.connection.hostname, submarineCliConfig.connection.port
+ )
+)
+
+POLLING_INTERVAL = 1 # sec
+TIMEOUT = 30 # sec
@click.command("environment")
def list_environment():
"""List environment"""
- click.echo("list environment!")
+ COLS_TO_SHOW = ["Name", "Id", "dockerImage"]
+ console = Console()
+ try:
+ thread = environmentClient.list_environments_async()
+ timeout = time.time() + TIMEOUT
+ with console.status("[bold green] Fetching Environments..."):
+ while not thread.ready():
+ time.sleep(POLLING_INTERVAL)
+ if time.time() > timeout:
+ console.print("[bold red] Timeout!")
+ return
+
+ result = thread.get()
+ results = result.result
+
+ results = list(
+ map(
+ lambda r: [
+ r["environmentSpec"]["name"],
+ r["environmentId"],
+ r["environmentSpec"]["dockerImage"],
+ ],
+ results,
+ )
+ )
+
+ table = Table(title="List of Environments")
+
+ for col in COLS_TO_SHOW:
+ table.add_column(col, overflow="fold")
+ for res in results:
+ table.add_row(*res)
+
+ console.print(table)
+
+ except ApiException as err:
+ if err.body is not None:
+ errbody = json.loads(err.body)
+ click.echo("[Api Error] {}".format(errbody["message"]))
+ else:
+ click.echo("[Api Error] {}".format(err))
@click.command("environment")
-@click.argument("id")
-def get_environment(id):
+@click.argument("name")
+def get_environment(name):
"""Get environment"""
- click.echo("get environment! id={}".format(id))
+ console = Console()
+ try:
+ thread = environmentClient.get_environment_async(name)
+ timeout = time.time() + TIMEOUT
+ with console.status("[bold green] Fetching Environment(name = {} )...".format(name)):
+ while not thread.ready():
+ time.sleep(POLLING_INTERVAL)
+ if time.time() > timeout:
+ console.print("[bold red] Timeout!")
+ return
+
+ result = thread.get()
+ result = result.result
+
+ json_data = richJSON.from_data(result)
+ console.print(Panel(json_data, title="Environment(name = {} )".format(name)))
+ except ApiException as err:
+ if err.body is not None:
+ errbody = json.loads(err.body)
+ click.echo("[Api Error] {}".format(errbody["message"]))
+ else:
+ click.echo("[Api Error] {}".format(err))
@click.command("environment")
-@click.argument("id")
-def delete_environment(id):
+@click.argument("name")
+def delete_environment(name):
"""Delete environment"""
- click.echo("delete environment! id={}".format(id))
+ console = Console()
+ try:
+ thread = environmentClient.delete_environment_async(name)
+ timeout = time.time() + TIMEOUT
+ with console.status("[bold green] Deleting Environment(name = {} )...".format(name)):
+ while not thread.ready():
+ time.sleep(POLLING_INTERVAL)
+ if time.time() > timeout:
+ console.print("[bold red] Timeout!")
+ return
+
+ result = thread.get()
+ result = result.result
+
+ console.print("[bold green] Environment(name = {} ) deleted".format(name))
+
+ except ApiException as err:
+ if err.body is not None:
+ errbody = json.loads(err.body)
+ click.echo("[Api Error] {}".format(errbody["message"]))
+ else:
+ click.echo("[Api Error] {}".format(err))
diff --git a/submarine-sdk/pysubmarine/submarine/client/__init__.py b/submarine-sdk/pysubmarine/submarine/client/__init__.py
index c14fa11..47834d0 100644
--- a/submarine-sdk/pysubmarine/submarine/client/__init__.py
+++ b/submarine-sdk/pysubmarine/submarine/client/__init__.py
@@ -34,7 +34,6 @@ __version__ = "0.7.0-SNAPSHOT"
# import apis into sdk package
from submarine.client.api.environment_api import EnvironmentApi
-from submarine.client.api.environments_api import EnvironmentsApi
from submarine.client.api.experiment_api import ExperimentApi
from submarine.client.api.notebook_api import NotebookApi
@@ -51,8 +50,6 @@ from submarine.client.exceptions import (
# import models into sdk package
from submarine.client.models.code_spec import CodeSpec
-from submarine.client.models.environment import Environment
-from submarine.client.models.environment_id import EnvironmentId
from submarine.client.models.environment_spec import EnvironmentSpec
from submarine.client.models.experiment_meta import ExperimentMeta
from submarine.client.models.experiment_spec import ExperimentSpec
diff --git a/submarine-sdk/pysubmarine/submarine/client/api/__init__.py b/submarine-sdk/pysubmarine/submarine/client/api/__init__.py
index 09104dd..19defd6 100644
--- a/submarine-sdk/pysubmarine/submarine/client/api/__init__.py
+++ b/submarine-sdk/pysubmarine/submarine/client/api/__init__.py
@@ -17,7 +17,6 @@ from __future__ import absolute_import
# import apis into api package
from submarine.client.api.environment_api import EnvironmentApi
-from submarine.client.api.environments_api import EnvironmentsApi
from submarine.client.api.experiment_api import ExperimentApi
from submarine.client.api.notebook_api import NotebookApi
diff --git a/submarine-sdk/pysubmarine/submarine/client/api/environment_api.py b/submarine-sdk/pysubmarine/submarine/client/api/environment_api.py
index 533c1ad..609b534 100644
--- a/submarine-sdk/pysubmarine/submarine/client/api/environment_api.py
+++ b/submarine-sdk/pysubmarine/submarine/client/api/environment_api.py
@@ -66,7 +66,7 @@ class EnvironmentApi(object):
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
- :return: Environment
+ :return: JsonResponse
If the method is called asynchronously,
returns the request thread.
"""
@@ -92,7 +92,7 @@ class EnvironmentApi(object):
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
- :return: tuple(Environment, status_code(int), headers(HTTPHeaderDict))
+ :return: tuple(JsonResponse, status_code(int), headers(HTTPHeaderDict))
If the method is called asynchronously,
returns the request thread.
"""
@@ -148,7 +148,117 @@ class EnvironmentApi(object):
body=body_params,
post_params=form_params,
files=local_var_files,
- response_type="Environment", # noqa: E501
+ response_type="JsonResponse", # noqa: E501
+ auth_settings=auth_settings,
+ async_req=local_var_params.get("async_req"),
+ _return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
+ _preload_content=local_var_params.get("_preload_content", True),
+ _request_timeout=local_var_params.get("_request_timeout"),
+ collection_formats=collection_formats,
+ )
+
+ def delete_environment(self, id, **kwargs): # noqa: E501
+ """Delete the environment # noqa: E501
+
+ This method makes a synchronous HTTP request by default. To make an
+ asynchronous HTTP request, please pass async_req=True
+ >>> thread = api.delete_environment(id, async_req=True)
+ >>> result = thread.get()
+
+ :param async_req bool: execute request asynchronously
+ :param str id: (required)
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
+ be returned without reading/decoding response
+ data. Default is True.
+ :param _request_timeout: timeout setting for this request. If one
+ number provided, it will be total request
+ timeout. It can also be a pair (tuple) of
+ (connection, read) timeouts.
+ :return: JsonResponse
+ If the method is called asynchronously,
+ returns the request thread.
+ """
+ kwargs["_return_http_data_only"] = True
+ return self.delete_environment_with_http_info(id, **kwargs) # noqa: E501
+
+ def delete_environment_with_http_info(self, id, **kwargs): # noqa: E501
+ """Delete the environment # noqa: E501
+
+ This method makes a synchronous HTTP request by default. To make an
+ asynchronous HTTP request, please pass async_req=True
+ >>> thread = api.delete_environment_with_http_info(id, async_req=True)
+ >>> result = thread.get()
+
+ :param async_req bool: execute request asynchronously
+ :param str id: (required)
+ :param _return_http_data_only: response data without head status code
+ and headers
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
+ be returned without reading/decoding response
+ data. Default is True.
+ :param _request_timeout: timeout setting for this request. If one
+ number provided, it will be total request
+ timeout. It can also be a pair (tuple) of
+ (connection, read) timeouts.
+ :return: tuple(JsonResponse, status_code(int), headers(HTTPHeaderDict))
+ If the method is called asynchronously,
+ returns the request thread.
+ """
+
+ local_var_params = locals()
+
+ all_params = ["id"]
+ all_params.extend(
+ ["async_req", "_return_http_data_only", "_preload_content", "_request_timeout"]
+ )
+
+ for key, val in six.iteritems(local_var_params["kwargs"]):
+ if key not in all_params:
+ raise ApiTypeError(
+ "Got an unexpected keyword argument '%s' to method delete_environment" % key
+ )
+ local_var_params[key] = val
+ del local_var_params["kwargs"]
+ # verify the required parameter 'id' is set
+ if self.api_client.client_side_validation and (
+ "id" not in local_var_params or local_var_params["id"] is None # noqa: E501
+ ): # noqa: E501
+ raise ApiValueError(
+ "Missing the required parameter `id` when calling `delete_environment`"
+ ) # noqa: E501
+
+ collection_formats = {}
+
+ path_params = {}
+ if "id" in local_var_params:
+ path_params["id"] = local_var_params["id"] # noqa: E501
+
+ query_params = []
+
+ header_params = {}
+
+ form_params = []
+ local_var_files = {}
+
+ body_params = None
+ # HTTP header `Accept`
+ header_params["Accept"] = self.api_client.select_header_accept(
+ ["application/json; charset=utf-8"]
+ ) # noqa: E501
+
+ # Authentication setting
+ auth_settings = [] # noqa: E501
+
+ return self.api_client.call_api(
+ "/v1/environment/{id}",
+ "DELETE",
+ path_params,
+ query_params,
+ header_params,
+ body=body_params,
+ post_params=form_params,
+ files=local_var_files,
+ response_type="JsonResponse", # noqa: E501
auth_settings=auth_settings,
async_req=local_var_params.get("async_req"),
_return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
@@ -174,7 +284,7 @@ class EnvironmentApi(object):
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
- :return: Environment
+ :return: JsonResponse
If the method is called asynchronously,
returns the request thread.
"""
@@ -200,7 +310,7 @@ class EnvironmentApi(object):
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
- :return: tuple(Environment, status_code(int), headers(HTTPHeaderDict))
+ :return: tuple(JsonResponse, status_code(int), headers(HTTPHeaderDict))
If the method is called asynchronously,
returns the request thread.
"""
@@ -258,7 +368,229 @@ class EnvironmentApi(object):
body=body_params,
post_params=form_params,
files=local_var_files,
- response_type="Environment", # noqa: E501
+ response_type="JsonResponse", # noqa: E501
+ auth_settings=auth_settings,
+ async_req=local_var_params.get("async_req"),
+ _return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
+ _preload_content=local_var_params.get("_preload_content", True),
+ _request_timeout=local_var_params.get("_request_timeout"),
+ collection_formats=collection_formats,
+ )
+
+ def list_environment(self, **kwargs): # noqa: E501
+ """List of Environments # noqa: E501
+
+ This method makes a synchronous HTTP request by default. To make an
+ asynchronous HTTP request, please pass async_req=True
+ >>> thread = api.list_environment(async_req=True)
+ >>> result = thread.get()
+
+ :param async_req bool: execute request asynchronously
+ :param str status:
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
+ be returned without reading/decoding response
+ data. Default is True.
+ :param _request_timeout: timeout setting for this request. If one
+ number provided, it will be total request
+ timeout. It can also be a pair (tuple) of
+ (connection, read) timeouts.
+ :return: JsonResponse
+ If the method is called asynchronously,
+ returns the request thread.
+ """
+ kwargs["_return_http_data_only"] = True
+ return self.list_environment_with_http_info(**kwargs) # noqa: E501
+
+ def list_environment_with_http_info(self, **kwargs): # noqa: E501
+ """List of Environments # noqa: E501
+
+ This method makes a synchronous HTTP request by default. To make an
+ asynchronous HTTP request, please pass async_req=True
+ >>> thread = api.list_environment_with_http_info(async_req=True)
+ >>> result = thread.get()
+
+ :param async_req bool: execute request asynchronously
+ :param str status:
+ :param _return_http_data_only: response data without head status code
+ and headers
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
+ be returned without reading/decoding response
+ data. Default is True.
+ :param _request_timeout: timeout setting for this request. If one
+ number provided, it will be total request
+ timeout. It can also be a pair (tuple) of
+ (connection, read) timeouts.
+ :return: tuple(JsonResponse, status_code(int), headers(HTTPHeaderDict))
+ If the method is called asynchronously,
+ returns the request thread.
+ """
+
+ local_var_params = locals()
+
+ all_params = ["status"]
+ all_params.extend(
+ ["async_req", "_return_http_data_only", "_preload_content", "_request_timeout"]
+ )
+
+ for key, val in six.iteritems(local_var_params["kwargs"]):
+ if key not in all_params:
+ raise ApiTypeError(
+ "Got an unexpected keyword argument '%s' to method list_environment" % key
+ )
+ local_var_params[key] = val
+ del local_var_params["kwargs"]
+
+ collection_formats = {}
+
+ path_params = {}
+
+ query_params = []
+ if "status" in local_var_params and local_var_params["status"] is not None: # noqa: E501
+ query_params.append(("status", local_var_params["status"])) # noqa: E501
+
+ header_params = {}
+
+ form_params = []
+ local_var_files = {}
+
+ body_params = None
+ # HTTP header `Accept`
+ header_params["Accept"] = self.api_client.select_header_accept(
+ ["application/json; charset=utf-8"]
+ ) # noqa: E501
+
+ # Authentication setting
+ auth_settings = [] # noqa: E501
+
+ return self.api_client.call_api(
+ "/v1/environment",
+ "GET",
+ path_params,
+ query_params,
+ header_params,
+ body=body_params,
+ post_params=form_params,
+ files=local_var_files,
+ response_type="JsonResponse", # noqa: E501
+ auth_settings=auth_settings,
+ async_req=local_var_params.get("async_req"),
+ _return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
+ _preload_content=local_var_params.get("_preload_content", True),
+ _request_timeout=local_var_params.get("_request_timeout"),
+ collection_formats=collection_formats,
+ )
+
+ def update_environment(self, id, **kwargs): # noqa: E501
+ """Update the environment with job spec # noqa: E501
+
+ This method makes a synchronous HTTP request by default. To make an
+ asynchronous HTTP request, please pass async_req=True
+ >>> thread = api.update_environment(id, async_req=True)
+ >>> result = thread.get()
+
+ :param async_req bool: execute request asynchronously
+ :param str id: (required)
+ :param EnvironmentSpec environment_spec:
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
+ be returned without reading/decoding response
+ data. Default is True.
+ :param _request_timeout: timeout setting for this request. If one
+ number provided, it will be total request
+ timeout. It can also be a pair (tuple) of
+ (connection, read) timeouts.
+ :return: JsonResponse
+ If the method is called asynchronously,
+ returns the request thread.
+ """
+ kwargs["_return_http_data_only"] = True
+ return self.update_environment_with_http_info(id, **kwargs) # noqa: E501
+
+ def update_environment_with_http_info(self, id, **kwargs): # noqa: E501
+ """Update the environment with job spec # noqa: E501
+
+ This method makes a synchronous HTTP request by default. To make an
+ asynchronous HTTP request, please pass async_req=True
+ >>> thread = api.update_environment_with_http_info(id, async_req=True)
+ >>> result = thread.get()
+
+ :param async_req bool: execute request asynchronously
+ :param str id: (required)
+ :param EnvironmentSpec environment_spec:
+ :param _return_http_data_only: response data without head status code
+ and headers
+ :param _preload_content: if False, the urllib3.HTTPResponse object will
+ be returned without reading/decoding response
+ data. Default is True.
+ :param _request_timeout: timeout setting for this request. If one
+ number provided, it will be total request
+ timeout. It can also be a pair (tuple) of
+ (connection, read) timeouts.
+ :return: tuple(JsonResponse, status_code(int), headers(HTTPHeaderDict))
+ If the method is called asynchronously,
+ returns the request thread.
+ """
+
+ local_var_params = locals()
+
+ all_params = ["id", "environment_spec"]
+ all_params.extend(
+ ["async_req", "_return_http_data_only", "_preload_content", "_request_timeout"]
+ )
+
+ for key, val in six.iteritems(local_var_params["kwargs"]):
+ if key not in all_params:
+ raise ApiTypeError(
+ "Got an unexpected keyword argument '%s' to method update_environment" % key
+ )
+ local_var_params[key] = val
+ del local_var_params["kwargs"]
+ # verify the required parameter 'id' is set
+ if self.api_client.client_side_validation and (
+ "id" not in local_var_params or local_var_params["id"] is None # noqa: E501
+ ): # noqa: E501
+ raise ApiValueError(
+ "Missing the required parameter `id` when calling `update_environment`"
+ ) # noqa: E501
+
+ collection_formats = {}
+
+ path_params = {}
+ if "id" in local_var_params:
+ path_params["id"] = local_var_params["id"] # noqa: E501
+
+ query_params = []
+
+ header_params = {}
+
+ form_params = []
+ local_var_files = {}
+
+ body_params = None
+ if "environment_spec" in local_var_params:
+ body_params = local_var_params["environment_spec"]
+ # HTTP header `Accept`
+ header_params["Accept"] = self.api_client.select_header_accept(
+ ["application/json; charset=utf-8"]
+ ) # noqa: E501
+
+ # HTTP header `Content-Type`
+ header_params["Content-Type"] = self.api_client.select_header_content_type( # noqa: E501
+ ["application/yaml", "application/json"]
+ ) # noqa: E501
+
+ # Authentication setting
+ auth_settings = [] # noqa: E501
+
+ return self.api_client.call_api(
+ "/v1/environment/{id}",
+ "PATCH",
+ path_params,
+ query_params,
+ header_params,
+ body=body_params,
+ post_params=form_params,
+ files=local_var_files,
+ response_type="JsonResponse", # noqa: E501
auth_settings=auth_settings,
async_req=local_var_params.get("async_req"),
_return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
diff --git a/submarine-sdk/pysubmarine/submarine/client/api/environment_client.py b/submarine-sdk/pysubmarine/submarine/client/api/environment_client.py
new file mode 100644
index 0000000..3a12dff
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/client/api/environment_client.py
@@ -0,0 +1,136 @@
+# 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.
+
+import logging
+import os
+
+from submarine.client.api.environment_api import EnvironmentApi
+from submarine.client.api_client import ApiClient
+from submarine.client.configuration import Configuration
+
+logger = logging.getLogger(__name__)
+logging.basicConfig(format="%(message)s")
+logging.getLogger().setLevel(logging.INFO)
+
+
+def generate_host():
+ """
+ Generate submarine host
+ :return: submarine host
+ """
+ submarine_server_dns_name = str(os.environ.get("SUBMARINE_SERVER_DNS_NAME"))
+ submarine_server_port = str(os.environ.get("SUBMARINE_SERVER_PORT"))
+ host = submarine_server_dns_name + ":" + submarine_server_port
+ return host
+
+
+class EnvironmentClient:
+ def __init__(self, host: str = generate_host()):
+ """
+ Submarine environment client constructor
+ :param host: An HTTP URI like http://submarine-server:8080.
+ """
+ # TODO(pingsutw): support authentication for talking to the submarine server
+ self.host = host
+ configuration = Configuration()
+ configuration.host = host + "/api"
+ api_client = ApiClient(configuration=configuration)
+ self.environment_api = EnvironmentApi(api_client=api_client)
+
+ def create_environment(self, environment_spec):
+ """
+ Create an environment
+ :param environment_spec: submarine environment spec
+ :return: submarine environment
+ """
+ response = self.environment_api.create_environment(environment_spec=environment_spec)
+ return response.result
+
+ def create_environment_async(self, environment_spec):
+ """
+ Create an environment (async)
+ :param environment_spec: submarine environment spec
+ :return: thread
+ """
+ thread = self.environment_api.create_environment(
+ environment_spec=environment_spec, async_req=True
+ )
+ return thread
+
+ def update_environment(self, name, environment_spec):
+ """
+ Update an environment
+ :param name: submarine environment name
+ :param environment_spec: submarine environment spec
+ :return: submarine environment
+ """
+ response = self.environment_api.update_environment(
+ id=name, environment_spec=environment_spec
+ )
+ return response.result
+
+ def get_environment(self, name):
+ """
+ Get the environment's detailed info by name
+ :param name: submarine environment name
+ :return: submarine environment
+ """
+ response = self.environment_api.get_environment(id=name)
+ return response.result
+
+ def get_environment_async(self, name):
+ """
+ Get the environment's detailed info by name (async)
+ :param name: submarine environment name
+ :return: thread
+ """
+ thread = self.environment_api.get_environment(id=name, async_req=True)
+ return thread
+
+ def list_environments(self, status=None):
+ """
+ List all environments for the user
+ :param status:
+ :return: List of submarine environments
+ """
+ response = self.environment_api.list_environment(status=status)
+ return response.result
+
+ def list_environments_async(self, status=None):
+ """
+ List all environments for the user (async)
+ :param status:
+ :return: thread
+ """
+ thread = self.environment_api.list_environment(status=status, async_req=True)
+ return thread
+
+ def delete_environment(self, name):
+ """
+ Delete the Submarine environment
+ :param name: Submarine environment name
+ :return: The detailed info about deleted submarine environment
+ """
+ response = self.environment_api.delete_environment(name)
+ return response.result
+
+ def delete_environment_async(self, name):
+ """
+ Delete the Submarine environment (async)
+ :param name: Submarine environment name
+ :return: thread
+ """
+ thread = self.environment_api.delete_environment(name, async_req=True)
+ return thread
diff --git a/submarine-sdk/pysubmarine/submarine/client/api/environments_api.py b/submarine-sdk/pysubmarine/submarine/client/api/environments_api.py
deleted file mode 100644
index d5d02a0..0000000
--- a/submarine-sdk/pysubmarine/submarine/client/api/environments_api.py
+++ /dev/null
@@ -1,382 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# 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.
-
-# coding: utf-8
-
-"""
- Submarine API
-
- The Submarine REST API allows you to access Submarine resources such as, experiments, environments and notebooks. The API is hosted under the /v1 path on the Submarine server. For example, to list experiments on a server hosted at http://localhost:8080, access http://localhost:8080/api/v1/experiment/ # noqa: E501
-
- The version of the OpenAPI document: 0.7.0-SNAPSHOT
- Contact: dev@submarine.apache.org
- Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import re # noqa: F401
-
-# python 2 and python 3 compatibility library
-import six
-
-from submarine.client.api_client import ApiClient
-from submarine.client.exceptions import ApiTypeError, ApiValueError # noqa: F401
-
-
-class EnvironmentsApi(object):
- """NOTE: This class is auto generated by OpenAPI Generator
- Ref: https://openapi-generator.tech
-
- Do not edit the class manually.
- """
-
- def __init__(self, api_client=None):
- if api_client is None:
- api_client = ApiClient()
- self.api_client = api_client
-
- def delete_environment(self, id, **kwargs): # noqa: E501
- """Delete the environment # noqa: E501
-
- This method makes a synchronous HTTP request by default. To make an
- asynchronous HTTP request, please pass async_req=True
- >>> thread = api.delete_environment(id, async_req=True)
- >>> result = thread.get()
-
- :param async_req bool: execute request asynchronously
- :param str id: (required)
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return: Environment
- If the method is called asynchronously,
- returns the request thread.
- """
- kwargs["_return_http_data_only"] = True
- return self.delete_environment_with_http_info(id, **kwargs) # noqa: E501
-
- def delete_environment_with_http_info(self, id, **kwargs): # noqa: E501
- """Delete the environment # noqa: E501
-
- This method makes a synchronous HTTP request by default. To make an
- asynchronous HTTP request, please pass async_req=True
- >>> thread = api.delete_environment_with_http_info(id, async_req=True)
- >>> result = thread.get()
-
- :param async_req bool: execute request asynchronously
- :param str id: (required)
- :param _return_http_data_only: response data without head status code
- and headers
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return: tuple(Environment, status_code(int), headers(HTTPHeaderDict))
- If the method is called asynchronously,
- returns the request thread.
- """
-
- local_var_params = locals()
-
- all_params = ["id"]
- all_params.extend(
- ["async_req", "_return_http_data_only", "_preload_content", "_request_timeout"]
- )
-
- for key, val in six.iteritems(local_var_params["kwargs"]):
- if key not in all_params:
- raise ApiTypeError(
- "Got an unexpected keyword argument '%s' to method delete_environment" % key
- )
- local_var_params[key] = val
- del local_var_params["kwargs"]
- # verify the required parameter 'id' is set
- if self.api_client.client_side_validation and (
- "id" not in local_var_params or local_var_params["id"] is None # noqa: E501
- ): # noqa: E501
- raise ApiValueError(
- "Missing the required parameter `id` when calling `delete_environment`"
- ) # noqa: E501
-
- collection_formats = {}
-
- path_params = {}
- if "id" in local_var_params:
- path_params["id"] = local_var_params["id"] # noqa: E501
-
- query_params = []
-
- header_params = {}
-
- form_params = []
- local_var_files = {}
-
- body_params = None
- # HTTP header `Accept`
- header_params["Accept"] = self.api_client.select_header_accept(
- ["application/json; charset=utf-8"]
- ) # noqa: E501
-
- # Authentication setting
- auth_settings = [] # noqa: E501
-
- return self.api_client.call_api(
- "/v1/environment/{id}",
- "DELETE",
- path_params,
- query_params,
- header_params,
- body=body_params,
- post_params=form_params,
- files=local_var_files,
- response_type="Environment", # noqa: E501
- auth_settings=auth_settings,
- async_req=local_var_params.get("async_req"),
- _return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
- _preload_content=local_var_params.get("_preload_content", True),
- _request_timeout=local_var_params.get("_request_timeout"),
- collection_formats=collection_formats,
- )
-
- def list_environment(self, **kwargs): # noqa: E501
- """List of Environments # noqa: E501
-
- This method makes a synchronous HTTP request by default. To make an
- asynchronous HTTP request, please pass async_req=True
- >>> thread = api.list_environment(async_req=True)
- >>> result = thread.get()
-
- :param async_req bool: execute request asynchronously
- :param str status:
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return: Environment
- If the method is called asynchronously,
- returns the request thread.
- """
- kwargs["_return_http_data_only"] = True
- return self.list_environment_with_http_info(**kwargs) # noqa: E501
-
- def list_environment_with_http_info(self, **kwargs): # noqa: E501
- """List of Environments # noqa: E501
-
- This method makes a synchronous HTTP request by default. To make an
- asynchronous HTTP request, please pass async_req=True
- >>> thread = api.list_environment_with_http_info(async_req=True)
- >>> result = thread.get()
-
- :param async_req bool: execute request asynchronously
- :param str status:
- :param _return_http_data_only: response data without head status code
- and headers
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return: tuple(Environment, status_code(int), headers(HTTPHeaderDict))
- If the method is called asynchronously,
- returns the request thread.
- """
-
- local_var_params = locals()
-
- all_params = ["status"]
- all_params.extend(
- ["async_req", "_return_http_data_only", "_preload_content", "_request_timeout"]
- )
-
- for key, val in six.iteritems(local_var_params["kwargs"]):
- if key not in all_params:
- raise ApiTypeError(
- "Got an unexpected keyword argument '%s' to method list_environment" % key
- )
- local_var_params[key] = val
- del local_var_params["kwargs"]
-
- collection_formats = {}
-
- path_params = {}
-
- query_params = []
- if "status" in local_var_params and local_var_params["status"] is not None: # noqa: E501
- query_params.append(("status", local_var_params["status"])) # noqa: E501
-
- header_params = {}
-
- form_params = []
- local_var_files = {}
-
- body_params = None
- # HTTP header `Accept`
- header_params["Accept"] = self.api_client.select_header_accept(
- ["application/json; charset=utf-8"]
- ) # noqa: E501
-
- # Authentication setting
- auth_settings = [] # noqa: E501
-
- return self.api_client.call_api(
- "/v1/environment",
- "GET",
- path_params,
- query_params,
- header_params,
- body=body_params,
- post_params=form_params,
- files=local_var_files,
- response_type="Environment", # noqa: E501
- auth_settings=auth_settings,
- async_req=local_var_params.get("async_req"),
- _return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
- _preload_content=local_var_params.get("_preload_content", True),
- _request_timeout=local_var_params.get("_request_timeout"),
- collection_formats=collection_formats,
- )
-
- def update_environment(self, id, **kwargs): # noqa: E501
- """Update the environment with job spec # noqa: E501
-
- This method makes a synchronous HTTP request by default. To make an
- asynchronous HTTP request, please pass async_req=True
- >>> thread = api.update_environment(id, async_req=True)
- >>> result = thread.get()
-
- :param async_req bool: execute request asynchronously
- :param str id: (required)
- :param EnvironmentSpec environment_spec:
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return: Environment
- If the method is called asynchronously,
- returns the request thread.
- """
- kwargs["_return_http_data_only"] = True
- return self.update_environment_with_http_info(id, **kwargs) # noqa: E501
-
- def update_environment_with_http_info(self, id, **kwargs): # noqa: E501
- """Update the environment with job spec # noqa: E501
-
- This method makes a synchronous HTTP request by default. To make an
- asynchronous HTTP request, please pass async_req=True
- >>> thread = api.update_environment_with_http_info(id, async_req=True)
- >>> result = thread.get()
-
- :param async_req bool: execute request asynchronously
- :param str id: (required)
- :param EnvironmentSpec environment_spec:
- :param _return_http_data_only: response data without head status code
- and headers
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return: tuple(Environment, status_code(int), headers(HTTPHeaderDict))
- If the method is called asynchronously,
- returns the request thread.
- """
-
- local_var_params = locals()
-
- all_params = ["id", "environment_spec"]
- all_params.extend(
- ["async_req", "_return_http_data_only", "_preload_content", "_request_timeout"]
- )
-
- for key, val in six.iteritems(local_var_params["kwargs"]):
- if key not in all_params:
- raise ApiTypeError(
- "Got an unexpected keyword argument '%s' to method update_environment" % key
- )
- local_var_params[key] = val
- del local_var_params["kwargs"]
- # verify the required parameter 'id' is set
- if self.api_client.client_side_validation and (
- "id" not in local_var_params or local_var_params["id"] is None # noqa: E501
- ): # noqa: E501
- raise ApiValueError(
- "Missing the required parameter `id` when calling `update_environment`"
- ) # noqa: E501
-
- collection_formats = {}
-
- path_params = {}
- if "id" in local_var_params:
- path_params["id"] = local_var_params["id"] # noqa: E501
-
- query_params = []
-
- header_params = {}
-
- form_params = []
- local_var_files = {}
-
- body_params = None
- if "environment_spec" in local_var_params:
- body_params = local_var_params["environment_spec"]
- # HTTP header `Accept`
- header_params["Accept"] = self.api_client.select_header_accept(
- ["application/json; charset=utf-8"]
- ) # noqa: E501
-
- # HTTP header `Content-Type`
- header_params["Content-Type"] = self.api_client.select_header_content_type( # noqa: E501
- ["application/yaml", "application/json"]
- ) # noqa: E501
-
- # Authentication setting
- auth_settings = [] # noqa: E501
-
- return self.api_client.call_api(
- "/v1/environment/{id}",
- "PATCH",
- path_params,
- query_params,
- header_params,
- body=body_params,
- post_params=form_params,
- files=local_var_files,
- response_type="Environment", # noqa: E501
- auth_settings=auth_settings,
- async_req=local_var_params.get("async_req"),
- _return_http_data_only=local_var_params.get("_return_http_data_only"), # noqa: E501
- _preload_content=local_var_params.get("_preload_content", True),
- _request_timeout=local_var_params.get("_request_timeout"),
- collection_formats=collection_formats,
- )
diff --git a/submarine-sdk/pysubmarine/submarine/client/models/__init__.py b/submarine-sdk/pysubmarine/submarine/client/models/__init__.py
index 75be16c..005b99b 100644
--- a/submarine-sdk/pysubmarine/submarine/client/models/__init__.py
+++ b/submarine-sdk/pysubmarine/submarine/client/models/__init__.py
@@ -31,8 +31,6 @@ from __future__ import absolute_import
# import models into model package
from submarine.client.models.code_spec import CodeSpec
-from submarine.client.models.environment import Environment
-from submarine.client.models.environment_id import EnvironmentId
from submarine.client.models.environment_spec import EnvironmentSpec
from submarine.client.models.experiment_meta import ExperimentMeta
from submarine.client.models.experiment_spec import ExperimentSpec
diff --git a/submarine-sdk/pysubmarine/submarine/client/models/environment_id.py b/submarine-sdk/pysubmarine/submarine/client/models/environment_id.py
deleted file mode 100644
index f4d9756..0000000
--- a/submarine-sdk/pysubmarine/submarine/client/models/environment_id.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# 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.
-
-# coding: utf-8
-
-"""
- Submarine API
-
- The Submarine REST API allows you to access Submarine resources such as, experiments, environments and notebooks. The API is hosted under the /v1 path on the Submarine server. For example, to list experiments on a server hosted at http://localhost:8080, access http://localhost:8080/api/v1/experiment/ # noqa: E501
-
- The version of the OpenAPI document: 0.7.0-SNAPSHOT
- Contact: dev@submarine.apache.org
- Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re # noqa: F401
-
-import six
-
-from submarine.client.configuration import Configuration
-
-
-class EnvironmentId(object):
- """NOTE: This class is auto generated by OpenAPI Generator.
- Ref: https://openapi-generator.tech
-
- Do not edit the class manually.
- """
-
- """
- Attributes:
- openapi_types (dict): The key is attribute name
- and the value is attribute type.
- attribute_map (dict): The key is attribute name
- and the value is json key in definition.
- """
- openapi_types = {"id": "int", "server_timestamp": "int"}
-
- attribute_map = {"id": "id", "server_timestamp": "serverTimestamp"}
-
- def __init__(self, id=None, server_timestamp=None, local_vars_configuration=None): # noqa: E501
- """EnvironmentId - a model defined in OpenAPI""" # noqa: E501
- if local_vars_configuration is None:
- local_vars_configuration = Configuration()
- self.local_vars_configuration = local_vars_configuration
-
- self._id = None
- self._server_timestamp = None
- self.discriminator = None
-
- if id is not None:
- self.id = id
- if server_timestamp is not None:
- self.server_timestamp = server_timestamp
-
- @property
- def id(self):
- """Gets the id of this EnvironmentId. # noqa: E501
-
-
- :return: The id of this EnvironmentId. # noqa: E501
- :rtype: int
- """
- return self._id
-
- @id.setter
- def id(self, id):
- """Sets the id of this EnvironmentId.
-
-
- :param id: The id of this EnvironmentId. # noqa: E501
- :type: int
- """
-
- self._id = id
-
- @property
- def server_timestamp(self):
- """Gets the server_timestamp of this EnvironmentId. # noqa: E501
-
-
- :return: The server_timestamp of this EnvironmentId. # noqa: E501
- :rtype: int
- """
- return self._server_timestamp
-
- @server_timestamp.setter
- def server_timestamp(self, server_timestamp):
- """Sets the server_timestamp of this EnvironmentId.
-
-
- :param server_timestamp: The server_timestamp of this EnvironmentId. # noqa: E501
- :type: int
- """
-
- self._server_timestamp = server_timestamp
-
- def to_dict(self):
- """Returns the model properties as a dict"""
- result = {}
-
- for attr, _ in six.iteritems(self.openapi_types):
- value = getattr(self, attr)
- if isinstance(value, list):
- result[attr] = list(
- map(lambda x: x.to_dict() if hasattr(x, "to_dict") else x, value)
- )
- elif hasattr(value, "to_dict"):
- result[attr] = value.to_dict()
- elif isinstance(value, dict):
- result[attr] = dict(
- map(
- lambda item: (item[0], item[1].to_dict())
- if hasattr(item[1], "to_dict")
- else item,
- value.items(),
- )
- )
- else:
- result[attr] = value
-
- return result
-
- def to_str(self):
- """Returns the string representation of the model"""
- return pprint.pformat(self.to_dict())
-
- def __repr__(self):
- """For `print` and `pprint`"""
- return self.to_str()
-
- def __eq__(self, other):
- """Returns true if both objects are equal"""
- if not isinstance(other, EnvironmentId):
- return False
-
- return self.to_dict() == other.to_dict()
-
- def __ne__(self, other):
- """Returns true if both objects are not equal"""
- if not isinstance(other, EnvironmentId):
- return True
-
- return self.to_dict() != other.to_dict()
diff --git a/submarine-sdk/pysubmarine/submarine/client/models/environment.py b/submarine-sdk/pysubmarine/submarine/client/models/serve_request.py
similarity index 61%
rename from submarine-sdk/pysubmarine/submarine/client/models/environment.py
rename to submarine-sdk/pysubmarine/submarine/client/models/serve_request.py
index d047e46..9a4313e 100644
--- a/submarine-sdk/pysubmarine/submarine/client/models/environment.py
+++ b/submarine-sdk/pysubmarine/submarine/client/models/serve_request.py
@@ -34,7 +34,7 @@ import six
from submarine.client.configuration import Configuration
-class Environment(object):
+class ServeRequest(object):
"""NOTE: This class is auto generated by OpenAPI Generator.
Ref: https://openapi-generator.tech
@@ -48,68 +48,96 @@ class Environment(object):
attribute_map (dict): The key is attribute name
and the value is json key in definition.
"""
- openapi_types = {"environment_id": "EnvironmentId", "environment_spec": "EnvironmentSpec"}
+ openapi_types = {"model_name": "str", "model_version": "str", "namespace": "str"}
- attribute_map = {"environment_id": "environmentId", "environment_spec": "environmentSpec"}
+ attribute_map = {
+ "model_name": "modelName",
+ "model_version": "modelVersion",
+ "namespace": "namespace",
+ }
def __init__(
- self, environment_id=None, environment_spec=None, local_vars_configuration=None
+ self, model_name=None, model_version=None, namespace=None, local_vars_configuration=None
): # noqa: E501
- """Environment - a model defined in OpenAPI""" # noqa: E501
+ """ServeRequest - a model defined in OpenAPI""" # noqa: E501
if local_vars_configuration is None:
local_vars_configuration = Configuration()
self.local_vars_configuration = local_vars_configuration
- self._environment_id = None
- self._environment_spec = None
+ self._model_name = None
+ self._model_version = None
+ self._namespace = None
self.discriminator = None
- if environment_id is not None:
- self.environment_id = environment_id
- if environment_spec is not None:
- self.environment_spec = environment_spec
+ if model_name is not None:
+ self.model_name = model_name
+ if model_version is not None:
+ self.model_version = model_version
+ if namespace is not None:
+ self.namespace = namespace
@property
- def environment_id(self):
- """Gets the environment_id of this Environment. # noqa: E501
+ def model_name(self):
+ """Gets the model_name of this ServeRequest. # noqa: E501
- :return: The environment_id of this Environment. # noqa: E501
- :rtype: EnvironmentId
+ :return: The model_name of this ServeRequest. # noqa: E501
+ :rtype: str
"""
- return self._environment_id
+ return self._model_name
- @environment_id.setter
- def environment_id(self, environment_id):
- """Sets the environment_id of this Environment.
+ @model_name.setter
+ def model_name(self, model_name):
+ """Sets the model_name of this ServeRequest.
- :param environment_id: The environment_id of this Environment. # noqa: E501
- :type: EnvironmentId
+ :param model_name: The model_name of this ServeRequest. # noqa: E501
+ :type: str
"""
- self._environment_id = environment_id
+ self._model_name = model_name
@property
- def environment_spec(self):
- """Gets the environment_spec of this Environment. # noqa: E501
+ def model_version(self):
+ """Gets the model_version of this ServeRequest. # noqa: E501
- :return: The environment_spec of this Environment. # noqa: E501
- :rtype: EnvironmentSpec
+ :return: The model_version of this ServeRequest. # noqa: E501
+ :rtype: str
"""
- return self._environment_spec
+ return self._model_version
- @environment_spec.setter
- def environment_spec(self, environment_spec):
- """Sets the environment_spec of this Environment.
+ @model_version.setter
+ def model_version(self, model_version):
+ """Sets the model_version of this ServeRequest.
- :param environment_spec: The environment_spec of this Environment. # noqa: E501
- :type: EnvironmentSpec
+ :param model_version: The model_version of this ServeRequest. # noqa: E501
+ :type: str
"""
- self._environment_spec = environment_spec
+ self._model_version = model_version
+
+ @property
+ def namespace(self):
+ """Gets the namespace of this ServeRequest. # noqa: E501
+
+
+ :return: The namespace of this ServeRequest. # noqa: E501
+ :rtype: str
+ """
+ return self._namespace
+
+ @namespace.setter
+ def namespace(self, namespace):
+ """Sets the namespace of this ServeRequest.
+
+
+ :param namespace: The namespace of this ServeRequest. # noqa: E501
+ :type: str
+ """
+
+ self._namespace = namespace
def to_dict(self):
"""Returns the model properties as a dict"""
@@ -147,14 +175,14 @@ class Environment(object):
def __eq__(self, other):
"""Returns true if both objects are equal"""
- if not isinstance(other, Environment):
+ if not isinstance(other, ServeRequest):
return False
return self.to_dict() == other.to_dict()
def __ne__(self, other):
"""Returns true if both objects are not equal"""
- if not isinstance(other, Environment):
+ if not isinstance(other, ServeRequest):
return True
return self.to_dict() != other.to_dict()
diff --git a/submarine-sdk/pysubmarine/tests/cli/test_environment.py b/submarine-sdk/pysubmarine/tests/cli/test_environment.py
index 7240bf1..3ebcf1f 100644
--- a/submarine-sdk/pysubmarine/tests/cli/test_environment.py
+++ b/submarine-sdk/pysubmarine/tests/cli/test_environment.py
@@ -13,29 +13,66 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import pytest
from click.testing import CliRunner
from submarine.cli import main
+from submarine.client.api.environment_client import EnvironmentClient
+from submarine.client.models.environment_spec import EnvironmentSpec
+from submarine.client.models.kernel_spec import KernelSpec
+TEST_CONSOLE_WIDTH = 191
-def test_list_environment():
- runner = CliRunner()
- result = runner.invoke(main.entry_point, ["list", "environment"])
+
+@pytest.mark.e2e
+def test_all_environment_e2e():
+ """E2E Test for using submarine CLI to access submarine environment
+ To run this test, you should first set
+ your submarine CLI config `port` to 8080 and `hostname` to localhost
+ i.e. please execute the commands in your terminal:
+ submarine config set connection.hostname localhost
+ submarine config set connection.port 8080
+ """
+ # set env to display full table
+ runner = CliRunner(env={"COLUMNS": str(TEST_CONSOLE_WIDTH)})
+ # check if cli config is correct for testing
+ result = runner.invoke(main.entry_point, ["config", "get", "connection.port"])
assert result.exit_code == 0
- assert "list environment!" in result.output
+ assert "connection.port={}".format(8080) in result.output
+
+ submarine_client = EnvironmentClient(host="http://localhost:8080")
+ kernel_spec = KernelSpec(
+ name="submarine_jupyter_py3",
+ channels=["defaults"],
+ conda_dependencies=[],
+ pip_dependencies=[],
+ )
+ environment_spec = EnvironmentSpec(
+ name="mytest",
+ kernel_spec=kernel_spec,
+ docker_image="apache/submarine:jupyter-notebook-gpu-0.7.0-SNAPSHOT",
+ )
+ environment = submarine_client.create_environment(environment_spec=environment_spec)
+ environment_name = environment["environmentSpec"]["name"]
-def test_get_environment():
- mock_environment_id = "0"
- runner = CliRunner()
- result = runner.invoke(main.entry_point, ["get", "environment", mock_environment_id])
+ # test list environment
+ result = runner.invoke(main.entry_point, ["list", "environment"])
assert result.exit_code == 0
- assert "get environment! id={}".format(mock_environment_id) in result.output
+ assert "List of Environments" in result.output
+ assert environment["environmentSpec"]["name"] in result.output
+ assert environment["environmentSpec"]["dockerImage"] in result.output
+ assert environment["environmentId"] in result.output
+ # test get environment
+ result = runner.invoke(main.entry_point, ["get", "environment", environment_name])
+ assert "Environment(name = {} )".format(environment_name) in result.output
+ assert environment["environmentSpec"]["name"] in result.output
-def test_delete_environment():
- mock_environment_id = "0"
- runner = CliRunner()
- result = runner.invoke(main.entry_point, ["delete", "environment", mock_environment_id])
- assert result.exit_code == 0
- assert "delete environment! id={}".format(mock_environment_id) in result.output
+ # test delete environment
+ result = runner.invoke(main.entry_point, ["delete", "environment", environment_name])
+ assert "Environment(name = {} ) deleted".format(environment_name) in result.output
+
+ # test get environment fail after delete
+ result = runner.invoke(main.entry_point, ["get", "environment", environment_name])
+ assert "[Api Error] Environment not found." in result.output
diff --git a/submarine-sdk/pysubmarine/tests/environment/test_environment_client.py b/submarine-sdk/pysubmarine/tests/environment/test_environment_client.py
new file mode 100644
index 0000000..a735235
--- /dev/null
+++ b/submarine-sdk/pysubmarine/tests/environment/test_environment_client.py
@@ -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.
+
+import pytest
+
+from submarine.client.api.environment_client import EnvironmentClient
+from submarine.client.models.environment_spec import EnvironmentSpec
+from submarine.client.models.kernel_spec import KernelSpec
+
+
+@pytest.mark.e2e
+def test_environment_e2e():
+ submarine_client = EnvironmentClient(host="http://localhost:8080")
+ kernel_spec = KernelSpec(
+ name="submarine_jupyter_py3",
+ channels=["defaults"],
+ conda_dependencies=[],
+ pip_dependencies=[],
+ )
+ environment_spec = EnvironmentSpec(
+ name="mytest",
+ kernel_spec=kernel_spec,
+ docker_image="apache/submarine:jupyter-notebook-gpu-0.7.0-SNAPSHOT",
+ )
+
+ environment = submarine_client.create_environment(environment_spec=environment_spec)
+ environment_name = environment["environmentSpec"]["name"]
+ submarine_client.get_environment(environment_name)
+ submarine_client.list_environments()
+ submarine_client.delete_environment(environment_name)
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/EnvironmentRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/EnvironmentRestApi.java
index 6e381c7..ba56383 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/EnvironmentRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/EnvironmentRestApi.java
@@ -67,7 +67,7 @@ public class EnvironmentRestApi {
@ApiResponse(description = "successful operation",
content = @Content(
schema = @Schema(
- implementation = Environment.class)))})
+ implementation = JsonResponse.class)))})
public Response createEnvironment(EnvironmentSpec spec) {
try {
Environment environment = environmentManager.createEnvironment(spec);
@@ -88,12 +88,12 @@ public class EnvironmentRestApi {
@Path("/{id}")
@Consumes({RestConstants.MEDIA_TYPE_YAML, MediaType.APPLICATION_JSON})
@Operation(summary = "Update the environment with job spec",
- tags = {"environments"},
+ tags = {"environment"},
responses = {
@ApiResponse(description = "successful operation",
content = @Content(
schema = @Schema(
- implementation = Environment.class))),
+ implementation = JsonResponse.class))),
@ApiResponse(
responseCode = "404",
description = "Environment not found")})
@@ -118,11 +118,11 @@ public class EnvironmentRestApi {
@DELETE
@Path("/{id}")
@Operation(summary = "Delete the environment",
- tags = {"environments"},
+ tags = {"environment"},
responses = {
@ApiResponse(description = "successful operation",
content = @Content(
- schema = @Schema(implementation = Environment.class))),
+ schema = @Schema(implementation = JsonResponse.class))),
@ApiResponse(
responseCode = "404", description = "Environment not found")})
public Response deleteEnvironment(
@@ -142,12 +142,12 @@ public class EnvironmentRestApi {
*/
@GET
@Operation(summary = "List of Environments",
- tags = {"environments"},
+ tags = {"environment"},
responses = {
@ApiResponse(description = "successful operation",
content = @Content(
schema = @Schema(
- implementation = Environment.class)))})
+ implementation = JsonResponse.class)))})
public Response listEnvironment(@QueryParam("status") String status) {
try {
List<Environment> environmentList =
@@ -171,7 +171,7 @@ public class EnvironmentRestApi {
responses = {
@ApiResponse(description = "successful operation",
content = @Content(
- schema = @Schema(implementation = Environment.class))),
+ schema = @Schema(implementation = JsonResponse.class))),
@ApiResponse(
responseCode = "404",
description = "Environment not found")})
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org