Skip to content

Commit ddd700d

Browse files
Merge pull request #229 from Paperspace/PS-12943
Ps 12943
2 parents 2b57657 + 19fdb0b commit ddd700d

File tree

13 files changed

+355
-1
lines changed

13 files changed

+355
-1
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from gradient.api_sdk import repositories
2+
3+
from gradient.api_sdk.clients.base_client import BaseClient
4+
5+
6+
class ClustersClient(BaseClient):
7+
def list(self, limit=11, offset=0, **kwargs):
8+
"""
9+
Get a list of clusters for your team
10+
11+
:param int limit: how many element to return on request
12+
:param int offset: from what position we should return clusters
13+
14+
:return: clusters
15+
:rtype: list
16+
"""
17+
repository = repositories.ListClusters(api_key=self.api_key, logger=self.logger)
18+
clusters = repository.list(limit=limit, offset=offset)
19+
return clusters

gradient/api_sdk/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .artifact import Artifact
2+
from .cluster import Cluster
23
from .dataset import Dataset
34
from .deployment import Deployment
45
from .experiment import BaseExperiment, MultiNodeExperiment, SingleNodeExperiment, MpiMultiNodeExperiment

gradient/api_sdk/models/cluster.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import attr
2+
3+
4+
@attr.s
5+
class Cluster(object):
6+
id = attr.ib(type=str, default=None)
7+
name = attr.ib(type=str, default=None)
8+
type = attr.ib(type=str, default=None)

gradient/api_sdk/repositories/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .clusters import ListClusters
12
from .deployments import ListDeployments, CreateDeployment, StartDeployment, StopDeployment, DeleteDeployment, \
23
UpdateDeployment, GetDeployment
34
from .experiments import ListExperiments, GetExperiment, ListExperimentLogs, StartExperiment, StopExperiment, \

gradient/api_sdk/repositories/clusters.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import json
2+
from collections import OrderedDict
3+
14
from gradient.api_sdk.config import config
2-
from gradient.api_sdk.repositories.common import GetResource
5+
from gradient.api_sdk.repositories.common import GetResource, ListResources
36
from gradient.api_sdk.sdk_exceptions import MalformedResponseError
47
from gradient.api_sdk.serializers.cluster import ClusterSchema
58

@@ -27,3 +30,26 @@ def _parse_object(self, instance_dict, **kwargs):
2730
if instance.errors:
2831
raise MalformedResponseError(instance.errors)
2932
return instance.data
33+
34+
35+
class ListClusters(ListResources):
36+
SERIALIZER_CLS = ClusterSchema
37+
38+
def get_request_url(self, **kwargs):
39+
return "/clusters/getClusters"
40+
41+
def _get_api_url(self, **kwargs):
42+
return config.CONFIG_HOST
43+
44+
def _get_request_params(self, kwargs):
45+
filter = OrderedDict({
46+
"limit": kwargs.get("limit"),
47+
"offset": kwargs.get("offset"),
48+
})
49+
filter["where"] = {
50+
"isPrivate": True
51+
}
52+
53+
return {
54+
"filter": json.dumps(OrderedDict(filter))
55+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import marshmallow as ma
22

3+
from gradient.api_sdk import models
34
from gradient.api_sdk.serializers.base import BaseSchema
45

56

67
class ClusterSchema(BaseSchema):
8+
MODEL = models.Cluster
79
id = ma.fields.String()
810
name = ma.fields.String()
911
type = ma.fields.String()

gradient/cli/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from click._compat import get_text_stderr
44

55
import gradient.cli.auth
6+
import gradient.cli.clusters
67
import gradient.cli.deployments
78
import gradient.cli.experiments
89
import gradient.cli.hyperparameters

gradient/cli/clusters.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import click
2+
3+
from gradient.api_sdk.clients.clusters import ClustersClient
4+
from gradient.cli import common
5+
from gradient.cli.cli import cli
6+
from gradient.cli.common import ClickGroup, api_key_option
7+
from gradient.commands.clusters import ListClustersCommand
8+
9+
10+
def get_clusters_client(api_key):
11+
client = ClustersClient(api_key=api_key)
12+
return client
13+
14+
15+
@cli.group("clusters", help="Manage clusters", cls=ClickGroup)
16+
def clusters():
17+
pass
18+
19+
@clusters.command("list", help="List your team clusters")
20+
@click.option(
21+
"--limit",
22+
"-l",
23+
"cluster_limit",
24+
default=20,
25+
help="Limit listed experiments per page",
26+
cls=common.GradientOption,
27+
)
28+
@click.option(
29+
"--offset",
30+
"-o",
31+
"cluster_offset",
32+
default=0,
33+
cls=common.GradientOption,
34+
)
35+
@api_key_option
36+
@common.options_file
37+
def get_clusters_list(api_key, cluster_limit, cluster_offset, options_file):
38+
command = ListClustersCommand(cluster_client=get_clusters_client(api_key))
39+
40+
res = command.execute(limit=cluster_limit, offset=cluster_offset)
41+
42+
for cluster_str, next_iteration in res:
43+
click.echo(cluster_str)
44+
if next_iteration:
45+
click.confirm("Do you want to continue?", abort=True)

gradient/commands/clusters.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import abc
2+
3+
import six
4+
from halo import halo
5+
6+
from gradient import clilogger as gradient_logger, exceptions
7+
from gradient.api_sdk import sdk_exceptions
8+
from gradient.commands.common import ListCommandMixin
9+
10+
11+
@six.add_metaclass(abc.ABCMeta)
12+
class _ClustersCommand(object):
13+
def __init__(self, cluster_client, logger_=gradient_logger.CliLogger()):
14+
self.client = cluster_client
15+
self.logger = logger_
16+
17+
@abc.abstractmethod
18+
def execute(self, **kwargs):
19+
pass
20+
21+
22+
class ListClustersCommand(ListCommandMixin, _ClustersCommand):
23+
WAITING_FOR_RESPONSE_MESSAGE = "Waiting for data..."
24+
25+
def execute(self, **kwargs):
26+
return self._generate_data_table(**kwargs)
27+
28+
def _get_instances(self, **kwargs):
29+
try:
30+
instances= self.client.list(**kwargs)
31+
except sdk_exceptions.GradientSdkError as e:
32+
raise exceptions.ReceivingDataFailedError(e)
33+
34+
return instances
35+
36+
def _get_table_data(self, objects):
37+
data = [("ID", "Name", "Type")]
38+
39+
for cluster in objects:
40+
handle = cluster.id
41+
name = cluster.name
42+
type = cluster.type
43+
data.append((handle, name, type))
44+
return data
45+
46+
def _generate_data_table(self, **kwargs):
47+
limit = kwargs.get("limit")
48+
offset = kwargs.get("offset")
49+
next_iteration = True
50+
51+
while next_iteration:
52+
with halo.Halo(text=self.WAITING_FOR_RESPONSE_MESSAGE, spinner="dots"):
53+
kwargs["offset"] = offset
54+
instances = self._get_instances(
55+
**kwargs
56+
)
57+
if instances:
58+
table_data = self._get_table_data(instances)
59+
table_str = self._make_list_table(table_data) + "\n"
60+
else:
61+
table_str = "No data found"
62+
63+
if len(instances) < limit:
64+
next_iteration = False
65+
66+
yield table_str, next_iteration
67+
offset += limit
68+
69+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
apiKey: some_key
2+
limit: 2

0 commit comments

Comments
 (0)