proximl 0.5.4__tar.gz → 0.5.6__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.4/proximl.egg-info → proximl-0.5.6}/PKG-INFO +1 -1
- {proximl-0.5.4 → proximl-0.5.6}/proximl/__init__.py +1 -1
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/__init__.py +3 -6
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/__init__.py +1 -1
- proximl-0.5.6/proximl/cli/cloudbender/service.py +129 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/project.py +10 -15
- proximl-0.5.6/proximl/cli/volume.py +235 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/cloudbender.py +2 -2
- proximl-0.5.4/proximl/cloudbender/reservations.py → proximl-0.5.6/proximl/cloudbender/services.py +28 -39
- {proximl-0.5.4 → proximl-0.5.6}/proximl/exceptions.py +21 -12
- {proximl-0.5.4 → proximl-0.5.6}/proximl/jobs.py +36 -39
- {proximl-0.5.4 → proximl-0.5.6}/proximl/projects.py +19 -30
- {proximl-0.5.4 → proximl-0.5.6}/proximl/proximl.py +7 -15
- proximl-0.5.6/proximl/volumes.py +255 -0
- {proximl-0.5.4 → proximl-0.5.6/proximl.egg-info}/PKG-INFO +1 -1
- {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/SOURCES.txt +8 -3
- {proximl-0.5.4 → proximl-0.5.6}/pyproject.toml +5 -6
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_checkpoints_integration.py +7 -5
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_datasets_integration.py +4 -5
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_jobs_integration.py +40 -2
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_models_integration.py +8 -10
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_projects_integration.py +2 -6
- proximl-0.5.6/tests/integration/test_volumes_integration.py +100 -0
- proximl-0.5.6/tests/unit/cli/cloudbender/test_cli_reservation_unit.py +34 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_project_unit.py +5 -9
- proximl-0.5.6/tests/unit/cli/test_cli_volume_unit.py +20 -0
- proximl-0.5.6/tests/unit/cloudbender/test_services_unit.py +161 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/conftest.py +94 -21
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_projects_unit.py +34 -48
- proximl-0.5.6/tests/unit/test_volumes_unit.py +447 -0
- proximl-0.5.4/proximl/cli/cloudbender/reservation.py +0 -159
- proximl-0.5.4/tests/unit/cli/cloudbender/test_cli_reservation_unit.py +0 -38
- proximl-0.5.4/tests/unit/cloudbender/test_reservations_unit.py +0 -173
- {proximl-0.5.4 → proximl-0.5.6}/LICENSE +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/README.md +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/examples/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/examples/create_dataset_and_training_job.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/examples/local_storage.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/examples/training_inference_pipeline.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/__main__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/auth.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/checkpoints.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/checkpoint.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/datastore.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/device.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/node.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/provider.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/region.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/connection.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/dataset.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/environment.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/gpu.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/job/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/job/create.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/model.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/datastores.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/device_configs.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/devices.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/nodes.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/providers.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/regions.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/connections.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/datasets.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/environments.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/gpu_types.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl/models.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/dependency_links.txt +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/entry_points.txt +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/requires.txt +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/top_level.txt +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/setup.cfg +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/setup.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/cloudbender/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/cloudbender/test_providers_integration.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/conftest.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_environments_integration.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_gpu_types_integration.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_datastore_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_device_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_node_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_provider_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_region_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/conftest.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_checkpoint_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_datasets_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_environment_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_gpu_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_job_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_model_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/__init__.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_datastores_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_device_configs_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_devices_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_nodes_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_providers_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_regions_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_auth.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_checkpoints_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_connections_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_datasets_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_environments_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_exceptions.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_gpu_types_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_jobs_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_models_unit.py +0 -0
- {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_proximl.py +0 -0
|
@@ -142,9 +142,7 @@ def configure(config):
|
|
|
142
142
|
project for project in projects if project.id == active_project_id
|
|
143
143
|
]
|
|
144
144
|
|
|
145
|
-
active_project_name = (
|
|
146
|
-
active_project[0].name if len(active_project) else "UNSET"
|
|
147
|
-
)
|
|
145
|
+
active_project_name = active_project[0].name if len(active_project) else "UNSET"
|
|
148
146
|
|
|
149
147
|
click.echo(f"Current Active Project: {active_project_name}")
|
|
150
148
|
|
|
@@ -154,9 +152,7 @@ def configure(config):
|
|
|
154
152
|
show_choices=True,
|
|
155
153
|
default=active_project_name,
|
|
156
154
|
)
|
|
157
|
-
selected_project = [
|
|
158
|
-
project for project in projects if project.name == name
|
|
159
|
-
]
|
|
155
|
+
selected_project = [project for project in projects if project.name == name]
|
|
160
156
|
config.proximl.client.set_active_project(selected_project[0].id)
|
|
161
157
|
|
|
162
158
|
|
|
@@ -164,6 +160,7 @@ from proximl.cli.connection import connection
|
|
|
164
160
|
from proximl.cli.dataset import dataset
|
|
165
161
|
from proximl.cli.model import model
|
|
166
162
|
from proximl.cli.checkpoint import checkpoint
|
|
163
|
+
from proximl.cli.volume import volume
|
|
167
164
|
from proximl.cli.environment import environment
|
|
168
165
|
from proximl.cli.gpu import gpu
|
|
169
166
|
from proximl.cli.job import job
|
|
@@ -15,4 +15,4 @@ from proximl.cli.cloudbender.region import region
|
|
|
15
15
|
from proximl.cli.cloudbender.node import node
|
|
16
16
|
from proximl.cli.cloudbender.device import device
|
|
17
17
|
from proximl.cli.cloudbender.datastore import datastore
|
|
18
|
-
from proximl.cli.cloudbender.
|
|
18
|
+
from proximl.cli.cloudbender.service import service
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from proximl.cli import cli, pass_config, search_by_id_name
|
|
3
|
+
from proximl.cli.cloudbender import cloudbender
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@cloudbender.group()
|
|
7
|
+
@pass_config
|
|
8
|
+
def service(config):
|
|
9
|
+
"""proxiML CloudBender service commands."""
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@service.command()
|
|
14
|
+
@click.option(
|
|
15
|
+
"--provider",
|
|
16
|
+
"-p",
|
|
17
|
+
type=click.STRING,
|
|
18
|
+
required=True,
|
|
19
|
+
help="The provider ID of the region.",
|
|
20
|
+
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"--region",
|
|
23
|
+
"-r",
|
|
24
|
+
type=click.STRING,
|
|
25
|
+
required=True,
|
|
26
|
+
help="The region ID to list services for.",
|
|
27
|
+
)
|
|
28
|
+
@pass_config
|
|
29
|
+
def list(config, provider, region):
|
|
30
|
+
"""List services."""
|
|
31
|
+
data = [
|
|
32
|
+
["ID", "NAME", "HOSTNAME"],
|
|
33
|
+
[
|
|
34
|
+
"-" * 80,
|
|
35
|
+
"-" * 80,
|
|
36
|
+
"-" * 80,
|
|
37
|
+
],
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
services = config.proximl.run(
|
|
41
|
+
config.proximl.client.cloudbender.services.list(
|
|
42
|
+
provider_uuid=provider, region_uuid=region
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for service in services:
|
|
47
|
+
data.append(
|
|
48
|
+
[
|
|
49
|
+
service.id,
|
|
50
|
+
service.name,
|
|
51
|
+
service.hostname,
|
|
52
|
+
]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
for row in data:
|
|
56
|
+
click.echo(
|
|
57
|
+
"{: >25.24} {: >29.28} {: >40.39}" "".format(*row),
|
|
58
|
+
file=config.stdout,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@service.command()
|
|
63
|
+
@click.option(
|
|
64
|
+
"--provider",
|
|
65
|
+
"-p",
|
|
66
|
+
type=click.STRING,
|
|
67
|
+
required=True,
|
|
68
|
+
help="The provider ID of the region.",
|
|
69
|
+
)
|
|
70
|
+
@click.option(
|
|
71
|
+
"--region",
|
|
72
|
+
"-r",
|
|
73
|
+
type=click.STRING,
|
|
74
|
+
required=True,
|
|
75
|
+
help="The region ID to create the service in.",
|
|
76
|
+
)
|
|
77
|
+
@click.option(
|
|
78
|
+
"--public/--no-public",
|
|
79
|
+
default=True,
|
|
80
|
+
show_default=True,
|
|
81
|
+
help="Service should be accessible from the public internet.",
|
|
82
|
+
)
|
|
83
|
+
@click.argument("name", type=click.STRING, required=True)
|
|
84
|
+
@pass_config
|
|
85
|
+
def create(config, provider, region, public, name):
|
|
86
|
+
"""
|
|
87
|
+
Creates a service.
|
|
88
|
+
"""
|
|
89
|
+
return config.proximl.run(
|
|
90
|
+
config.proximl.client.cloudbender.services.create(
|
|
91
|
+
provider_uuid=provider, region_uuid=region, name=name, public=public
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@service.command()
|
|
97
|
+
@click.option(
|
|
98
|
+
"--provider",
|
|
99
|
+
"-p",
|
|
100
|
+
type=click.STRING,
|
|
101
|
+
required=True,
|
|
102
|
+
help="The provider ID of the region.",
|
|
103
|
+
)
|
|
104
|
+
@click.option(
|
|
105
|
+
"--region",
|
|
106
|
+
"-r",
|
|
107
|
+
type=click.STRING,
|
|
108
|
+
required=True,
|
|
109
|
+
help="The region ID to remove the service from.",
|
|
110
|
+
)
|
|
111
|
+
@click.argument("service", type=click.STRING)
|
|
112
|
+
@pass_config
|
|
113
|
+
def remove(config, provider, region, service):
|
|
114
|
+
"""
|
|
115
|
+
Remove a service.
|
|
116
|
+
|
|
117
|
+
RESERVATION may be specified by name or ID, but ID is preferred.
|
|
118
|
+
"""
|
|
119
|
+
services = config.proximl.run(
|
|
120
|
+
config.proximl.client.cloudbender.services.list(
|
|
121
|
+
provider_uuid=provider, region_uuid=region
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
found = search_by_id_name(service, services)
|
|
126
|
+
if None is found:
|
|
127
|
+
raise click.UsageError("Cannot find specified service.")
|
|
128
|
+
|
|
129
|
+
return config.proximl.run(found.remove())
|
|
@@ -115,40 +115,35 @@ def list_datastores(config):
|
|
|
115
115
|
|
|
116
116
|
@project.command()
|
|
117
117
|
@pass_config
|
|
118
|
-
def
|
|
119
|
-
"""List project
|
|
118
|
+
def list_services(config):
|
|
119
|
+
"""List project services."""
|
|
120
120
|
data = [
|
|
121
|
-
["ID", "NAME", "
|
|
121
|
+
["ID", "NAME", "HOSTNAME", "REGION_UUID"],
|
|
122
122
|
[
|
|
123
123
|
"-" * 80,
|
|
124
124
|
"-" * 80,
|
|
125
125
|
"-" * 80,
|
|
126
126
|
"-" * 80,
|
|
127
|
-
"-" * 80,
|
|
128
|
-
"-" * 80,
|
|
129
127
|
],
|
|
130
128
|
]
|
|
131
129
|
project = config.proximl.run(
|
|
132
130
|
config.proximl.client.projects.get(config.proximl.client.project)
|
|
133
131
|
)
|
|
134
132
|
|
|
135
|
-
|
|
133
|
+
services = config.proximl.run(project.list_services())
|
|
136
134
|
|
|
137
|
-
for
|
|
135
|
+
for service in services:
|
|
138
136
|
data.append(
|
|
139
137
|
[
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
reservation.hostname,
|
|
145
|
-
reservation.region_uuid,
|
|
138
|
+
service.id,
|
|
139
|
+
service.name,
|
|
140
|
+
service.hostname,
|
|
141
|
+
service.region_uuid,
|
|
146
142
|
]
|
|
147
143
|
)
|
|
148
144
|
|
|
149
145
|
for row in data:
|
|
150
146
|
click.echo(
|
|
151
|
-
"{: >38.36} {: >30.28} {: >
|
|
152
|
-
"".format(*row),
|
|
147
|
+
"{: >38.36} {: >30.28} {: >30.28} {: >38.36}" "".format(*row),
|
|
153
148
|
file=config.stdout,
|
|
154
149
|
)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from proximl.cli import cli, pass_config, search_by_id_name
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def pretty_size(num):
|
|
6
|
+
if not num:
|
|
7
|
+
num = 0.0
|
|
8
|
+
s = (" B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB")
|
|
9
|
+
n = 0
|
|
10
|
+
while num > 1023:
|
|
11
|
+
num = num / 1024
|
|
12
|
+
n += 1
|
|
13
|
+
return f"{num:.2f} {s[n]}"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@cli.group()
|
|
17
|
+
@pass_config
|
|
18
|
+
def volume(config):
|
|
19
|
+
"""proxiML volume commands."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@volume.command()
|
|
24
|
+
@click.argument("volume", type=click.STRING)
|
|
25
|
+
@pass_config
|
|
26
|
+
def attach(config, volume):
|
|
27
|
+
"""
|
|
28
|
+
Attach to volume and show creation logs.
|
|
29
|
+
|
|
30
|
+
VOLUME may be specified by name or ID, but ID is preferred.
|
|
31
|
+
"""
|
|
32
|
+
volumes = config.proximl.run(config.proximl.client.volumes.list())
|
|
33
|
+
|
|
34
|
+
found = search_by_id_name(volume, volumes)
|
|
35
|
+
if None is found:
|
|
36
|
+
raise click.UsageError("Cannot find specified volume.")
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
config.proximl.run(found.attach())
|
|
40
|
+
return config.proximl.run(found.disconnect())
|
|
41
|
+
except:
|
|
42
|
+
try:
|
|
43
|
+
config.proximl.run(found.disconnect())
|
|
44
|
+
except:
|
|
45
|
+
pass
|
|
46
|
+
raise
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@volume.command()
|
|
50
|
+
@click.option(
|
|
51
|
+
"--attach/--no-attach",
|
|
52
|
+
default=True,
|
|
53
|
+
show_default=True,
|
|
54
|
+
help="Auto attach to volume and show creation logs.",
|
|
55
|
+
)
|
|
56
|
+
@click.argument("volume", type=click.STRING)
|
|
57
|
+
@pass_config
|
|
58
|
+
def connect(config, volume, attach):
|
|
59
|
+
"""
|
|
60
|
+
Connect local source to volume and begin upload.
|
|
61
|
+
|
|
62
|
+
VOLUME may be specified by name or ID, but ID is preferred.
|
|
63
|
+
"""
|
|
64
|
+
volumes = config.proximl.run(config.proximl.client.volumes.list())
|
|
65
|
+
|
|
66
|
+
found = search_by_id_name(volume, volumes)
|
|
67
|
+
if None is found:
|
|
68
|
+
raise click.UsageError("Cannot find specified volume.")
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
if attach:
|
|
72
|
+
config.proximl.run(found.connect(), found.attach())
|
|
73
|
+
return config.proximl.run(found.disconnect())
|
|
74
|
+
else:
|
|
75
|
+
return config.proximl.run(found.connect())
|
|
76
|
+
except:
|
|
77
|
+
try:
|
|
78
|
+
config.proximl.run(found.disconnect())
|
|
79
|
+
except:
|
|
80
|
+
pass
|
|
81
|
+
raise
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@volume.command()
|
|
85
|
+
@click.option(
|
|
86
|
+
"--attach/--no-attach",
|
|
87
|
+
default=True,
|
|
88
|
+
show_default=True,
|
|
89
|
+
help="Auto attach to volume and show creation logs.",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"--connect/--no-connect",
|
|
93
|
+
default=True,
|
|
94
|
+
show_default=True,
|
|
95
|
+
help="Auto connect source and start volume creation.",
|
|
96
|
+
)
|
|
97
|
+
@click.option(
|
|
98
|
+
"--source",
|
|
99
|
+
"-s",
|
|
100
|
+
type=click.Choice(["local"], case_sensitive=False),
|
|
101
|
+
default="local",
|
|
102
|
+
show_default=True,
|
|
103
|
+
help="Dataset source type.",
|
|
104
|
+
)
|
|
105
|
+
@click.argument("name", type=click.STRING)
|
|
106
|
+
@click.argument("capacity", type=click.INT)
|
|
107
|
+
@click.argument(
|
|
108
|
+
"path", type=click.Path(exists=True, file_okay=False, resolve_path=True)
|
|
109
|
+
)
|
|
110
|
+
@pass_config
|
|
111
|
+
def create(config, attach, connect, source, name, capacity, path):
|
|
112
|
+
"""
|
|
113
|
+
Create a volume.
|
|
114
|
+
|
|
115
|
+
A volume with maximum size CAPACITY is created with the specified NAME using a local source at the PATH
|
|
116
|
+
specified. PATH should be a local directory containing the source data for
|
|
117
|
+
a local source or a URI for all other source types.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
if source == "local":
|
|
121
|
+
volume = config.proximl.run(
|
|
122
|
+
config.proximl.client.volumes.create(
|
|
123
|
+
name=name, source_type="local", source_uri=path, capacity=capacity
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
if connect and attach:
|
|
129
|
+
config.proximl.run(volume.attach(), volume.connect())
|
|
130
|
+
return config.proximl.run(volume.disconnect())
|
|
131
|
+
elif connect:
|
|
132
|
+
return config.proximl.run(volume.connect())
|
|
133
|
+
else:
|
|
134
|
+
raise click.UsageError(
|
|
135
|
+
"Abort!\n"
|
|
136
|
+
"No logs to show for local sourced volume without connect."
|
|
137
|
+
)
|
|
138
|
+
except:
|
|
139
|
+
try:
|
|
140
|
+
config.proximl.run(volume.disconnect())
|
|
141
|
+
except:
|
|
142
|
+
pass
|
|
143
|
+
raise
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@volume.command()
|
|
147
|
+
@click.argument("volume", type=click.STRING)
|
|
148
|
+
@pass_config
|
|
149
|
+
def disconnect(config, volume):
|
|
150
|
+
"""
|
|
151
|
+
Disconnect and clean-up volume upload.
|
|
152
|
+
|
|
153
|
+
VOLUME may be specified by name or ID, but ID is preferred.
|
|
154
|
+
"""
|
|
155
|
+
volumes = config.proximl.run(config.proximl.client.volumes.list())
|
|
156
|
+
|
|
157
|
+
found = search_by_id_name(volume, volumes)
|
|
158
|
+
if None is found:
|
|
159
|
+
raise click.UsageError("Cannot find specified volume.")
|
|
160
|
+
|
|
161
|
+
return config.proximl.run(found.disconnect())
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@volume.command()
|
|
165
|
+
@pass_config
|
|
166
|
+
def list(config):
|
|
167
|
+
"""List volumes."""
|
|
168
|
+
data = [
|
|
169
|
+
["ID", "STATUS", "NAME", "CAPACITY"],
|
|
170
|
+
["-" * 80, "-" * 80, "-" * 80, "-" * 80],
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
volumes = config.proximl.run(config.proximl.client.volumes.list())
|
|
174
|
+
|
|
175
|
+
for volume in volumes:
|
|
176
|
+
data.append(
|
|
177
|
+
[
|
|
178
|
+
volume.id,
|
|
179
|
+
volume.status,
|
|
180
|
+
volume.name,
|
|
181
|
+
volume.capacity,
|
|
182
|
+
]
|
|
183
|
+
)
|
|
184
|
+
for row in data:
|
|
185
|
+
click.echo(
|
|
186
|
+
"{: >38.36} {: >13.11} {: >40.38} {: >14.12}" "".format(*row),
|
|
187
|
+
file=config.stdout,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@volume.command()
|
|
192
|
+
@click.option(
|
|
193
|
+
"--force/--no-force",
|
|
194
|
+
default=False,
|
|
195
|
+
show_default=True,
|
|
196
|
+
help="Force removal.",
|
|
197
|
+
)
|
|
198
|
+
@click.argument("volume", type=click.STRING)
|
|
199
|
+
@pass_config
|
|
200
|
+
def remove(config, volume, force):
|
|
201
|
+
"""
|
|
202
|
+
Remove a volume.
|
|
203
|
+
|
|
204
|
+
VOLUME may be specified by name or ID, but ID is preferred.
|
|
205
|
+
"""
|
|
206
|
+
volumes = config.proximl.run(config.proximl.client.volumes.list())
|
|
207
|
+
|
|
208
|
+
found = search_by_id_name(volume, volumes)
|
|
209
|
+
if None is found:
|
|
210
|
+
if force:
|
|
211
|
+
config.proximl.run(found.client.volumes.remove(volume))
|
|
212
|
+
else:
|
|
213
|
+
raise click.UsageError("Cannot find specified volume.")
|
|
214
|
+
|
|
215
|
+
return config.proximl.run(found.remove(force=force))
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@volume.command()
|
|
219
|
+
@click.argument("volume", type=click.STRING)
|
|
220
|
+
@click.argument("name", type=click.STRING)
|
|
221
|
+
@pass_config
|
|
222
|
+
def rename(config, volume, name):
|
|
223
|
+
"""
|
|
224
|
+
Renames a volume.
|
|
225
|
+
|
|
226
|
+
VOLUME may be specified by name or ID, but ID is preferred.
|
|
227
|
+
"""
|
|
228
|
+
try:
|
|
229
|
+
volume = config.proximl.run(config.proximl.client.volumes.get(volume))
|
|
230
|
+
if volume is None:
|
|
231
|
+
raise click.UsageError("Cannot find specified volume.")
|
|
232
|
+
except:
|
|
233
|
+
raise click.UsageError("Cannot find specified volume.")
|
|
234
|
+
|
|
235
|
+
return config.proximl.run(volume.rename(name=name))
|
|
@@ -3,7 +3,7 @@ from .regions import Regions
|
|
|
3
3
|
from .nodes import Nodes
|
|
4
4
|
from .devices import Devices
|
|
5
5
|
from .datastores import Datastores
|
|
6
|
-
from .
|
|
6
|
+
from .services import Services
|
|
7
7
|
from .device_configs import DeviceConfigs
|
|
8
8
|
|
|
9
9
|
|
|
@@ -15,5 +15,5 @@ class Cloudbender(object):
|
|
|
15
15
|
self.nodes = Nodes(proximl)
|
|
16
16
|
self.devices = Devices(proximl)
|
|
17
17
|
self.datastores = Datastores(proximl)
|
|
18
|
-
self.
|
|
18
|
+
self.services = Services(proximl)
|
|
19
19
|
self.device_configs = DeviceConfigs(proximl)
|
proximl-0.5.4/proximl/cloudbender/reservations.py → proximl-0.5.6/proximl/cloudbender/services.py
RENAMED
|
@@ -2,77 +2,70 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class Services(object):
|
|
6
6
|
def __init__(self, proximl):
|
|
7
7
|
self.proximl = proximl
|
|
8
8
|
|
|
9
9
|
async def get(self, provider_uuid, region_uuid, id, **kwargs):
|
|
10
10
|
resp = await self.proximl._query(
|
|
11
|
-
f"/provider/{provider_uuid}/region/{region_uuid}/
|
|
11
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
|
|
12
12
|
"GET",
|
|
13
13
|
kwargs,
|
|
14
14
|
)
|
|
15
|
-
return
|
|
15
|
+
return Service(self.proximl, **resp)
|
|
16
16
|
|
|
17
17
|
async def list(self, provider_uuid, region_uuid, **kwargs):
|
|
18
18
|
resp = await self.proximl._query(
|
|
19
|
-
f"/provider/{provider_uuid}/region/{region_uuid}/
|
|
19
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service",
|
|
20
20
|
"GET",
|
|
21
21
|
kwargs,
|
|
22
22
|
)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]
|
|
26
|
-
return reservations
|
|
23
|
+
services = [Service(self.proximl, **service) for service in resp]
|
|
24
|
+
return services
|
|
27
25
|
|
|
28
26
|
async def create(
|
|
29
27
|
self,
|
|
30
28
|
provider_uuid,
|
|
31
29
|
region_uuid,
|
|
32
30
|
name,
|
|
33
|
-
|
|
34
|
-
resource,
|
|
35
|
-
hostname,
|
|
31
|
+
public,
|
|
36
32
|
**kwargs,
|
|
37
33
|
):
|
|
38
|
-
logging.info(f"Creating
|
|
34
|
+
logging.info(f"Creating Service {name}")
|
|
39
35
|
data = dict(
|
|
40
36
|
name=name,
|
|
41
|
-
|
|
42
|
-
resource=resource,
|
|
43
|
-
hostname=hostname,
|
|
37
|
+
public=public,
|
|
44
38
|
**kwargs,
|
|
45
39
|
)
|
|
46
40
|
payload = {k: v for k, v in data.items() if v is not None}
|
|
47
41
|
resp = await self.proximl._query(
|
|
48
|
-
f"/provider/{provider_uuid}/region/{region_uuid}/
|
|
42
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service",
|
|
49
43
|
"POST",
|
|
50
44
|
None,
|
|
51
45
|
payload,
|
|
52
46
|
)
|
|
53
|
-
|
|
54
|
-
logging.info(f"Created
|
|
55
|
-
return
|
|
47
|
+
service = Service(self.proximl, **resp)
|
|
48
|
+
logging.info(f"Created Service {name} with id {service.id}")
|
|
49
|
+
return service
|
|
56
50
|
|
|
57
51
|
async def remove(self, provider_uuid, region_uuid, id, **kwargs):
|
|
58
52
|
await self.proximl._query(
|
|
59
|
-
f"/provider/{provider_uuid}/region/{region_uuid}/
|
|
53
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
|
|
60
54
|
"DELETE",
|
|
61
55
|
kwargs,
|
|
62
56
|
)
|
|
63
57
|
|
|
64
58
|
|
|
65
|
-
class
|
|
59
|
+
class Service:
|
|
66
60
|
def __init__(self, proximl, **kwargs):
|
|
67
61
|
self.proximl = proximl
|
|
68
|
-
self.
|
|
69
|
-
self._id = self.
|
|
70
|
-
self._provider_uuid = self.
|
|
71
|
-
self._region_uuid = self.
|
|
72
|
-
self.
|
|
73
|
-
self._name = self.
|
|
74
|
-
self.
|
|
75
|
-
self._hostname = self._reservation.get("hostname")
|
|
62
|
+
self._service = kwargs
|
|
63
|
+
self._id = self._service.get("service_id")
|
|
64
|
+
self._provider_uuid = self._service.get("provider_uuid")
|
|
65
|
+
self._region_uuid = self._service.get("region_uuid")
|
|
66
|
+
self._public = self._service.get("public")
|
|
67
|
+
self._name = self._service.get("name")
|
|
68
|
+
self._hostname = self._service.get("hostname")
|
|
76
69
|
|
|
77
70
|
@property
|
|
78
71
|
def id(self) -> str:
|
|
@@ -87,39 +80,35 @@ class Reservation:
|
|
|
87
80
|
return self._region_uuid
|
|
88
81
|
|
|
89
82
|
@property
|
|
90
|
-
def
|
|
91
|
-
return self.
|
|
83
|
+
def public(self) -> bool:
|
|
84
|
+
return self._public
|
|
92
85
|
|
|
93
86
|
@property
|
|
94
87
|
def name(self) -> str:
|
|
95
88
|
return self._name
|
|
96
89
|
|
|
97
|
-
@property
|
|
98
|
-
def resource(self) -> str:
|
|
99
|
-
return self._resource
|
|
100
|
-
|
|
101
90
|
@property
|
|
102
91
|
def hostname(self) -> str:
|
|
103
92
|
return self._hostname
|
|
104
93
|
|
|
105
94
|
def __str__(self):
|
|
106
|
-
return json.dumps({k: v for k, v in self.
|
|
95
|
+
return json.dumps({k: v for k, v in self._service.items()})
|
|
107
96
|
|
|
108
97
|
def __repr__(self):
|
|
109
|
-
return f"
|
|
98
|
+
return f"Service( proximl , **{self._service.__repr__()})"
|
|
110
99
|
|
|
111
100
|
def __bool__(self):
|
|
112
101
|
return bool(self._id)
|
|
113
102
|
|
|
114
103
|
async def remove(self):
|
|
115
104
|
await self.proximl._query(
|
|
116
|
-
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/
|
|
105
|
+
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
|
|
117
106
|
"DELETE",
|
|
118
107
|
)
|
|
119
108
|
|
|
120
109
|
async def refresh(self):
|
|
121
110
|
resp = await self.proximl._query(
|
|
122
|
-
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/
|
|
111
|
+
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
|
|
123
112
|
"GET",
|
|
124
113
|
)
|
|
125
114
|
self.__init__(self.proximl, **resp)
|
|
@@ -97,14 +97,27 @@ class CheckpointError(ProxiMLException):
|
|
|
97
97
|
return self._status
|
|
98
98
|
|
|
99
99
|
def __repr__(self):
|
|
100
|
-
return "CheckpointError({self.status}, {self.message})".format(
|
|
101
|
-
self=self
|
|
102
|
-
)
|
|
100
|
+
return "CheckpointError({self.status}, {self.message})".format(self=self)
|
|
103
101
|
|
|
104
102
|
def __str__(self):
|
|
105
|
-
return "CheckpointError({self.status}, {self.message})".format(
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
return "CheckpointError({self.status}, {self.message})".format(self=self)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class VolumeError(ProxiMLException):
|
|
107
|
+
def __init__(self, status, data, *args):
|
|
108
|
+
super().__init__(data, *args)
|
|
109
|
+
self._status = status
|
|
110
|
+
self._message = data
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def status(self) -> str:
|
|
114
|
+
return self._status
|
|
115
|
+
|
|
116
|
+
def __repr__(self):
|
|
117
|
+
return "VolumeError({self.status}, {self.message})".format(self=self)
|
|
118
|
+
|
|
119
|
+
def __str__(self):
|
|
120
|
+
return "VolumeError({self.status}, {self.message})".format(self=self)
|
|
108
121
|
|
|
109
122
|
|
|
110
123
|
class ConnectionError(ProxiMLException):
|
|
@@ -130,11 +143,7 @@ class SpecificationError(ProxiMLException):
|
|
|
130
143
|
return self._attribute
|
|
131
144
|
|
|
132
145
|
def __repr__(self):
|
|
133
|
-
return "SpecificationError({self.attribute}, {self.message})".format(
|
|
134
|
-
self=self
|
|
135
|
-
)
|
|
146
|
+
return "SpecificationError({self.attribute}, {self.message})".format(self=self)
|
|
136
147
|
|
|
137
148
|
def __str__(self):
|
|
138
|
-
return "SpecificationError({self.attribute}, {self.message})".format(
|
|
139
|
-
self=self
|
|
140
|
-
)
|
|
149
|
+
return "SpecificationError({self.attribute}, {self.message})".format(self=self)
|