proximl 0.5.8__tar.gz → 0.5.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {proximl-0.5.8/proximl.egg-info → proximl-0.5.10}/PKG-INFO +1 -1
- {proximl-0.5.8 → proximl-0.5.10}/proximl/__init__.py +1 -1
- {proximl-0.5.8 → proximl-0.5.10}/proximl/checkpoints.py +14 -3
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/datastore.py +2 -7
- proximl-0.5.8/proximl/cli/project.py → proximl-0.5.10/proximl/cli/project/__init__.py +4 -0
- proximl-0.5.10/proximl/cli/project/key.py +124 -0
- proximl-0.5.10/proximl/cli/project/secret.py +71 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/data_connectors.py +8 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/datastores.py +9 -19
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/nodes.py +45 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/datasets.py +14 -3
- {proximl-0.5.8 → proximl-0.5.10}/proximl/jobs.py +2 -13
- {proximl-0.5.8 → proximl-0.5.10}/proximl/models.py +14 -3
- proximl-0.5.10/proximl/projects/__init__.py +3 -0
- proximl-0.5.10/proximl/projects/data_connectors.py +63 -0
- proximl-0.5.10/proximl/projects/datastores.py +58 -0
- proximl-0.5.10/proximl/projects/keys.py +71 -0
- proximl-0.5.10/proximl/projects/projects.py +83 -0
- proximl-0.5.10/proximl/projects/secrets.py +70 -0
- proximl-0.5.10/proximl/projects/services.py +63 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/volumes.py +15 -3
- {proximl-0.5.8 → proximl-0.5.10/proximl.egg-info}/PKG-INFO +1 -1
- {proximl-0.5.8 → proximl-0.5.10}/proximl.egg-info/SOURCES.txt +25 -7
- proximl-0.5.10/tests/integration/projects/conftest.py +8 -0
- {proximl-0.5.8/tests/integration → proximl-0.5.10/tests/integration/projects}/test_projects_integration.py +0 -6
- proximl-0.5.10/tests/integration/projects/test_projects_keys_integration.py +43 -0
- proximl-0.5.10/tests/integration/projects/test_projects_secrets_integration.py +44 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_checkpoints_integration.py +0 -1
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_models_integration.py +0 -1
- proximl-0.5.10/tests/unit/cloudbender/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_datastores_unit.py +1 -5
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/conftest.py +72 -2
- proximl-0.5.10/tests/unit/projects/__init__.py +0 -0
- proximl-0.5.10/tests/unit/projects/test_project_data_connectors_unit.py +102 -0
- proximl-0.5.10/tests/unit/projects/test_project_datastores_unit.py +96 -0
- proximl-0.5.10/tests/unit/projects/test_project_keys_unit.py +96 -0
- proximl-0.5.10/tests/unit/projects/test_project_secrets_unit.py +101 -0
- proximl-0.5.10/tests/unit/projects/test_project_services_unit.py +102 -0
- proximl-0.5.10/tests/unit/projects/test_projects_unit.py +128 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_checkpoints_unit.py +15 -23
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_datasets_unit.py +15 -20
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_models_unit.py +13 -16
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_volumes_unit.py +3 -0
- proximl-0.5.8/proximl/projects.py +0 -228
- proximl-0.5.8/tests/unit/test_projects_unit.py +0 -320
- {proximl-0.5.8 → proximl-0.5.10}/LICENSE +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/README.md +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/examples/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/examples/create_dataset_and_training_job.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/examples/local_storage.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/examples/training_inference_pipeline.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/__main__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/auth.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/checkpoint.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/data_connector.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/device.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/node.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/provider.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/region.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/cloudbender/service.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/connection.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/dataset.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/environment.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/gpu.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/job/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/job/create.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/model.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cli/volume.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/cloudbender.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/device_configs.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/devices.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/providers.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/regions.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/cloudbender/services.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/connections.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/environments.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/exceptions.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/gpu_types.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl/proximl.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl.egg-info/dependency_links.txt +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl.egg-info/entry_points.txt +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl.egg-info/requires.txt +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/proximl.egg-info/top_level.txt +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/pyproject.toml +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/setup.cfg +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/setup.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/cloudbender/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/cloudbender/test_providers_integration.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/conftest.py +0 -0
- {proximl-0.5.8/tests/unit → proximl-0.5.10/tests/integration/projects}/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_datasets_integration.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_environments_integration.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_gpu_types_integration.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_jobs_integration.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/integration/test_volumes_integration.py +0 -0
- {proximl-0.5.8/tests/unit/cli → proximl-0.5.10/tests/unit}/__init__.py +0 -0
- {proximl-0.5.8/tests/unit/cli/cloudbender → proximl-0.5.10/tests/unit/cli}/__init__.py +0 -0
- {proximl-0.5.8/tests/unit → proximl-0.5.10/tests/unit/cli}/cloudbender/__init__.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/cloudbender/test_cli_datastore_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/cloudbender/test_cli_device_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/cloudbender/test_cli_node_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/cloudbender/test_cli_provider_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/cloudbender/test_cli_region_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/cloudbender/test_cli_service_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/conftest.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_checkpoint_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_datasets_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_environment_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_gpu_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_job_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_model_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_project_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cli/test_cli_volume_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_data_connectors_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_device_configs_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_devices_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_nodes_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_providers_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_regions_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/cloudbender/test_services_unit.py +0 -0
- /proximl-0.5.8/tests/unit/test_auth.py → /proximl-0.5.10/tests/unit/test_auth_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_connections_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_environments_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_exceptions.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_gpu_types_unit.py +0 -0
- {proximl-0.5.8 → proximl-0.5.10}/tests/unit/test_jobs_unit.py +0 -0
- /proximl-0.5.8/tests/unit/test_proximl.py → /proximl-0.5.10/tests/unit/test_proximl_unit.py +0 -0
|
@@ -31,13 +31,24 @@ class Checkpoints(object):
|
|
|
31
31
|
datasets = [Checkpoint(self.proximl, **dataset) for dataset in resp]
|
|
32
32
|
return datasets
|
|
33
33
|
|
|
34
|
-
async def create(
|
|
34
|
+
async def create(
|
|
35
|
+
self,
|
|
36
|
+
name,
|
|
37
|
+
source_type,
|
|
38
|
+
source_uri,
|
|
39
|
+
type="evefs",
|
|
40
|
+
project_uuid=None,
|
|
41
|
+
**kwargs,
|
|
42
|
+
):
|
|
43
|
+
if not project_uuid:
|
|
44
|
+
project_uuid = self.proximl.active_project
|
|
35
45
|
data = dict(
|
|
36
46
|
name=name,
|
|
37
47
|
source_type=source_type,
|
|
38
48
|
source_uri=source_uri,
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
project_uuid=project_uuid,
|
|
50
|
+
type=type,
|
|
51
|
+
**kwargs,
|
|
41
52
|
)
|
|
42
53
|
payload = {k: v for k, v in data.items() if v is not None}
|
|
43
54
|
logging.info(f"Creating Checkpoint {name}")
|
|
@@ -29,13 +29,11 @@ def datastore(config):
|
|
|
29
29
|
def list(config, provider, region):
|
|
30
30
|
"""List datastores."""
|
|
31
31
|
data = [
|
|
32
|
-
["ID", "NAME", "TYPE"
|
|
32
|
+
["ID", "NAME", "TYPE"],
|
|
33
33
|
[
|
|
34
34
|
"-" * 80,
|
|
35
35
|
"-" * 80,
|
|
36
36
|
"-" * 80,
|
|
37
|
-
"-" * 80,
|
|
38
|
-
"-" * 80,
|
|
39
37
|
],
|
|
40
38
|
]
|
|
41
39
|
|
|
@@ -51,15 +49,12 @@ def list(config, provider, region):
|
|
|
51
49
|
datastore.id,
|
|
52
50
|
datastore.name,
|
|
53
51
|
datastore.type,
|
|
54
|
-
datastore.uri,
|
|
55
|
-
datastore.root,
|
|
56
52
|
]
|
|
57
53
|
)
|
|
58
54
|
|
|
59
55
|
for row in data:
|
|
60
56
|
click.echo(
|
|
61
|
-
"{: >37.36} {: >29.28} {: >9.8}
|
|
62
|
-
"".format(*row),
|
|
57
|
+
"{: >37.36} {: >29.28} {: >9.8} " "".format(*row),
|
|
63
58
|
file=config.stdout,
|
|
64
59
|
)
|
|
65
60
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
import base64
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from proximl.cli import pass_config
|
|
7
|
+
from proximl.cli.project import project
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@project.group()
|
|
11
|
+
@pass_config
|
|
12
|
+
def key(config):
|
|
13
|
+
"""proxiML project key commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@key.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List keys."""
|
|
21
|
+
data = [
|
|
22
|
+
["TYPE", "KEY ID", "UPDATED AT"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
],
|
|
28
|
+
]
|
|
29
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
30
|
+
keys = config.proximl.run(project.keys.list())
|
|
31
|
+
|
|
32
|
+
for key in keys:
|
|
33
|
+
data.append(
|
|
34
|
+
[
|
|
35
|
+
key.type,
|
|
36
|
+
key.key_id,
|
|
37
|
+
key.updated_at.isoformat(timespec="seconds"),
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
for row in data:
|
|
42
|
+
click.echo(
|
|
43
|
+
"{: >13.11} {: >37.35} {: >28.26}" "".format(*row),
|
|
44
|
+
file=config.stdout,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@key.command()
|
|
49
|
+
@click.argument(
|
|
50
|
+
"type",
|
|
51
|
+
type=click.Choice(
|
|
52
|
+
[
|
|
53
|
+
"aws",
|
|
54
|
+
"azure",
|
|
55
|
+
"docker",
|
|
56
|
+
"gcp",
|
|
57
|
+
"huggingface",
|
|
58
|
+
"kaggle",
|
|
59
|
+
"ngc",
|
|
60
|
+
"wasabi",
|
|
61
|
+
],
|
|
62
|
+
case_sensitive=False,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
@pass_config
|
|
66
|
+
def put(config, type):
|
|
67
|
+
"""
|
|
68
|
+
Set a key.
|
|
69
|
+
|
|
70
|
+
A key is uploaded.
|
|
71
|
+
"""
|
|
72
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
73
|
+
|
|
74
|
+
tenant = None
|
|
75
|
+
|
|
76
|
+
if type in ["aws", "wasabi"]:
|
|
77
|
+
key_id = click.prompt("Enter the key ID", type=str, hide_input=False)
|
|
78
|
+
secret = click.prompt("Enter the secret key", type=str, hide_input=True)
|
|
79
|
+
elif type == "azure":
|
|
80
|
+
key_id = click.prompt(
|
|
81
|
+
"Enter the Application (client) ID", type=str, hide_input=False
|
|
82
|
+
)
|
|
83
|
+
tenant = click.prompt(
|
|
84
|
+
"Enter the Directory (tenant) ley", type=str, hide_input=False
|
|
85
|
+
)
|
|
86
|
+
secret = click.prompt("Enter the client secret", type=str, hide_input=True)
|
|
87
|
+
elif type in ["docker", "huggingface"]:
|
|
88
|
+
key_id = click.prompt("Enter the username", type=str, hide_input=False)
|
|
89
|
+
secret = click.prompt("Enter the access token", type=str, hide_input=True)
|
|
90
|
+
elif type in ["gcp", "kaggle"]:
|
|
91
|
+
file_name = click.prompt(
|
|
92
|
+
"Enter the path of the credentials file",
|
|
93
|
+
type=click.Path(
|
|
94
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True
|
|
95
|
+
),
|
|
96
|
+
hide_input=False,
|
|
97
|
+
)
|
|
98
|
+
key_id = os.path.basename(file_name)
|
|
99
|
+
with open(file_name) as f:
|
|
100
|
+
secret = json.load(f)
|
|
101
|
+
secret = json.dumps(secret)
|
|
102
|
+
elif type == "ngc":
|
|
103
|
+
key_id = "$oauthtoken"
|
|
104
|
+
secret = click.prompt("Enter the access token", type=str, hide_input=True)
|
|
105
|
+
else:
|
|
106
|
+
raise click.UsageError("Unsupported key type")
|
|
107
|
+
|
|
108
|
+
return config.proximl.run(
|
|
109
|
+
project.keys.put(type=type, key_id=key_id, secret=secret, tenant=tenant)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@key.command()
|
|
114
|
+
@click.argument("name", type=click.STRING)
|
|
115
|
+
@pass_config
|
|
116
|
+
def remove(config, name):
|
|
117
|
+
"""
|
|
118
|
+
Remove a key.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
"""
|
|
122
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
123
|
+
|
|
124
|
+
return config.proximl.run(project.key.remove(name))
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from proximl.cli import pass_config
|
|
3
|
+
from proximl.cli.project import project
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@project.group()
|
|
7
|
+
@pass_config
|
|
8
|
+
def secret(config):
|
|
9
|
+
"""proxiML project secret commands."""
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@secret.command()
|
|
14
|
+
@pass_config
|
|
15
|
+
def list(config):
|
|
16
|
+
"""List secrets."""
|
|
17
|
+
data = [
|
|
18
|
+
["NAME", "CREATED BY", "UPDATED AT"],
|
|
19
|
+
[
|
|
20
|
+
"-" * 80,
|
|
21
|
+
"-" * 80,
|
|
22
|
+
"-" * 80,
|
|
23
|
+
],
|
|
24
|
+
]
|
|
25
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
26
|
+
secrets = config.proximl.run(project.secrets.list())
|
|
27
|
+
|
|
28
|
+
for secret in secrets:
|
|
29
|
+
data.append(
|
|
30
|
+
[
|
|
31
|
+
secret.name,
|
|
32
|
+
secret.created_by,
|
|
33
|
+
secret.updated_at.isoformat(timespec="seconds"),
|
|
34
|
+
]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
for row in data:
|
|
38
|
+
click.echo(
|
|
39
|
+
"{: >38.36} {: >30.28} {: >28.26}" "".format(*row),
|
|
40
|
+
file=config.stdout,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@secret.command()
|
|
45
|
+
@click.argument("name", type=click.STRING)
|
|
46
|
+
@pass_config
|
|
47
|
+
def put(config, name):
|
|
48
|
+
"""
|
|
49
|
+
Set a secret value.
|
|
50
|
+
|
|
51
|
+
Secret is created with the specified NAME.
|
|
52
|
+
"""
|
|
53
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
54
|
+
|
|
55
|
+
value = click.prompt("Enter the secret value", type=str, hide_input=True)
|
|
56
|
+
|
|
57
|
+
return config.proximl.run(project.secrets.put(name=name, value=value))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@secret.command()
|
|
61
|
+
@click.argument("name", type=click.STRING)
|
|
62
|
+
@pass_config
|
|
63
|
+
def remove(config, name):
|
|
64
|
+
"""
|
|
65
|
+
Remove a secret.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
70
|
+
|
|
71
|
+
return config.proximl.run(project.secret.remove(name))
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import asyncio
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
from proximl.exceptions import (
|
|
7
|
+
ApiError,
|
|
8
|
+
SpecificationError,
|
|
9
|
+
ProxiMLException,
|
|
10
|
+
)
|
|
3
11
|
|
|
4
12
|
|
|
5
13
|
class Datastores(object):
|
|
@@ -20,9 +28,7 @@ class Datastores(object):
|
|
|
20
28
|
"GET",
|
|
21
29
|
kwargs,
|
|
22
30
|
)
|
|
23
|
-
datastores = [
|
|
24
|
-
Datastore(self.proximl, **datastore) for datastore in resp
|
|
25
|
-
]
|
|
31
|
+
datastores = [Datastore(self.proximl, **datastore) for datastore in resp]
|
|
26
32
|
return datastores
|
|
27
33
|
|
|
28
34
|
async def create(
|
|
@@ -31,18 +37,12 @@ class Datastores(object):
|
|
|
31
37
|
region_uuid,
|
|
32
38
|
name,
|
|
33
39
|
type,
|
|
34
|
-
uri,
|
|
35
|
-
root,
|
|
36
|
-
options=None,
|
|
37
40
|
**kwargs,
|
|
38
41
|
):
|
|
39
42
|
logging.info(f"Creating Datastore {name}")
|
|
40
43
|
data = dict(
|
|
41
44
|
name=name,
|
|
42
45
|
type=type,
|
|
43
|
-
uri=uri,
|
|
44
|
-
root=root,
|
|
45
|
-
options=options,
|
|
46
46
|
**kwargs,
|
|
47
47
|
)
|
|
48
48
|
payload = {k: v for k, v in data.items() if v is not None}
|
|
@@ -73,8 +73,6 @@ class Datastore:
|
|
|
73
73
|
self._region_uuid = self._datastore.get("region_uuid")
|
|
74
74
|
self._type = self._datastore.get("type")
|
|
75
75
|
self._name = self._datastore.get("name")
|
|
76
|
-
self._uri = self._datastore.get("uri")
|
|
77
|
-
self._root = self._datastore.get("root")
|
|
78
76
|
|
|
79
77
|
@property
|
|
80
78
|
def id(self) -> str:
|
|
@@ -96,14 +94,6 @@ class Datastore:
|
|
|
96
94
|
def name(self) -> str:
|
|
97
95
|
return self._name
|
|
98
96
|
|
|
99
|
-
@property
|
|
100
|
-
def uri(self) -> str:
|
|
101
|
-
return self._uri
|
|
102
|
-
|
|
103
|
-
@property
|
|
104
|
-
def root(self) -> str:
|
|
105
|
-
return self._root
|
|
106
|
-
|
|
107
97
|
def __str__(self):
|
|
108
98
|
return json.dumps({k: v for k, v in self._datastore.items()})
|
|
109
99
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import asyncio
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
from proximl.exceptions import (
|
|
7
|
+
ApiError,
|
|
8
|
+
SpecificationError,
|
|
9
|
+
ProxiMLException,
|
|
10
|
+
)
|
|
3
11
|
|
|
4
12
|
|
|
5
13
|
class Nodes(object):
|
|
@@ -153,3 +161,40 @@ class Node:
|
|
|
153
161
|
None,
|
|
154
162
|
dict(command=command),
|
|
155
163
|
)
|
|
164
|
+
|
|
165
|
+
async def wait_for(self, status, timeout=300):
|
|
166
|
+
if self.status == status:
|
|
167
|
+
return
|
|
168
|
+
valid_statuses = ["active", "maintenance", "offline", "stopped", "archived"]
|
|
169
|
+
if not status in valid_statuses:
|
|
170
|
+
raise SpecificationError(
|
|
171
|
+
"status",
|
|
172
|
+
f"Invalid wait_for status {status}. Valid statuses are: {valid_statuses}",
|
|
173
|
+
)
|
|
174
|
+
MAX_TIMEOUT = 24 * 60 * 60
|
|
175
|
+
if timeout > MAX_TIMEOUT:
|
|
176
|
+
raise SpecificationError(
|
|
177
|
+
"timeout",
|
|
178
|
+
f"timeout must be less than {MAX_TIMEOUT} seconds.",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
POLL_INTERVAL_MIN = 5
|
|
182
|
+
POLL_INTERVAL_MAX = 60
|
|
183
|
+
POLL_INTERVAL = max(min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN)
|
|
184
|
+
retry_count = math.ceil(timeout / POLL_INTERVAL)
|
|
185
|
+
count = 0
|
|
186
|
+
while count < retry_count:
|
|
187
|
+
await asyncio.sleep(POLL_INTERVAL)
|
|
188
|
+
try:
|
|
189
|
+
await self.refresh()
|
|
190
|
+
except ApiError as e:
|
|
191
|
+
if status == "archived" and e.status == 404:
|
|
192
|
+
return
|
|
193
|
+
raise e
|
|
194
|
+
if self.status == status:
|
|
195
|
+
return self
|
|
196
|
+
else:
|
|
197
|
+
count += 1
|
|
198
|
+
logging.debug(f"self: {self}, retry count {count}")
|
|
199
|
+
|
|
200
|
+
raise ProxiMLException(f"Timeout waiting for {status}")
|
|
@@ -31,13 +31,24 @@ class Datasets(object):
|
|
|
31
31
|
datasets = [Dataset(self.proximl, **dataset) for dataset in resp]
|
|
32
32
|
return datasets
|
|
33
33
|
|
|
34
|
-
async def create(
|
|
34
|
+
async def create(
|
|
35
|
+
self,
|
|
36
|
+
name,
|
|
37
|
+
source_type,
|
|
38
|
+
source_uri,
|
|
39
|
+
type="evefs",
|
|
40
|
+
project_uuid=None,
|
|
41
|
+
**kwargs,
|
|
42
|
+
):
|
|
43
|
+
if not project_uuid:
|
|
44
|
+
project_uuid = self.proximl.active_project
|
|
35
45
|
data = dict(
|
|
36
46
|
name=name,
|
|
37
47
|
source_type=source_type,
|
|
38
48
|
source_uri=source_uri,
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
project_uuid=project_uuid,
|
|
50
|
+
type=type,
|
|
51
|
+
**kwargs,
|
|
41
52
|
)
|
|
42
53
|
payload = {k: v for k, v in data.items() if v is not None}
|
|
43
54
|
logging.info(f"Creating Dataset {name}")
|
|
@@ -476,7 +476,6 @@ class Job:
|
|
|
476
476
|
return
|
|
477
477
|
valid_statuses = [
|
|
478
478
|
"waiting for data/model download",
|
|
479
|
-
"waiting for GPUs",
|
|
480
479
|
"waiting for resources",
|
|
481
480
|
"running",
|
|
482
481
|
"stopped",
|
|
@@ -488,11 +487,6 @@ class Job:
|
|
|
488
487
|
"status",
|
|
489
488
|
f"Invalid wait_for status {status}. Valid statuses are: {valid_statuses}",
|
|
490
489
|
)
|
|
491
|
-
if status == "waiting for GPUs":
|
|
492
|
-
warnings.warn(
|
|
493
|
-
"'waiting for GPUs' status is deprecated, use 'waiting for resources' instead.",
|
|
494
|
-
DeprecationWarning,
|
|
495
|
-
)
|
|
496
490
|
if (self.type == "training") and status == "stopped":
|
|
497
491
|
warnings.warn(
|
|
498
492
|
"'stopped' status is deprecated for training jobs, use 'finished' instead.",
|
|
@@ -523,12 +517,8 @@ class Job:
|
|
|
523
517
|
self.status == status
|
|
524
518
|
or (
|
|
525
519
|
status
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
"waiting for resources",
|
|
529
|
-
] ## this status could be very short and the polling could miss it
|
|
530
|
-
and self.status
|
|
531
|
-
not in ["new", "waiting for GPUs", "waiting for resources"]
|
|
520
|
+
== "waiting for resources" ## this status could be very short and the polling could miss it
|
|
521
|
+
and self.status not in ["new", "waiting for resources"]
|
|
532
522
|
)
|
|
533
523
|
or (
|
|
534
524
|
status
|
|
@@ -536,7 +526,6 @@ class Job:
|
|
|
536
526
|
and self.status
|
|
537
527
|
not in [
|
|
538
528
|
"new",
|
|
539
|
-
"waiting for GPUs",
|
|
540
529
|
"waiting for resources",
|
|
541
530
|
"waiting for data/model download",
|
|
542
531
|
]
|
|
@@ -26,13 +26,24 @@ class Models(object):
|
|
|
26
26
|
models = [Model(self.proximl, **model) for model in resp]
|
|
27
27
|
return models
|
|
28
28
|
|
|
29
|
-
async def create(
|
|
29
|
+
async def create(
|
|
30
|
+
self,
|
|
31
|
+
name,
|
|
32
|
+
source_type,
|
|
33
|
+
source_uri,
|
|
34
|
+
type="evefs",
|
|
35
|
+
project_uuid=None,
|
|
36
|
+
**kwargs,
|
|
37
|
+
):
|
|
38
|
+
if not project_uuid:
|
|
39
|
+
project_uuid = self.proximl.active_project
|
|
30
40
|
data = dict(
|
|
31
41
|
name=name,
|
|
32
42
|
source_type=source_type,
|
|
33
43
|
source_uri=source_uri,
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
project_uuid=project_uuid,
|
|
45
|
+
type=type,
|
|
46
|
+
**kwargs,
|
|
36
47
|
)
|
|
37
48
|
payload = {k: v for k, v in data.items() if v is not None}
|
|
38
49
|
logging.info(f"Creating Model {name}")
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ProjectDataConnectors(object):
|
|
6
|
+
def __init__(self, proximl, project_id):
|
|
7
|
+
self.proximl = proximl
|
|
8
|
+
self.project_id = project_id
|
|
9
|
+
|
|
10
|
+
async def list(self, **kwargs):
|
|
11
|
+
resp = await self.proximl._query(
|
|
12
|
+
f"/project/{self.project_id}/data_connectors", "GET", kwargs
|
|
13
|
+
)
|
|
14
|
+
data_connectors = [
|
|
15
|
+
ProjectDataConnector(self.proximl, **data_connector)
|
|
16
|
+
for data_connector in resp
|
|
17
|
+
]
|
|
18
|
+
return data_connectors
|
|
19
|
+
|
|
20
|
+
async def refresh(self):
|
|
21
|
+
await self.proximl._query(
|
|
22
|
+
f"/project/{self.project_id}/data_connectors", "PATCH"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ProjectDataConnector:
|
|
27
|
+
def __init__(self, proximl, **kwargs):
|
|
28
|
+
self.proximl = proximl
|
|
29
|
+
self._entity = kwargs
|
|
30
|
+
self._id = self._entity.get("id")
|
|
31
|
+
self._project_uuid = self._entity.get("project_uuid")
|
|
32
|
+
self._name = self._entity.get("name")
|
|
33
|
+
self._type = self._entity.get("type")
|
|
34
|
+
self._region_uuid = self._entity.get("region_uuid")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def id(self) -> str:
|
|
38
|
+
return self._id
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def project_uuid(self) -> str:
|
|
42
|
+
return self._project_uuid
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def name(self) -> str:
|
|
46
|
+
return self._name
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def type(self) -> str:
|
|
50
|
+
return self._type
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def region_uuid(self) -> str:
|
|
54
|
+
return self._region_uuid
|
|
55
|
+
|
|
56
|
+
def __str__(self):
|
|
57
|
+
return json.dumps({k: v for k, v in self._entity.items()})
|
|
58
|
+
|
|
59
|
+
def __repr__(self):
|
|
60
|
+
return f"ProjectDataConnector( proximl , **{self._entity.__repr__()})"
|
|
61
|
+
|
|
62
|
+
def __bool__(self):
|
|
63
|
+
return bool(self._id)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ProjectDatastores(object):
|
|
6
|
+
def __init__(self, proximl, project_id):
|
|
7
|
+
self.proximl = proximl
|
|
8
|
+
self.project_id = project_id
|
|
9
|
+
|
|
10
|
+
async def list(self, **kwargs):
|
|
11
|
+
resp = await self.proximl._query(
|
|
12
|
+
f"/project/{self.project_id}/datastores", "GET", kwargs
|
|
13
|
+
)
|
|
14
|
+
datastores = [ProjectDatastore(self.proximl, **datastore) for datastore in resp]
|
|
15
|
+
return datastores
|
|
16
|
+
|
|
17
|
+
async def refresh(self):
|
|
18
|
+
await self.proximl._query(f"/project/{self.project_id}/datastores", "PATCH")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProjectDatastore:
|
|
22
|
+
def __init__(self, proximl, **kwargs):
|
|
23
|
+
self.proximl = proximl
|
|
24
|
+
self._entity = kwargs
|
|
25
|
+
self._id = self._entity.get("id")
|
|
26
|
+
self._project_uuid = self._entity.get("project_uuid")
|
|
27
|
+
self._name = self._entity.get("name")
|
|
28
|
+
self._type = self._entity.get("type")
|
|
29
|
+
self._region_uuid = self._entity.get("region_uuid")
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def id(self) -> str:
|
|
33
|
+
return self._id
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def project_uuid(self) -> str:
|
|
37
|
+
return self._project_uuid
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def name(self) -> str:
|
|
41
|
+
return self._name
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def type(self) -> str:
|
|
45
|
+
return self._type
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def region_uuid(self) -> str:
|
|
49
|
+
return self._region_uuid
|
|
50
|
+
|
|
51
|
+
def __str__(self):
|
|
52
|
+
return json.dumps({k: v for k, v in self._entity.items()})
|
|
53
|
+
|
|
54
|
+
def __repr__(self):
|
|
55
|
+
return f"ProjectDatastore( proximl , **{self._entity.__repr__()})"
|
|
56
|
+
|
|
57
|
+
def __bool__(self):
|
|
58
|
+
return bool(self._id)
|