proximl 0.5.4__py3-none-any.whl → 0.5.6__py3-none-any.whl
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/__init__.py +1 -1
- proximl/cli/__init__.py +3 -6
- proximl/cli/cloudbender/service.py +129 -0
- proximl/cli/volume.py +235 -0
- proximl/cloudbender/services.py +115 -0
- proximl/exceptions.py +21 -12
- proximl/jobs.py +36 -39
- proximl/proximl.py +7 -15
- proximl/volumes.py +255 -0
- {proximl-0.5.4.dist-info → proximl-0.5.6.dist-info}/METADATA +1 -1
- {proximl-0.5.4.dist-info → proximl-0.5.6.dist-info}/RECORD +25 -17
- tests/integration/test_checkpoints_integration.py +7 -5
- tests/integration/test_datasets_integration.py +4 -5
- tests/integration/test_jobs_integration.py +40 -2
- tests/integration/test_models_integration.py +8 -10
- tests/integration/test_projects_integration.py +2 -6
- tests/integration/test_volumes_integration.py +100 -0
- tests/unit/cli/test_cli_volume_unit.py +20 -0
- tests/unit/cloudbender/test_services_unit.py +161 -0
- tests/unit/conftest.py +82 -9
- tests/unit/test_volumes_unit.py +447 -0
- {proximl-0.5.4.dist-info → proximl-0.5.6.dist-info}/LICENSE +0 -0
- {proximl-0.5.4.dist-info → proximl-0.5.6.dist-info}/WHEEL +0 -0
- {proximl-0.5.4.dist-info → proximl-0.5.6.dist-info}/entry_points.txt +0 -0
- {proximl-0.5.4.dist-info → proximl-0.5.6.dist-info}/top_level.txt +0 -0
proximl/__init__.py
CHANGED
proximl/cli/__init__.py
CHANGED
|
@@ -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
|
|
@@ -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())
|
proximl/cli/volume.py
ADDED
|
@@ -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))
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Services(object):
|
|
6
|
+
def __init__(self, proximl):
|
|
7
|
+
self.proximl = proximl
|
|
8
|
+
|
|
9
|
+
async def get(self, provider_uuid, region_uuid, id, **kwargs):
|
|
10
|
+
resp = await self.proximl._query(
|
|
11
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
|
|
12
|
+
"GET",
|
|
13
|
+
kwargs,
|
|
14
|
+
)
|
|
15
|
+
return Service(self.proximl, **resp)
|
|
16
|
+
|
|
17
|
+
async def list(self, provider_uuid, region_uuid, **kwargs):
|
|
18
|
+
resp = await self.proximl._query(
|
|
19
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service",
|
|
20
|
+
"GET",
|
|
21
|
+
kwargs,
|
|
22
|
+
)
|
|
23
|
+
services = [Service(self.proximl, **service) for service in resp]
|
|
24
|
+
return services
|
|
25
|
+
|
|
26
|
+
async def create(
|
|
27
|
+
self,
|
|
28
|
+
provider_uuid,
|
|
29
|
+
region_uuid,
|
|
30
|
+
name,
|
|
31
|
+
public,
|
|
32
|
+
**kwargs,
|
|
33
|
+
):
|
|
34
|
+
logging.info(f"Creating Service {name}")
|
|
35
|
+
data = dict(
|
|
36
|
+
name=name,
|
|
37
|
+
public=public,
|
|
38
|
+
**kwargs,
|
|
39
|
+
)
|
|
40
|
+
payload = {k: v for k, v in data.items() if v is not None}
|
|
41
|
+
resp = await self.proximl._query(
|
|
42
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service",
|
|
43
|
+
"POST",
|
|
44
|
+
None,
|
|
45
|
+
payload,
|
|
46
|
+
)
|
|
47
|
+
service = Service(self.proximl, **resp)
|
|
48
|
+
logging.info(f"Created Service {name} with id {service.id}")
|
|
49
|
+
return service
|
|
50
|
+
|
|
51
|
+
async def remove(self, provider_uuid, region_uuid, id, **kwargs):
|
|
52
|
+
await self.proximl._query(
|
|
53
|
+
f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
|
|
54
|
+
"DELETE",
|
|
55
|
+
kwargs,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class Service:
|
|
60
|
+
def __init__(self, proximl, **kwargs):
|
|
61
|
+
self.proximl = proximl
|
|
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")
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def id(self) -> str:
|
|
72
|
+
return self._id
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def provider_uuid(self) -> str:
|
|
76
|
+
return self._provider_uuid
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def region_uuid(self) -> str:
|
|
80
|
+
return self._region_uuid
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def public(self) -> bool:
|
|
84
|
+
return self._public
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def name(self) -> str:
|
|
88
|
+
return self._name
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def hostname(self) -> str:
|
|
92
|
+
return self._hostname
|
|
93
|
+
|
|
94
|
+
def __str__(self):
|
|
95
|
+
return json.dumps({k: v for k, v in self._service.items()})
|
|
96
|
+
|
|
97
|
+
def __repr__(self):
|
|
98
|
+
return f"Service( proximl , **{self._service.__repr__()})"
|
|
99
|
+
|
|
100
|
+
def __bool__(self):
|
|
101
|
+
return bool(self._id)
|
|
102
|
+
|
|
103
|
+
async def remove(self):
|
|
104
|
+
await self.proximl._query(
|
|
105
|
+
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
|
|
106
|
+
"DELETE",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
async def refresh(self):
|
|
110
|
+
resp = await self.proximl._query(
|
|
111
|
+
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
|
|
112
|
+
"GET",
|
|
113
|
+
)
|
|
114
|
+
self.__init__(self.proximl, **resp)
|
|
115
|
+
return self
|
proximl/exceptions.py
CHANGED
|
@@ -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)
|