proximl 0.5.10__tar.gz → 0.5.11__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.10/proximl.egg-info → proximl-0.5.11}/PKG-INFO +1 -1
- {proximl-0.5.10 → proximl-0.5.11}/proximl/__init__.py +1 -1
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/project/__init__.py +3 -72
- proximl-0.5.11/proximl/cli/project/data_connector.py +61 -0
- proximl-0.5.11/proximl/cli/project/datastore.py +61 -0
- proximl-0.5.11/proximl/cli/project/service.py +61 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/nodes.py +4 -6
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/providers.py +53 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/regions.py +48 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/exceptions.py +51 -0
- {proximl-0.5.10 → proximl-0.5.11/proximl.egg-info}/PKG-INFO +1 -1
- {proximl-0.5.10 → proximl-0.5.11}/proximl.egg-info/SOURCES.txt +13 -1
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/projects/conftest.py +3 -1
- proximl-0.5.11/tests/integration/projects/test_projects_data_connectors_integration.py +44 -0
- proximl-0.5.11/tests/integration/projects/test_projects_datastores_integration.py +42 -0
- proximl-0.5.11/tests/integration/projects/test_projects_services_integration.py +44 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_checkpoints_integration.py +1 -1
- proximl-0.5.11/tests/unit/cli/projects/test_cli_project_data_connector_unit.py +28 -0
- proximl-0.5.11/tests/unit/cli/projects/test_cli_project_datastore_unit.py +26 -0
- proximl-0.5.11/tests/unit/cli/projects/test_cli_project_key_unit.py +26 -0
- proximl-0.5.11/tests/unit/cli/projects/test_cli_project_secret_unit.py +26 -0
- proximl-0.5.11/tests/unit/cli/projects/test_cli_project_service_unit.py +26 -0
- proximl-0.5.11/tests/unit/cli/projects/test_cli_project_unit.py +19 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/conftest.py +77 -4
- proximl-0.5.11/tests/unit/projects/__init__.py +0 -0
- proximl-0.5.10/tests/unit/cli/test_cli_project_unit.py +0 -42
- {proximl-0.5.10 → proximl-0.5.11}/LICENSE +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/README.md +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/examples/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/examples/create_dataset_and_training_job.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/examples/local_storage.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/examples/training_inference_pipeline.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/__main__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/auth.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/checkpoints.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/checkpoint.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/data_connector.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/datastore.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/device.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/node.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/provider.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/region.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/cloudbender/service.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/connection.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/dataset.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/environment.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/gpu.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/job/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/job/create.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/model.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/project/key.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/project/secret.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cli/volume.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/cloudbender.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/data_connectors.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/datastores.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/device_configs.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/devices.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/cloudbender/services.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/connections.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/datasets.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/environments.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/gpu_types.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/jobs.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/models.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/data_connectors.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/datastores.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/keys.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/projects.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/secrets.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/projects/services.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/proximl.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl/volumes.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl.egg-info/dependency_links.txt +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl.egg-info/entry_points.txt +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl.egg-info/requires.txt +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/proximl.egg-info/top_level.txt +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/pyproject.toml +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/setup.cfg +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/setup.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/cloudbender/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/cloudbender/test_providers_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/conftest.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/projects/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/projects/test_projects_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/projects/test_projects_keys_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/projects/test_projects_secrets_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_datasets_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_environments_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_gpu_types_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_jobs_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_models_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/integration/test_volumes_integration.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/test_cli_datastore_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/test_cli_device_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/test_cli_node_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/test_cli_provider_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/test_cli_region_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/cloudbender/test_cli_service_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/conftest.py +0 -0
- {proximl-0.5.10/tests/unit/cloudbender → proximl-0.5.11/tests/unit/cli/projects}/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_checkpoint_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_datasets_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_environment_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_gpu_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_job_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_model_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cli/test_cli_volume_unit.py +0 -0
- {proximl-0.5.10/tests/unit/projects → proximl-0.5.11/tests/unit/cloudbender}/__init__.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_data_connectors_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_datastores_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_device_configs_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_devices_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_nodes_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_providers_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_regions_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/cloudbender/test_services_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/projects/test_project_data_connectors_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/projects/test_project_datastores_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/projects/test_project_keys_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/projects/test_project_secrets_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/projects/test_project_services_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/projects/test_projects_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_auth_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_checkpoints_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_connections_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_datasets_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_environments_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_exceptions.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_gpu_types_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_jobs_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_models_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_proximl_unit.py +0 -0
- {proximl-0.5.10 → proximl-0.5.11}/tests/unit/test_volumes_unit.py +0 -0
|
@@ -77,77 +77,8 @@ def remove(config, project):
|
|
|
77
77
|
return config.proximl.run(found.remove())
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
@project.command()
|
|
81
|
-
@pass_config
|
|
82
|
-
def list_datastores(config):
|
|
83
|
-
"""List project datastores."""
|
|
84
|
-
data = [
|
|
85
|
-
["ID", "NAME", "TYPE", "REGION_UUID"],
|
|
86
|
-
[
|
|
87
|
-
"-" * 80,
|
|
88
|
-
"-" * 80,
|
|
89
|
-
"-" * 80,
|
|
90
|
-
"-" * 80,
|
|
91
|
-
],
|
|
92
|
-
]
|
|
93
|
-
project = config.proximl.run(
|
|
94
|
-
config.proximl.client.projects.get(config.proximl.client.project)
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
datastores = config.proximl.run(project.list_datastores())
|
|
98
|
-
|
|
99
|
-
for datastore in datastores:
|
|
100
|
-
data.append(
|
|
101
|
-
[
|
|
102
|
-
datastore.id,
|
|
103
|
-
datastore.name,
|
|
104
|
-
datastore.type,
|
|
105
|
-
datastore.region_uuid,
|
|
106
|
-
]
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
for row in data:
|
|
110
|
-
click.echo(
|
|
111
|
-
"{: >38.36} {: >30.28} {: >15.13} {: >38.36}" "".format(*row),
|
|
112
|
-
file=config.stdout,
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
@project.command()
|
|
117
|
-
@pass_config
|
|
118
|
-
def list_services(config):
|
|
119
|
-
"""List project services."""
|
|
120
|
-
data = [
|
|
121
|
-
["ID", "NAME", "HOSTNAME", "REGION_UUID"],
|
|
122
|
-
[
|
|
123
|
-
"-" * 80,
|
|
124
|
-
"-" * 80,
|
|
125
|
-
"-" * 80,
|
|
126
|
-
"-" * 80,
|
|
127
|
-
],
|
|
128
|
-
]
|
|
129
|
-
project = config.proximl.run(
|
|
130
|
-
config.proximl.client.projects.get(config.proximl.client.project)
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
services = config.proximl.run(project.list_services())
|
|
134
|
-
|
|
135
|
-
for service in services:
|
|
136
|
-
data.append(
|
|
137
|
-
[
|
|
138
|
-
service.id,
|
|
139
|
-
service.name,
|
|
140
|
-
service.hostname,
|
|
141
|
-
service.region_uuid,
|
|
142
|
-
]
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
for row in data:
|
|
146
|
-
click.echo(
|
|
147
|
-
"{: >38.36} {: >30.28} {: >30.28} {: >38.36}" "".format(*row),
|
|
148
|
-
file=config.stdout,
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
|
|
152
80
|
from proximl.cli.project.secret import secret
|
|
153
81
|
from proximl.cli.project.key import key
|
|
82
|
+
from proximl.cli.project.data_connector import data_connector
|
|
83
|
+
from proximl.cli.project.datastore import datastore
|
|
84
|
+
from proximl.cli.project.service import service
|
|
@@ -0,0 +1,61 @@
|
|
|
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 data_connector(config):
|
|
13
|
+
"""proxiML project data_connector commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@data_connector.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List project data_connectors."""
|
|
21
|
+
data = [
|
|
22
|
+
["ID", "NAME", "TYPE", "REGION_UUID"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
"-" * 80,
|
|
28
|
+
],
|
|
29
|
+
]
|
|
30
|
+
project = config.proximl.run(
|
|
31
|
+
config.proximl.client.projects.get(config.proximl.client.project)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
data_connectors = config.proximl.run(project.data_connectors.list())
|
|
35
|
+
|
|
36
|
+
for data_connector in data_connectors:
|
|
37
|
+
data.append(
|
|
38
|
+
[
|
|
39
|
+
data_connector.id,
|
|
40
|
+
data_connector.name,
|
|
41
|
+
data_connector.type,
|
|
42
|
+
data_connector.region_uuid,
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for row in data:
|
|
47
|
+
click.echo(
|
|
48
|
+
"{: >38.36} {: >30.28} {: >15.13} {: >38.36}" "".format(*row),
|
|
49
|
+
file=config.stdout,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@data_connector.command()
|
|
54
|
+
@pass_config
|
|
55
|
+
def refresh(config):
|
|
56
|
+
"""
|
|
57
|
+
Refresh project data_connector list.
|
|
58
|
+
"""
|
|
59
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
60
|
+
|
|
61
|
+
return config.proximl.run(project.data_connectors.refresh())
|
|
@@ -0,0 +1,61 @@
|
|
|
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 datastore(config):
|
|
13
|
+
"""proxiML project datastore commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@datastore.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List project datastores."""
|
|
21
|
+
data = [
|
|
22
|
+
["ID", "NAME", "TYPE", "REGION_UUID"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
"-" * 80,
|
|
28
|
+
],
|
|
29
|
+
]
|
|
30
|
+
project = config.proximl.run(
|
|
31
|
+
config.proximl.client.projects.get(config.proximl.client.project)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
datastores = config.proximl.run(project.datastores.list())
|
|
35
|
+
|
|
36
|
+
for datastore in datastores:
|
|
37
|
+
data.append(
|
|
38
|
+
[
|
|
39
|
+
datastore.id,
|
|
40
|
+
datastore.name,
|
|
41
|
+
datastore.type,
|
|
42
|
+
datastore.region_uuid,
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for row in data:
|
|
47
|
+
click.echo(
|
|
48
|
+
"{: >38.36} {: >30.28} {: >15.13} {: >38.36}" "".format(*row),
|
|
49
|
+
file=config.stdout,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@datastore.command()
|
|
54
|
+
@pass_config
|
|
55
|
+
def refresh(config):
|
|
56
|
+
"""
|
|
57
|
+
Refresh project datastore list.
|
|
58
|
+
"""
|
|
59
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
60
|
+
|
|
61
|
+
return config.proximl.run(project.datastores.refresh())
|
|
@@ -0,0 +1,61 @@
|
|
|
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 service(config):
|
|
13
|
+
"""proxiML project service commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@service.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List project services."""
|
|
21
|
+
data = [
|
|
22
|
+
["ID", "NAME", "TYPE", "REGION_UUID"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
"-" * 80,
|
|
28
|
+
],
|
|
29
|
+
]
|
|
30
|
+
project = config.proximl.run(
|
|
31
|
+
config.proximl.client.projects.get(config.proximl.client.project)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
services = config.proximl.run(project.services.list())
|
|
35
|
+
|
|
36
|
+
for service in services:
|
|
37
|
+
data.append(
|
|
38
|
+
[
|
|
39
|
+
service.id,
|
|
40
|
+
service.name,
|
|
41
|
+
service.hostname,
|
|
42
|
+
service.region_uuid,
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for row in data:
|
|
47
|
+
click.echo(
|
|
48
|
+
"{: >38.36} {: >30.28} {: >15.13} {: >38.36}" "".format(*row),
|
|
49
|
+
file=config.stdout,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@service.command()
|
|
54
|
+
@pass_config
|
|
55
|
+
def refresh(config):
|
|
56
|
+
"""
|
|
57
|
+
Refresh project service list.
|
|
58
|
+
"""
|
|
59
|
+
project = config.proximl.run(config.proximl.client.projects.get_current())
|
|
60
|
+
|
|
61
|
+
return config.proximl.run(project.services.refresh())
|
|
@@ -3,11 +3,7 @@ import logging
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import math
|
|
5
5
|
|
|
6
|
-
from proximl.exceptions import
|
|
7
|
-
ApiError,
|
|
8
|
-
SpecificationError,
|
|
9
|
-
ProxiMLException,
|
|
10
|
-
)
|
|
6
|
+
from proximl.exceptions import ApiError, SpecificationError, ProxiMLException, NodeError
|
|
11
7
|
|
|
12
8
|
|
|
13
9
|
class Nodes(object):
|
|
@@ -37,7 +33,7 @@ class Nodes(object):
|
|
|
37
33
|
region_uuid,
|
|
38
34
|
friendly_name,
|
|
39
35
|
hostname,
|
|
40
|
-
minion_id,
|
|
36
|
+
minion_id=None,
|
|
41
37
|
type="permanent",
|
|
42
38
|
service="compute",
|
|
43
39
|
**kwargs,
|
|
@@ -191,6 +187,8 @@ class Node:
|
|
|
191
187
|
if status == "archived" and e.status == 404:
|
|
192
188
|
return
|
|
193
189
|
raise e
|
|
190
|
+
if self.status in ["errored", "failed"]:
|
|
191
|
+
raise NodeError(self.status, self)
|
|
194
192
|
if self.status == status:
|
|
195
193
|
return self
|
|
196
194
|
else:
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import asyncio
|
|
4
|
+
import math
|
|
3
5
|
from datetime import datetime
|
|
4
6
|
|
|
7
|
+
from proximl.exceptions import (
|
|
8
|
+
ApiError,
|
|
9
|
+
SpecificationError,
|
|
10
|
+
ProxiMLException,
|
|
11
|
+
ProviderError,
|
|
12
|
+
)
|
|
13
|
+
|
|
5
14
|
|
|
6
15
|
class Providers(object):
|
|
7
16
|
def __init__(self, proximl):
|
|
@@ -36,6 +45,7 @@ class Provider:
|
|
|
36
45
|
self._provider = kwargs
|
|
37
46
|
self._id = self._provider.get("provider_uuid")
|
|
38
47
|
self._type = self._provider.get("type")
|
|
48
|
+
self._status = self._provider.get("status")
|
|
39
49
|
self._credits = self._provider.get("credits")
|
|
40
50
|
|
|
41
51
|
@property
|
|
@@ -46,6 +56,10 @@ class Provider:
|
|
|
46
56
|
def type(self) -> str:
|
|
47
57
|
return self._type
|
|
48
58
|
|
|
59
|
+
@property
|
|
60
|
+
def status(self) -> str:
|
|
61
|
+
return self._status
|
|
62
|
+
|
|
49
63
|
@property
|
|
50
64
|
def credits(self) -> float:
|
|
51
65
|
return self._credits
|
|
@@ -69,3 +83,42 @@ class Provider:
|
|
|
69
83
|
)
|
|
70
84
|
self.__init__(self.proximl, **resp)
|
|
71
85
|
return self
|
|
86
|
+
|
|
87
|
+
async def wait_for(self, status, timeout=300):
|
|
88
|
+
if self.status == status:
|
|
89
|
+
return
|
|
90
|
+
valid_statuses = ["ready", "archived"]
|
|
91
|
+
if not status in valid_statuses:
|
|
92
|
+
raise SpecificationError(
|
|
93
|
+
"status",
|
|
94
|
+
f"Invalid wait_for status {status}. Valid statuses are: {valid_statuses}",
|
|
95
|
+
)
|
|
96
|
+
MAX_TIMEOUT = 24 * 60 * 60
|
|
97
|
+
if timeout > MAX_TIMEOUT:
|
|
98
|
+
raise SpecificationError(
|
|
99
|
+
"timeout",
|
|
100
|
+
f"timeout must be less than {MAX_TIMEOUT} seconds.",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
POLL_INTERVAL_MIN = 5
|
|
104
|
+
POLL_INTERVAL_MAX = 60
|
|
105
|
+
POLL_INTERVAL = max(min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN)
|
|
106
|
+
retry_count = math.ceil(timeout / POLL_INTERVAL)
|
|
107
|
+
count = 0
|
|
108
|
+
while count < retry_count:
|
|
109
|
+
await asyncio.sleep(POLL_INTERVAL)
|
|
110
|
+
try:
|
|
111
|
+
await self.refresh()
|
|
112
|
+
except ApiError as e:
|
|
113
|
+
if status == "archived" and e.status == 404:
|
|
114
|
+
return
|
|
115
|
+
raise e
|
|
116
|
+
if self.status in ["errored", "failed"]:
|
|
117
|
+
raise ProviderError(self.status, self)
|
|
118
|
+
if self.status == status:
|
|
119
|
+
return self
|
|
120
|
+
else:
|
|
121
|
+
count += 1
|
|
122
|
+
logging.debug(f"self: {self}, retry count {count}")
|
|
123
|
+
|
|
124
|
+
raise ProxiMLException(f"Timeout waiting for {status}")
|
|
@@ -1,5 +1,14 @@
|
|
|
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
|
+
RegionError,
|
|
11
|
+
)
|
|
3
12
|
|
|
4
13
|
|
|
5
14
|
class Regions(object):
|
|
@@ -111,3 +120,42 @@ class Region:
|
|
|
111
120
|
None,
|
|
112
121
|
dict(project_uuid=project_uuid, checkpoint_uuid=checkpoint_uuid),
|
|
113
122
|
)
|
|
123
|
+
|
|
124
|
+
async def wait_for(self, status, timeout=300):
|
|
125
|
+
if self.status == status:
|
|
126
|
+
return
|
|
127
|
+
valid_statuses = ["healthy", "offline", "archived"]
|
|
128
|
+
if not status in valid_statuses:
|
|
129
|
+
raise SpecificationError(
|
|
130
|
+
"status",
|
|
131
|
+
f"Invalid wait_for status {status}. Valid statuses are: {valid_statuses}",
|
|
132
|
+
)
|
|
133
|
+
MAX_TIMEOUT = 24 * 60 * 60
|
|
134
|
+
if timeout > MAX_TIMEOUT:
|
|
135
|
+
raise SpecificationError(
|
|
136
|
+
"timeout",
|
|
137
|
+
f"timeout must be less than {MAX_TIMEOUT} seconds.",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
POLL_INTERVAL_MIN = 5
|
|
141
|
+
POLL_INTERVAL_MAX = 60
|
|
142
|
+
POLL_INTERVAL = max(min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN)
|
|
143
|
+
retry_count = math.ceil(timeout / POLL_INTERVAL)
|
|
144
|
+
count = 0
|
|
145
|
+
while count < retry_count:
|
|
146
|
+
await asyncio.sleep(POLL_INTERVAL)
|
|
147
|
+
try:
|
|
148
|
+
await self.refresh()
|
|
149
|
+
except ApiError as e:
|
|
150
|
+
if status == "archived" and e.status == 404:
|
|
151
|
+
return
|
|
152
|
+
raise e
|
|
153
|
+
if self.status in ["errored", "failed"]:
|
|
154
|
+
raise RegionError(self.status, self)
|
|
155
|
+
if self.status == status:
|
|
156
|
+
return self
|
|
157
|
+
else:
|
|
158
|
+
count += 1
|
|
159
|
+
logging.debug(f"self: {self}, retry count {count}")
|
|
160
|
+
|
|
161
|
+
raise ProxiMLException(f"Timeout waiting for {status}")
|
|
@@ -147,3 +147,54 @@ class SpecificationError(ProxiMLException):
|
|
|
147
147
|
|
|
148
148
|
def __str__(self):
|
|
149
149
|
return "SpecificationError({self.attribute}, {self.message})".format(self=self)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class NodeError(ProxiMLException):
|
|
153
|
+
def __init__(self, status, data, *args):
|
|
154
|
+
super().__init__(data, *args)
|
|
155
|
+
self._status = status
|
|
156
|
+
self._message = data
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def status(self) -> str:
|
|
160
|
+
return self._status
|
|
161
|
+
|
|
162
|
+
def __repr__(self):
|
|
163
|
+
return "NodeError({self.status}, {self.message})".format(self=self)
|
|
164
|
+
|
|
165
|
+
def __str__(self):
|
|
166
|
+
return "NodeError({self.status}, {self.message})".format(self=self)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class ProviderError(ProxiMLException):
|
|
170
|
+
def __init__(self, status, data, *args):
|
|
171
|
+
super().__init__(data, *args)
|
|
172
|
+
self._status = status
|
|
173
|
+
self._message = data
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def status(self) -> str:
|
|
177
|
+
return self._status
|
|
178
|
+
|
|
179
|
+
def __repr__(self):
|
|
180
|
+
return "ProviderError({self.status}, {self.message})".format(self=self)
|
|
181
|
+
|
|
182
|
+
def __str__(self):
|
|
183
|
+
return "ProviderError({self.status}, {self.message})".format(self=self)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class RegionError(ProxiMLException):
|
|
187
|
+
def __init__(self, status, data, *args):
|
|
188
|
+
super().__init__(data, *args)
|
|
189
|
+
self._status = status
|
|
190
|
+
self._message = data
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def status(self) -> str:
|
|
194
|
+
return self._status
|
|
195
|
+
|
|
196
|
+
def __repr__(self):
|
|
197
|
+
return "RegionError({self.status}, {self.message})".format(self=self)
|
|
198
|
+
|
|
199
|
+
def __str__(self):
|
|
200
|
+
return "RegionError({self.status}, {self.message})".format(self=self)
|
|
@@ -44,8 +44,11 @@ proximl/cli/cloudbender/service.py
|
|
|
44
44
|
proximl/cli/job/__init__.py
|
|
45
45
|
proximl/cli/job/create.py
|
|
46
46
|
proximl/cli/project/__init__.py
|
|
47
|
+
proximl/cli/project/data_connector.py
|
|
48
|
+
proximl/cli/project/datastore.py
|
|
47
49
|
proximl/cli/project/key.py
|
|
48
50
|
proximl/cli/project/secret.py
|
|
51
|
+
proximl/cli/project/service.py
|
|
49
52
|
proximl/cloudbender/__init__.py
|
|
50
53
|
proximl/cloudbender/cloudbender.py
|
|
51
54
|
proximl/cloudbender/data_connectors.py
|
|
@@ -76,9 +79,12 @@ tests/integration/cloudbender/__init__.py
|
|
|
76
79
|
tests/integration/cloudbender/test_providers_integration.py
|
|
77
80
|
tests/integration/projects/__init__.py
|
|
78
81
|
tests/integration/projects/conftest.py
|
|
82
|
+
tests/integration/projects/test_projects_data_connectors_integration.py
|
|
83
|
+
tests/integration/projects/test_projects_datastores_integration.py
|
|
79
84
|
tests/integration/projects/test_projects_integration.py
|
|
80
85
|
tests/integration/projects/test_projects_keys_integration.py
|
|
81
86
|
tests/integration/projects/test_projects_secrets_integration.py
|
|
87
|
+
tests/integration/projects/test_projects_services_integration.py
|
|
82
88
|
tests/unit/__init__.py
|
|
83
89
|
tests/unit/conftest.py
|
|
84
90
|
tests/unit/test_auth_unit.py
|
|
@@ -100,7 +106,6 @@ tests/unit/cli/test_cli_environment_unit.py
|
|
|
100
106
|
tests/unit/cli/test_cli_gpu_unit.py
|
|
101
107
|
tests/unit/cli/test_cli_job_unit.py
|
|
102
108
|
tests/unit/cli/test_cli_model_unit.py
|
|
103
|
-
tests/unit/cli/test_cli_project_unit.py
|
|
104
109
|
tests/unit/cli/test_cli_volume_unit.py
|
|
105
110
|
tests/unit/cli/cloudbender/__init__.py
|
|
106
111
|
tests/unit/cli/cloudbender/test_cli_datastore_unit.py
|
|
@@ -109,6 +114,13 @@ tests/unit/cli/cloudbender/test_cli_node_unit.py
|
|
|
109
114
|
tests/unit/cli/cloudbender/test_cli_provider_unit.py
|
|
110
115
|
tests/unit/cli/cloudbender/test_cli_region_unit.py
|
|
111
116
|
tests/unit/cli/cloudbender/test_cli_service_unit.py
|
|
117
|
+
tests/unit/cli/projects/__init__.py
|
|
118
|
+
tests/unit/cli/projects/test_cli_project_data_connector_unit.py
|
|
119
|
+
tests/unit/cli/projects/test_cli_project_datastore_unit.py
|
|
120
|
+
tests/unit/cli/projects/test_cli_project_key_unit.py
|
|
121
|
+
tests/unit/cli/projects/test_cli_project_secret_unit.py
|
|
122
|
+
tests/unit/cli/projects/test_cli_project_service_unit.py
|
|
123
|
+
tests/unit/cli/projects/test_cli_project_unit.py
|
|
112
124
|
tests/unit/cloudbender/__init__.py
|
|
113
125
|
tests/unit/cloudbender/test_data_connectors_unit.py
|
|
114
126
|
tests/unit/cloudbender/test_datastores_unit.py
|
|
@@ -3,6 +3,8 @@ from pytest import fixture
|
|
|
3
3
|
|
|
4
4
|
@fixture(scope="module")
|
|
5
5
|
async def project(proximl):
|
|
6
|
-
project = await proximl.projects.create(
|
|
6
|
+
project = await proximl.projects.create(
|
|
7
|
+
name="New Project", copy_keys=False, copy_secrets=False
|
|
8
|
+
)
|
|
7
9
|
yield project
|
|
8
10
|
await project.remove()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
import asyncio
|
|
4
|
+
from pytest import mark, fixture
|
|
5
|
+
|
|
6
|
+
pytestmark = [mark.sdk, mark.integration, mark.projects]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@mark.create
|
|
10
|
+
@mark.asyncio
|
|
11
|
+
class ProjectDataConnectorsTests:
|
|
12
|
+
@fixture(scope="class")
|
|
13
|
+
async def project_data_connector(self, project):
|
|
14
|
+
data_connectors = await project.data_connectors.list()
|
|
15
|
+
yield data_connectors[0]
|
|
16
|
+
|
|
17
|
+
async def test_list_project_data_connectors(self, project, project_data_connector):
|
|
18
|
+
data_connectors = await project.data_connectors.list()
|
|
19
|
+
assert len(data_connectors) > 0
|
|
20
|
+
|
|
21
|
+
async def test_project_data_connector_properties(
|
|
22
|
+
self, project, project_data_connector
|
|
23
|
+
):
|
|
24
|
+
assert isinstance(project_data_connector.project_uuid, str)
|
|
25
|
+
assert isinstance(project_data_connector.type, str)
|
|
26
|
+
assert isinstance(project_data_connector.name, str)
|
|
27
|
+
assert isinstance(project_data_connector.region_uuid, str)
|
|
28
|
+
assert project.id == project_data_connector.project_uuid
|
|
29
|
+
|
|
30
|
+
async def test_project_data_connector_str(self, project_data_connector):
|
|
31
|
+
string = str(project_data_connector)
|
|
32
|
+
regex = r"^{.*\"name\": \"" + project_data_connector.name + r"\".*}$"
|
|
33
|
+
assert isinstance(string, str)
|
|
34
|
+
assert re.match(regex, string)
|
|
35
|
+
|
|
36
|
+
async def test_project_data_connector_repr(self, project_data_connector):
|
|
37
|
+
string = repr(project_data_connector)
|
|
38
|
+
regex = (
|
|
39
|
+
r"^ProjectDataConnector\( proximl , \*\*{.*'name': '"
|
|
40
|
+
+ project_data_connector.name
|
|
41
|
+
+ r"'.*}\)$"
|
|
42
|
+
)
|
|
43
|
+
assert isinstance(string, str)
|
|
44
|
+
assert re.match(regex, string)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
import asyncio
|
|
4
|
+
from pytest import mark, fixture
|
|
5
|
+
|
|
6
|
+
pytestmark = [mark.sdk, mark.integration, mark.projects]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@mark.create
|
|
10
|
+
@mark.asyncio
|
|
11
|
+
class ProjectDatastoresTests:
|
|
12
|
+
@fixture(scope="class")
|
|
13
|
+
async def project_datastore(self, project):
|
|
14
|
+
datastores = await project.datastores.list()
|
|
15
|
+
yield datastores[0]
|
|
16
|
+
|
|
17
|
+
async def test_list_project_datastores(self, project):
|
|
18
|
+
datastores = await project.datastores.list()
|
|
19
|
+
assert len(datastores) > 0
|
|
20
|
+
|
|
21
|
+
async def test_project_datastore_properties(self, project, project_datastore):
|
|
22
|
+
assert isinstance(project_datastore.project_uuid, str)
|
|
23
|
+
assert isinstance(project_datastore.type, str)
|
|
24
|
+
assert isinstance(project_datastore.name, str)
|
|
25
|
+
assert isinstance(project_datastore.region_uuid, str)
|
|
26
|
+
assert project.id == project_datastore.project_uuid
|
|
27
|
+
|
|
28
|
+
async def test_project_datastore_str(self, project_datastore):
|
|
29
|
+
string = str(project_datastore)
|
|
30
|
+
regex = r"^{.*\"name\": \"" + project_datastore.name + r"\".*}$"
|
|
31
|
+
assert isinstance(string, str)
|
|
32
|
+
assert re.match(regex, string)
|
|
33
|
+
|
|
34
|
+
async def test_project_datastore_repr(self, project_datastore):
|
|
35
|
+
string = repr(project_datastore)
|
|
36
|
+
regex = (
|
|
37
|
+
r"^ProjectDatastore\( proximl , \*\*{.*'name': '"
|
|
38
|
+
+ project_datastore.name
|
|
39
|
+
+ r"'.*}\)$"
|
|
40
|
+
)
|
|
41
|
+
assert isinstance(string, str)
|
|
42
|
+
assert re.match(regex, string)
|