Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions gradient/api_sdk/clients/deployment_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ def create(
deployment_id = repository.create(deployment, use_vpc=use_vpc)
return deployment_id

def get(self, deployment_id):
"""Get deployment instance

:param str deployment_id: Deployment ID

:return: Deployment instance
:rtype: models.Deployment
"""
repository = repositories.GetDeployment(self.api_key, logger=self.logger)
deployment = repository.get(deployment_id=deployment_id)
return deployment

def start(self, deployment_id, use_vpc=False):
"""
Start deployment
Expand Down
2 changes: 1 addition & 1 deletion gradient/api_sdk/repositories/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .deployments import ListDeployments, CreateDeployment, StartDeployment, StopDeployment, DeleteDeployment, \
UpdateDeployment
UpdateDeployment, GetDeployment
from .experiments import ListExperiments, GetExperiment, ListExperimentLogs, StartExperiment, StopExperiment, \
CreateSingleNodeExperiment, CreateMultiNodeExperiment, RunSingleNodeExperiment, RunMultiNodeExperiment, \
CreateMpiMultiNodeExperiment, RunMpiMultiNodeExperiment, DeleteExperiment
Expand Down
27 changes: 26 additions & 1 deletion gradient/api_sdk/repositories/deployments.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .common import ListResources, CreateResource, StartResource, StopResource, DeleteResource, AlterResource
from .common import ListResources, CreateResource, StartResource, StopResource, DeleteResource, AlterResource, \
GetResource
from .. import serializers, config
from ..sdk_exceptions import ResourceFetchingError, MalformedResponseError


class GetBaseDeploymentApiUrlMixin(object):
Expand Down Expand Up @@ -141,3 +143,26 @@ def _get_request_json(self, kwargs):
"upd": kwargs,
}
return j


class GetDeployment(GetBaseDeploymentApiUrlMixin, GetResource):
SERIALIZER_CLS = serializers.DeploymentSchema

def get_request_url(self, **kwargs):
return "/deployments/getDeploymentList/"

def _get_request_json(self, kwargs):
deployment_id = kwargs["deployment_id"]
filter_ = {"where": {"and": [{"id": deployment_id}]}}
json_ = {"filter": filter_}
return json_

def _parse_object(self, instance_dict, **kwargs):
try:
instance_dict = instance_dict["deploymentList"][0]
except KeyError:
raise MalformedResponseError("Malformed response from API")
except IndexError:
raise ResourceFetchingError("Deployment not found")

return super(GetDeployment, self)._parse_object(instance_dict, **kwargs)
4 changes: 4 additions & 0 deletions gradient/api_sdk/sdk_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class ResourceCreatingError(GradientSdkError):
pass


class MalformedResponseError(GradientSdkError):
pass


class ResourceCreatingDataError(ResourceCreatingError):
pass

Expand Down
27 changes: 17 additions & 10 deletions gradient/cli/deployments.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from gradient import exceptions, logger, DEPLOYMENT_TYPES_MAP
from gradient import utils
from gradient.api_sdk import DeploymentsClient, constants
from gradient.api_sdk import DeploymentsClient
from gradient.cli import common
from gradient.cli.cli import cli
from gradient.cli.cli_types import ChoiceType, json_string
Expand All @@ -17,15 +17,6 @@ def deployments():
pass


DEPLOYMENT_MACHINE_TYPES = (
"G1", "G6", "G12",
"K80", "P100", "GV100",
# VPC machine types
"c5.xlarge", "c5.4xlarge", "c5.12xlarge",
"p2.xlarge", "p3.2xlarge", "p3.16xlarge",
)


def get_deployment_client(api_key):
deployment_client = DeploymentsClient(api_key=api_key, logger=logger.Logger())
return deployment_client
Expand Down Expand Up @@ -447,3 +438,19 @@ def update_deployment(deployment_id, api_key, use_vpc, options_file, **kwargs):
deployment_client = get_deployment_client(api_key)
command = deployments_commands.UpdateDeploymentCommand(deployment_client=deployment_client)
command.execute(deployment_id, use_vpc=use_vpc, **kwargs)


@deployments.command("details", help="Get details of model deployment")
@click.option(
"--id",
"deployment_id",
required=True,
help="Deployment ID",
cls=common.GradientOption,
)
@api_key_option
@common.options_file
def get_deployment(deployment_id, api_key, options_file):
deployment_client = get_deployment_client(api_key)
command = deployments_commands.GetDeploymentDetails(deployment_client=deployment_client)
command.execute(deployment_id)
5 changes: 2 additions & 3 deletions gradient/commands/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@

import six
import terminaltables
from gradient import exceptions
from gradient.api_sdk import sdk_exceptions
from halo import halo

from gradient.logger import Logger
from gradient.utils import get_terminal_lines
from halo import halo


@six.add_metaclass(abc.ABCMeta)
Expand Down
38 changes: 30 additions & 8 deletions gradient/commands/deployments.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from halo import halo

from gradient import version, logger as gradient_logger, exceptions
from gradient.api_sdk import sdk_exceptions, utils
from gradient.api_sdk import sdk_exceptions, utils, models
from gradient.api_sdk.clients import http_client
from gradient.api_sdk.config import config
from gradient.api_sdk.utils import urljoin
from gradient.commands.common import DetailsCommandMixin
from gradient.utils import get_terminal_lines

default_headers = {"X-API-Key": config.PAPERSPACE_API_KEY,
Expand All @@ -21,7 +22,7 @@
@six.add_metaclass(abc.ABCMeta)
class _DeploymentCommand(object):
def __init__(self, deployment_client, logger_=gradient_logger.Logger()):
self.deployment_client = deployment_client
self.client = deployment_client
self.logger = logger_

@abc.abstractmethod
Expand All @@ -34,7 +35,7 @@ def execute(self, use_vpc=False, **kwargs):
self._handle_auth(kwargs)

with halo.Halo(text="Creating new deployment", spinner="dots"):
deployment_id = self.deployment_client.create(use_vpc=use_vpc, **kwargs)
deployment_id = self.client.create(use_vpc=use_vpc, **kwargs)

self.logger.log("New deployment created with id: {}".format(deployment_id))
self.logger.log(self.get_instance_url(deployment_id))
Expand Down Expand Up @@ -62,7 +63,7 @@ def execute(self, use_vpc=False, **kwargs):

def _get_instances(self, use_vpc=False, **kwargs):
try:
instances = self.deployment_client.list(use_vpc=use_vpc, **kwargs)
instances = self.client.list(use_vpc=use_vpc, **kwargs)
except sdk_exceptions.GradientSdkError as e:
raise exceptions.ReceivingDataFailedError(e)

Expand Down Expand Up @@ -103,25 +104,46 @@ def _make_table(table_data):

class StartDeploymentCommand(_DeploymentCommand):
def execute(self, use_vpc=False, **kwargs):
self.deployment_client.start(use_vpc=use_vpc, **kwargs)
self.client.start(use_vpc=use_vpc, **kwargs)
self.logger.log("Deployment started")


class StopDeploymentCommand(_DeploymentCommand):
def execute(self, use_vpc=False, **kwargs):
self.deployment_client.stop(use_vpc=use_vpc, **kwargs)
self.client.stop(use_vpc=use_vpc, **kwargs)
self.logger.log("Deployment stopped")


class DeleteDeploymentCommand(_DeploymentCommand):
def execute(self, **kwargs):
self.deployment_client.delete(**kwargs)
self.client.delete(**kwargs)
self.logger.log("Deployment deleted")


class UpdateDeploymentCommand(_DeploymentCommand):
def execute(self, deployment_id, use_vpc=False, **kwargs):
with halo.Halo(text="Updating deployment data", spinner="dots"):
self.deployment_client.update(deployment_id, use_vpc=use_vpc, **kwargs)
self.client.update(deployment_id, use_vpc=use_vpc, **kwargs)

self.logger.log("Deployment data updated")


class GetDeploymentDetails(DetailsCommandMixin, _DeploymentCommand):
def _get_table_data(self, instance):
"""
:param models.Deployment instance:
"""
data = (
("ID", instance.id),
("Name", instance.name),
("State", instance.state),
("Machine type", instance.machine_type),
("Instance count", instance.instance_count),
("Deployment type", instance.deployment_type),
("Model ID", instance.model_id),
("Project ID", instance.project_id),
("Endpoint", instance.endpoint),
("API type", instance.api_type),
("Cluster ID", instance.cluster_id),
)
return data
3 changes: 3 additions & 0 deletions tests/config_files/deployments_details.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apiKey: some_key
id: some_id
vpc: true
7 changes: 7 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ def deployments_delete_config_path():
return str(fixture_dir.resolve())


@pytest.fixture
def deployments_details_config_path():
p = Path(__file__)
fixture_dir = p.parent / "config_files" / "deployments_details.yaml"
return str(fixture_dir.resolve())


@pytest.fixture
def hyperparameters_create_config_path():
p = Path(__file__)
Expand Down
68 changes: 68 additions & 0 deletions tests/example_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -5596,3 +5596,71 @@
"url": "https://ps-projects.s3.amazonaws.com/some/path/model/keton/elo.txt?AWSAccessKeyId=some_aws_access_key_id&Expires=713274132&Signature=tHriojGx03S%2FKkVGQGVI5CQRFTo%3D&response-content-disposition=attachment%3Bfilename%3D%22elo.txt%22&x-amz-security-token=some_amz_security_token"
}
]

GET_DEPLOYMENT_DETAILS_JSON_RESPONSE = {
"deploymentList": [
{
"id": "some_id",
"ownerId": "some_owner_id",
"projectId": "some_project_id",
"experimentId": "some_experiment_id",
"state": "Stopped",
"startedByUserId": "some_user_id",
"startedByUserEmail": "some@address.com",
"deploymentType": "TFServing",
"deploymentTypeDescription": "Tensorflow Serving on K8s",
"modelId": "some_model_id",
"modelUrl": "s3://ps-projects/asdf/some/model/url",
"name": "some_name",
"tag": None,
"params": None,
"code": None,
"cluster": "KPS Jobs",
"clusterId": "some_cluster_id",
"machineType": "p3.2xlarge",
"imageUrl": "tensorflow/serving",
"imageUsername": None,
"imagePassword": None,
"imageServer": None,
"workspaceUrl": None,
"workspaceUsername": None,
"workspacePassword": None,
"instanceCount": 1,
"runningCount": 0,
"error": None,
"authToken": None,
"annotations": {},
"oauthKey": None,
"oauthSecret": None,
"serviceType": "model",
"apiType": "REST",
"endpoint": "https://paperspace.io/model-serving/some_id:predict",
"ports": None,
"dtCreated": "2020-01-13T22:21:28.210Z",
"dtModified": "2020-01-14T00:32:27.577Z",
"dtBuildStarted": "2020-01-13T22:21:28.482Z",
"dtBuildFinished": None,
"dtProvisioningStarted": None,
"dtProvisioningFinished": None,
"dtStarted": None,
"dtTeardownStarted": None,
"dtTeardownFinished": None,
"dtStopped": "2020-01-13T22:48:40.107Z",
"dtDeleted": None,
"isDeleted": False,
"modelType": "Tensorflow",
"modelPath": None,
"command": None,
"args": None,
"env": None,
"containerModelPath": None,
"containerUrlPath": None,
"endpointUrlPath": None,
"method": None,
"tags": None
}
],
"total": 129,
"displayTotal": 129,
"runningTotal": 0
}
Loading