trainml 0.5.8__py3-none-any.whl → 0.5.11__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.
- tests/integration/projects/__init__.py +0 -0
- tests/integration/projects/conftest.py +10 -0
- tests/integration/projects/test_projects_data_connectors_integration.py +44 -0
- tests/integration/projects/test_projects_datastores_integration.py +42 -0
- tests/integration/{test_projects_integration.py → projects/test_projects_integration.py} +0 -6
- tests/integration/projects/test_projects_keys_integration.py +43 -0
- tests/integration/projects/test_projects_secrets_integration.py +44 -0
- tests/integration/projects/test_projects_services_integration.py +44 -0
- tests/integration/test_checkpoints_integration.py +1 -2
- tests/integration/test_models_integration.py +0 -1
- tests/unit/cli/projects/__init__.py +0 -0
- tests/unit/cli/projects/test_cli_project_data_connector_unit.py +28 -0
- tests/unit/cli/projects/test_cli_project_datastore_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_key_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_secret_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_service_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_unit.py +19 -0
- tests/unit/cloudbender/test_datastores_unit.py +1 -5
- tests/unit/conftest.py +146 -3
- tests/unit/projects/__init__.py +0 -0
- tests/unit/projects/test_project_data_connectors_unit.py +102 -0
- tests/unit/projects/test_project_datastores_unit.py +96 -0
- tests/unit/projects/test_project_keys_unit.py +96 -0
- tests/unit/projects/test_project_secrets_unit.py +101 -0
- tests/unit/projects/test_project_services_unit.py +102 -0
- tests/unit/projects/test_projects_unit.py +128 -0
- tests/unit/test_checkpoints_unit.py +15 -23
- tests/unit/test_datasets_unit.py +15 -20
- tests/unit/test_models_unit.py +13 -16
- tests/unit/test_volumes_unit.py +3 -0
- trainml/__init__.py +1 -1
- trainml/checkpoints.py +14 -3
- trainml/cli/cloudbender/datastore.py +2 -7
- trainml/cli/project/__init__.py +84 -0
- trainml/cli/project/data_connector.py +61 -0
- trainml/cli/project/datastore.py +61 -0
- trainml/cli/project/key.py +124 -0
- trainml/cli/project/secret.py +71 -0
- trainml/cli/project/service.py +61 -0
- trainml/cloudbender/data_connectors.py +8 -0
- trainml/cloudbender/datastores.py +9 -19
- trainml/cloudbender/nodes.py +44 -1
- trainml/cloudbender/providers.py +53 -0
- trainml/cloudbender/regions.py +48 -0
- trainml/datasets.py +14 -3
- trainml/exceptions.py +51 -0
- trainml/jobs.py +2 -13
- trainml/models.py +14 -3
- trainml/projects/__init__.py +3 -0
- trainml/projects/data_connectors.py +63 -0
- trainml/projects/datastores.py +58 -0
- trainml/projects/keys.py +71 -0
- trainml/projects/projects.py +83 -0
- trainml/projects/secrets.py +70 -0
- trainml/projects/services.py +63 -0
- trainml/volumes.py +15 -3
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/METADATA +1 -1
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/RECORD +64 -38
- tests/unit/cli/cloudbender/test_cli_reservation_unit.py +0 -34
- tests/unit/cli/test_cli_project_unit.py +0 -42
- tests/unit/cloudbender/test_reservations_unit.py +0 -173
- tests/unit/test_projects_unit.py +0 -320
- trainml/cli/cloudbender/reservation.py +0 -159
- trainml/cli/project.py +0 -149
- trainml/cloudbender/reservations.py +0 -126
- trainml/projects.py +0 -228
- /tests/unit/{test_auth.py → test_auth_unit.py} +0 -0
- /tests/unit/{test_trainml.py → test_trainml_unit.py} +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/LICENSE +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/WHEEL +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/entry_points.txt +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/top_level.txt +0 -0
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import json
|
|
3
|
-
import click
|
|
4
|
-
from unittest.mock import AsyncMock, patch, create_autospec
|
|
5
|
-
from pytest import mark, fixture, raises
|
|
6
|
-
|
|
7
|
-
pytestmark = [mark.cli, mark.unit, mark.projects]
|
|
8
|
-
|
|
9
|
-
from trainml.cli import project as specimen
|
|
10
|
-
from trainml.projects import Project
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def test_list(runner, mock_projects):
|
|
14
|
-
with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
|
|
15
|
-
mock_trainml.projects = AsyncMock()
|
|
16
|
-
mock_trainml.projects.list = AsyncMock(return_value=mock_projects)
|
|
17
|
-
result = runner.invoke(specimen, ["list"])
|
|
18
|
-
print(result)
|
|
19
|
-
assert result.exit_code == 0
|
|
20
|
-
mock_trainml.projects.list.assert_called_once()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def test_list_datastores(runner, mock_project_datastores):
|
|
24
|
-
with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
|
|
25
|
-
mock_project = create_autospec(Project)
|
|
26
|
-
mock_project.list_datastores = AsyncMock(return_value=mock_project_datastores)
|
|
27
|
-
mock_trainml.projects.get = AsyncMock(return_value=mock_project)
|
|
28
|
-
result = runner.invoke(specimen, ["list-datastores"])
|
|
29
|
-
print(result)
|
|
30
|
-
assert result.exit_code == 0
|
|
31
|
-
mock_project.list_datastores.assert_called_once()
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def test_list_services(runner, mock_project_services):
|
|
35
|
-
with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
|
|
36
|
-
mock_project = create_autospec(Project)
|
|
37
|
-
mock_project.list_services = AsyncMock(return_value=mock_project_services)
|
|
38
|
-
mock_trainml.projects.get = AsyncMock(return_value=mock_project)
|
|
39
|
-
result = runner.invoke(specimen, ["list-services"])
|
|
40
|
-
print(result)
|
|
41
|
-
assert result.exit_code == 0
|
|
42
|
-
mock_project.list_services.assert_called_once()
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import json
|
|
3
|
-
import logging
|
|
4
|
-
from unittest.mock import AsyncMock, patch
|
|
5
|
-
from pytest import mark, fixture, raises
|
|
6
|
-
from aiohttp import WSMessage, WSMsgType
|
|
7
|
-
|
|
8
|
-
import trainml.cloudbender.reservations as specimen
|
|
9
|
-
from trainml.exceptions import (
|
|
10
|
-
ApiError,
|
|
11
|
-
SpecificationError,
|
|
12
|
-
TrainMLException,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
pytestmark = [mark.sdk, mark.unit, mark.cloudbender, mark.reservations]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@fixture
|
|
19
|
-
def reservations(mock_trainml):
|
|
20
|
-
yield specimen.Reservations(mock_trainml)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@fixture
|
|
24
|
-
def reservation(mock_trainml):
|
|
25
|
-
yield specimen.Reservation(
|
|
26
|
-
mock_trainml,
|
|
27
|
-
provider_uuid="1",
|
|
28
|
-
region_uuid="a",
|
|
29
|
-
reservation_id="x",
|
|
30
|
-
name="On-Prem Reservation",
|
|
31
|
-
type="port",
|
|
32
|
-
resource="8001",
|
|
33
|
-
hostname="service.local",
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class RegionsTests:
|
|
38
|
-
@mark.asyncio
|
|
39
|
-
async def test_get_reservation(
|
|
40
|
-
self,
|
|
41
|
-
reservations,
|
|
42
|
-
mock_trainml,
|
|
43
|
-
):
|
|
44
|
-
api_response = dict()
|
|
45
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
46
|
-
await reservations.get("1234", "5687", "91011")
|
|
47
|
-
mock_trainml._query.assert_called_once_with(
|
|
48
|
-
"/provider/1234/region/5687/reservation/91011", "GET", {}
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
@mark.asyncio
|
|
52
|
-
async def test_list_reservations(
|
|
53
|
-
self,
|
|
54
|
-
reservations,
|
|
55
|
-
mock_trainml,
|
|
56
|
-
):
|
|
57
|
-
api_response = dict()
|
|
58
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
59
|
-
await reservations.list("1234", "5687")
|
|
60
|
-
mock_trainml._query.assert_called_once_with(
|
|
61
|
-
"/provider/1234/region/5687/reservation", "GET", {}
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
@mark.asyncio
|
|
65
|
-
async def test_remove_reservation(
|
|
66
|
-
self,
|
|
67
|
-
reservations,
|
|
68
|
-
mock_trainml,
|
|
69
|
-
):
|
|
70
|
-
api_response = dict()
|
|
71
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
72
|
-
await reservations.remove("1234", "4567", "8910")
|
|
73
|
-
mock_trainml._query.assert_called_once_with(
|
|
74
|
-
"/provider/1234/region/4567/reservation/8910", "DELETE", {}
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
@mark.asyncio
|
|
78
|
-
async def test_create_reservation(self, reservations, mock_trainml):
|
|
79
|
-
requested_config = dict(
|
|
80
|
-
provider_uuid="provider-id-1",
|
|
81
|
-
region_uuid="region-id-1",
|
|
82
|
-
name="On-Prem Reservation",
|
|
83
|
-
type="port",
|
|
84
|
-
resource="8001",
|
|
85
|
-
hostname="service.local",
|
|
86
|
-
)
|
|
87
|
-
expected_payload = dict(
|
|
88
|
-
name="On-Prem Reservation",
|
|
89
|
-
type="port",
|
|
90
|
-
resource="8001",
|
|
91
|
-
hostname="service.local",
|
|
92
|
-
)
|
|
93
|
-
api_response = {
|
|
94
|
-
"provider_uuid": "provider-id-1",
|
|
95
|
-
"region_uuid": "region-id-1",
|
|
96
|
-
"reservation_id": "reservation-id-1",
|
|
97
|
-
"name": "On-Prem Reservation",
|
|
98
|
-
"type": "port",
|
|
99
|
-
"resource": "8001",
|
|
100
|
-
"hostname": "service.local",
|
|
101
|
-
"createdAt": "2020-12-31T23:59:59.000Z",
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
105
|
-
response = await reservations.create(**requested_config)
|
|
106
|
-
mock_trainml._query.assert_called_once_with(
|
|
107
|
-
"/provider/provider-id-1/region/region-id-1/reservation",
|
|
108
|
-
"POST",
|
|
109
|
-
None,
|
|
110
|
-
expected_payload,
|
|
111
|
-
)
|
|
112
|
-
assert response.id == "reservation-id-1"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class reservationTests:
|
|
116
|
-
def test_reservation_properties(self, reservation):
|
|
117
|
-
assert isinstance(reservation.id, str)
|
|
118
|
-
assert isinstance(reservation.provider_uuid, str)
|
|
119
|
-
assert isinstance(reservation.region_uuid, str)
|
|
120
|
-
assert isinstance(reservation.type, str)
|
|
121
|
-
assert isinstance(reservation.name, str)
|
|
122
|
-
assert isinstance(reservation.resource, str)
|
|
123
|
-
assert isinstance(reservation.hostname, str)
|
|
124
|
-
|
|
125
|
-
def test_reservation_str(self, reservation):
|
|
126
|
-
string = str(reservation)
|
|
127
|
-
regex = r"^{.*\"reservation_id\": \"" + reservation.id + r"\".*}$"
|
|
128
|
-
assert isinstance(string, str)
|
|
129
|
-
assert re.match(regex, string)
|
|
130
|
-
|
|
131
|
-
def test_reservation_repr(self, reservation):
|
|
132
|
-
string = repr(reservation)
|
|
133
|
-
regex = (
|
|
134
|
-
r"^Reservation\( trainml , \*\*{.*'reservation_id': '"
|
|
135
|
-
+ reservation.id
|
|
136
|
-
+ r"'.*}\)$"
|
|
137
|
-
)
|
|
138
|
-
assert isinstance(string, str)
|
|
139
|
-
assert re.match(regex, string)
|
|
140
|
-
|
|
141
|
-
def test_reservation_bool(self, reservation, mock_trainml):
|
|
142
|
-
empty_reservation = specimen.Reservation(mock_trainml)
|
|
143
|
-
assert bool(reservation)
|
|
144
|
-
assert not bool(empty_reservation)
|
|
145
|
-
|
|
146
|
-
@mark.asyncio
|
|
147
|
-
async def test_reservation_remove(self, reservation, mock_trainml):
|
|
148
|
-
api_response = dict()
|
|
149
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
150
|
-
await reservation.remove()
|
|
151
|
-
mock_trainml._query.assert_called_once_with(
|
|
152
|
-
"/provider/1/region/a/reservation/x", "DELETE"
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
@mark.asyncio
|
|
156
|
-
async def test_reservation_refresh(self, reservation, mock_trainml):
|
|
157
|
-
api_response = {
|
|
158
|
-
"provider_uuid": "provider-id-1",
|
|
159
|
-
"region_uuid": "region-id-1",
|
|
160
|
-
"reservation_id": "reservation-id-1",
|
|
161
|
-
"name": "On-Prem Reservation",
|
|
162
|
-
"type": "port",
|
|
163
|
-
"resource": "8001",
|
|
164
|
-
"hostname": "service.local",
|
|
165
|
-
"createdAt": "2020-12-31T23:59:59.000Z",
|
|
166
|
-
}
|
|
167
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
168
|
-
response = await reservation.refresh()
|
|
169
|
-
mock_trainml._query.assert_called_once_with(
|
|
170
|
-
f"/provider/1/region/a/reservation/x", "GET"
|
|
171
|
-
)
|
|
172
|
-
assert reservation.id == "reservation-id-1"
|
|
173
|
-
assert response.id == "reservation-id-1"
|
tests/unit/test_projects_unit.py
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import json
|
|
3
|
-
import logging
|
|
4
|
-
from unittest.mock import AsyncMock, patch
|
|
5
|
-
from pytest import mark, fixture, raises
|
|
6
|
-
from aiohttp import WSMessage, WSMsgType
|
|
7
|
-
|
|
8
|
-
import trainml.projects as specimen
|
|
9
|
-
from trainml.exceptions import (
|
|
10
|
-
ApiError,
|
|
11
|
-
SpecificationError,
|
|
12
|
-
TrainMLException,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
pytestmark = [mark.sdk, mark.unit, mark.projects]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@fixture
|
|
19
|
-
def projects(mock_trainml):
|
|
20
|
-
yield specimen.Projects(mock_trainml)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@fixture
|
|
24
|
-
def project(mock_trainml):
|
|
25
|
-
yield specimen.Project(
|
|
26
|
-
mock_trainml,
|
|
27
|
-
id="1",
|
|
28
|
-
name="My Mock Project",
|
|
29
|
-
owner=True,
|
|
30
|
-
owner_name="Me",
|
|
31
|
-
created_name="Me",
|
|
32
|
-
job_all=True,
|
|
33
|
-
dataset_all=True,
|
|
34
|
-
model_all=True,
|
|
35
|
-
createdAt="2020-12-31T23:59:59.000Z",
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@fixture
|
|
40
|
-
def project_datastore(mock_trainml):
|
|
41
|
-
yield specimen.ProjectDatastore(
|
|
42
|
-
mock_trainml,
|
|
43
|
-
id="ds-id-1",
|
|
44
|
-
name="datastore 1",
|
|
45
|
-
project_uuid="proj-id-1",
|
|
46
|
-
type="nfs",
|
|
47
|
-
region_uuid="reg-id-1",
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@fixture
|
|
52
|
-
def project_data_connector(mock_trainml):
|
|
53
|
-
yield specimen.ProjectDataConnector(
|
|
54
|
-
mock_trainml,
|
|
55
|
-
id="ds-id-1",
|
|
56
|
-
name="connector 1",
|
|
57
|
-
project_uuid="proj-id-1",
|
|
58
|
-
type="custom",
|
|
59
|
-
region_uuid="reg-id-1",
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@fixture
|
|
64
|
-
def project_service(mock_trainml):
|
|
65
|
-
yield specimen.ProjectService(
|
|
66
|
-
mock_trainml,
|
|
67
|
-
id="res-id-1",
|
|
68
|
-
name="service 1",
|
|
69
|
-
project_uuid="proj-id-1",
|
|
70
|
-
region_uuid="reg-id-1",
|
|
71
|
-
public=False,
|
|
72
|
-
hostname="asdf.proximl.cloud",
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
class ProjectsTests:
|
|
77
|
-
@mark.asyncio
|
|
78
|
-
async def test_get_project(
|
|
79
|
-
self,
|
|
80
|
-
projects,
|
|
81
|
-
mock_trainml,
|
|
82
|
-
):
|
|
83
|
-
api_response = dict()
|
|
84
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
85
|
-
await projects.get("1234")
|
|
86
|
-
mock_trainml._query.assert_called_once_with("/project/1234", "GET", dict())
|
|
87
|
-
|
|
88
|
-
@mark.asyncio
|
|
89
|
-
async def test_list_projects(
|
|
90
|
-
self,
|
|
91
|
-
projects,
|
|
92
|
-
mock_trainml,
|
|
93
|
-
):
|
|
94
|
-
api_response = dict()
|
|
95
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
96
|
-
await projects.list()
|
|
97
|
-
mock_trainml._query.assert_called_once_with("/project", "GET", dict())
|
|
98
|
-
|
|
99
|
-
@mark.asyncio
|
|
100
|
-
async def test_remove_project(
|
|
101
|
-
self,
|
|
102
|
-
projects,
|
|
103
|
-
mock_trainml,
|
|
104
|
-
):
|
|
105
|
-
api_response = dict()
|
|
106
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
107
|
-
await projects.remove("4567")
|
|
108
|
-
mock_trainml._query.assert_called_once_with("/project/4567", "DELETE", dict())
|
|
109
|
-
|
|
110
|
-
@mark.asyncio
|
|
111
|
-
async def test_create_project_simple(self, projects, mock_trainml):
|
|
112
|
-
requested_config = dict(
|
|
113
|
-
name="new project",
|
|
114
|
-
)
|
|
115
|
-
expected_payload = dict(name="new project", copy_keys=False)
|
|
116
|
-
api_response = {
|
|
117
|
-
"id": "project-id-1",
|
|
118
|
-
"name": "new project",
|
|
119
|
-
"owner": True,
|
|
120
|
-
"owner_name": "Me",
|
|
121
|
-
"created_name": "Me",
|
|
122
|
-
"job_all": True,
|
|
123
|
-
"dataset_all": True,
|
|
124
|
-
"model_all": True,
|
|
125
|
-
"createdAt": "2020-12-31T23:59:59.000Z",
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
129
|
-
response = await projects.create(**requested_config)
|
|
130
|
-
mock_trainml._query.assert_called_once_with(
|
|
131
|
-
"/project", "POST", None, expected_payload
|
|
132
|
-
)
|
|
133
|
-
assert response.id == "project-id-1"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
class ProjectDatastoreTests:
|
|
137
|
-
def test_project_datastore_properties(self, project_datastore):
|
|
138
|
-
assert isinstance(project_datastore.id, str)
|
|
139
|
-
assert isinstance(project_datastore.name, str)
|
|
140
|
-
assert isinstance(project_datastore.project_uuid, str)
|
|
141
|
-
assert isinstance(project_datastore.type, str)
|
|
142
|
-
assert isinstance(project_datastore.region_uuid, str)
|
|
143
|
-
|
|
144
|
-
def test_project_datastore_str(self, project_datastore):
|
|
145
|
-
string = str(project_datastore)
|
|
146
|
-
regex = r"^{.*\"id\": \"" + project_datastore.id + r"\".*}$"
|
|
147
|
-
assert isinstance(string, str)
|
|
148
|
-
assert re.match(regex, string)
|
|
149
|
-
|
|
150
|
-
def test_project_datastore_repr(self, project_datastore):
|
|
151
|
-
string = repr(project_datastore)
|
|
152
|
-
regex = (
|
|
153
|
-
r"^ProjectDatastore\( trainml , \*\*{.*'id': '"
|
|
154
|
-
+ project_datastore.id
|
|
155
|
-
+ r"'.*}\)$"
|
|
156
|
-
)
|
|
157
|
-
assert isinstance(string, str)
|
|
158
|
-
assert re.match(regex, string)
|
|
159
|
-
|
|
160
|
-
def test_project_datastore_bool(self, project_datastore, mock_trainml):
|
|
161
|
-
empty_project_datastore = specimen.ProjectDatastore(mock_trainml)
|
|
162
|
-
assert bool(project_datastore)
|
|
163
|
-
assert not bool(empty_project_datastore)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
class ProjectDataConnectorTests:
|
|
167
|
-
def test_project_data_connector_properties(self, project_data_connector):
|
|
168
|
-
assert isinstance(project_data_connector.id, str)
|
|
169
|
-
assert isinstance(project_data_connector.name, str)
|
|
170
|
-
assert isinstance(project_data_connector.project_uuid, str)
|
|
171
|
-
assert isinstance(project_data_connector.type, str)
|
|
172
|
-
assert isinstance(project_data_connector.region_uuid, str)
|
|
173
|
-
|
|
174
|
-
def test_project_data_connector_str(self, project_data_connector):
|
|
175
|
-
string = str(project_data_connector)
|
|
176
|
-
regex = r"^{.*\"id\": \"" + project_data_connector.id + r"\".*}$"
|
|
177
|
-
assert isinstance(string, str)
|
|
178
|
-
assert re.match(regex, string)
|
|
179
|
-
|
|
180
|
-
def test_project_data_connector_repr(self, project_data_connector):
|
|
181
|
-
string = repr(project_data_connector)
|
|
182
|
-
regex = (
|
|
183
|
-
r"^ProjectDataConnector\( trainml , \*\*{.*'id': '"
|
|
184
|
-
+ project_data_connector.id
|
|
185
|
-
+ r"'.*}\)$"
|
|
186
|
-
)
|
|
187
|
-
assert isinstance(string, str)
|
|
188
|
-
assert re.match(regex, string)
|
|
189
|
-
|
|
190
|
-
def test_project_data_connector_bool(self, project_data_connector, mock_trainml):
|
|
191
|
-
empty_project_data_connector = specimen.ProjectDataConnector(mock_trainml)
|
|
192
|
-
assert bool(project_data_connector)
|
|
193
|
-
assert not bool(empty_project_data_connector)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
class ProjectServiceTests:
|
|
197
|
-
def test_project_service_properties(self, project_service):
|
|
198
|
-
assert isinstance(project_service.id, str)
|
|
199
|
-
assert isinstance(project_service.name, str)
|
|
200
|
-
assert isinstance(project_service.project_uuid, str)
|
|
201
|
-
assert isinstance(project_service.hostname, str)
|
|
202
|
-
assert isinstance(project_service.public, bool)
|
|
203
|
-
assert isinstance(project_service.region_uuid, str)
|
|
204
|
-
|
|
205
|
-
def test_project_service_str(self, project_service):
|
|
206
|
-
string = str(project_service)
|
|
207
|
-
regex = r"^{.*\"id\": \"" + project_service.id + r"\".*}$"
|
|
208
|
-
assert isinstance(string, str)
|
|
209
|
-
assert re.match(regex, string)
|
|
210
|
-
|
|
211
|
-
def test_project_service_repr(self, project_service):
|
|
212
|
-
string = repr(project_service)
|
|
213
|
-
regex = (
|
|
214
|
-
r"^ProjectService\( trainml , \*\*{.*'id': '"
|
|
215
|
-
+ project_service.id
|
|
216
|
-
+ r"'.*}\)$"
|
|
217
|
-
)
|
|
218
|
-
assert isinstance(string, str)
|
|
219
|
-
assert re.match(regex, string)
|
|
220
|
-
|
|
221
|
-
def test_project_service_bool(self, project_service, mock_trainml):
|
|
222
|
-
empty_project_service = specimen.ProjectService(mock_trainml)
|
|
223
|
-
assert bool(project_service)
|
|
224
|
-
assert not bool(empty_project_service)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
class ProjectTests:
|
|
228
|
-
def test_project_properties(self, project):
|
|
229
|
-
assert isinstance(project.id, str)
|
|
230
|
-
assert isinstance(project.name, str)
|
|
231
|
-
assert isinstance(project.owner_name, str)
|
|
232
|
-
assert isinstance(project.is_owner, bool)
|
|
233
|
-
|
|
234
|
-
def test_project_str(self, project):
|
|
235
|
-
string = str(project)
|
|
236
|
-
regex = r"^{.*\"id\": \"" + project.id + r"\".*}$"
|
|
237
|
-
assert isinstance(string, str)
|
|
238
|
-
assert re.match(regex, string)
|
|
239
|
-
|
|
240
|
-
def test_project_repr(self, project):
|
|
241
|
-
string = repr(project)
|
|
242
|
-
regex = r"^Project\( trainml , \*\*{.*'id': '" + project.id + r"'.*}\)$"
|
|
243
|
-
assert isinstance(string, str)
|
|
244
|
-
assert re.match(regex, string)
|
|
245
|
-
|
|
246
|
-
def test_project_bool(self, project, mock_trainml):
|
|
247
|
-
empty_project = specimen.Project(mock_trainml)
|
|
248
|
-
assert bool(project)
|
|
249
|
-
assert not bool(empty_project)
|
|
250
|
-
|
|
251
|
-
@mark.asyncio
|
|
252
|
-
async def test_project_remove(self, project, mock_trainml):
|
|
253
|
-
api_response = dict()
|
|
254
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
255
|
-
await project.remove()
|
|
256
|
-
mock_trainml._query.assert_called_once_with("/project/1", "DELETE")
|
|
257
|
-
|
|
258
|
-
@mark.asyncio
|
|
259
|
-
async def test_project_refresh_datastores(self, project, mock_trainml):
|
|
260
|
-
api_response = dict()
|
|
261
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
262
|
-
await project.refresh_datastores()
|
|
263
|
-
mock_trainml._query.assert_called_once_with("/project/1/datastores", "PATCH")
|
|
264
|
-
|
|
265
|
-
@mark.asyncio
|
|
266
|
-
async def test_project_refresh_services(self, project, mock_trainml):
|
|
267
|
-
api_response = dict()
|
|
268
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
269
|
-
await project.refresh_services()
|
|
270
|
-
mock_trainml._query.assert_called_once_with("/project/1/services", "PATCH")
|
|
271
|
-
|
|
272
|
-
@mark.asyncio
|
|
273
|
-
async def test_project_list_datastores(self, project, mock_trainml):
|
|
274
|
-
api_response = [
|
|
275
|
-
{
|
|
276
|
-
"project_uuid": "proj-id-1",
|
|
277
|
-
"region_uuid": "reg-id-1",
|
|
278
|
-
"id": "store-id-1",
|
|
279
|
-
"type": "nfs",
|
|
280
|
-
"name": "On-prem NFS",
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
"project_uuid": "proj-id-1",
|
|
284
|
-
"region_uuid": "reg-id-2",
|
|
285
|
-
"id": "store-id-2",
|
|
286
|
-
"type": "smb",
|
|
287
|
-
"name": "GCP Samba",
|
|
288
|
-
},
|
|
289
|
-
]
|
|
290
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
291
|
-
resp = await project.list_datastores()
|
|
292
|
-
mock_trainml._query.assert_called_once_with("/project/1/datastores", "GET")
|
|
293
|
-
assert len(resp) == 2
|
|
294
|
-
|
|
295
|
-
@mark.asyncio
|
|
296
|
-
async def test_project_list_services(self, project, mock_trainml):
|
|
297
|
-
api_response = [
|
|
298
|
-
{
|
|
299
|
-
"project_uuid": "proj-id-1",
|
|
300
|
-
"region_uuid": "reg-id-1",
|
|
301
|
-
"id": "res-id-1",
|
|
302
|
-
"type": "port",
|
|
303
|
-
"name": "On-Prem Service A",
|
|
304
|
-
"resource": "8001",
|
|
305
|
-
"hostname": "service-a.local",
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
"project_uuid": "proj-id-1",
|
|
309
|
-
"region_uuid": "reg-id-2",
|
|
310
|
-
"id": "res-id-2",
|
|
311
|
-
"type": "port",
|
|
312
|
-
"name": "Cloud Service B",
|
|
313
|
-
"resource": "8001",
|
|
314
|
-
"hostname": "service-b.local",
|
|
315
|
-
},
|
|
316
|
-
]
|
|
317
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
318
|
-
resp = await project.list_services()
|
|
319
|
-
mock_trainml._query.assert_called_once_with("/project/1/services", "GET")
|
|
320
|
-
assert len(resp) == 2
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
from trainml.cli import cli, pass_config, search_by_id_name
|
|
3
|
-
from trainml.cli.cloudbender import cloudbender
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@cloudbender.group()
|
|
7
|
-
@pass_config
|
|
8
|
-
def reservation(config):
|
|
9
|
-
"""trainML CloudBender reservation commands."""
|
|
10
|
-
pass
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@reservation.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 reservations for.",
|
|
27
|
-
)
|
|
28
|
-
@pass_config
|
|
29
|
-
def list(config, provider, region):
|
|
30
|
-
"""List reservations."""
|
|
31
|
-
data = [
|
|
32
|
-
["ID", "NAME", "TYPE", "RESOURCE", "HOSTNAME"],
|
|
33
|
-
[
|
|
34
|
-
"-" * 80,
|
|
35
|
-
"-" * 80,
|
|
36
|
-
"-" * 80,
|
|
37
|
-
"-" * 80,
|
|
38
|
-
"-" * 80,
|
|
39
|
-
],
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
reservations = config.trainml.run(
|
|
43
|
-
config.trainml.client.cloudbender.reservations.list(
|
|
44
|
-
provider_uuid=provider, region_uuid=region
|
|
45
|
-
)
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
for reservation in reservations:
|
|
49
|
-
data.append(
|
|
50
|
-
[
|
|
51
|
-
reservation.id,
|
|
52
|
-
reservation.name,
|
|
53
|
-
reservation.type,
|
|
54
|
-
reservation.resource,
|
|
55
|
-
reservation.hostname,
|
|
56
|
-
]
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
for row in data:
|
|
60
|
-
click.echo(
|
|
61
|
-
"{: >37.36} {: >29.28} {: >9.8} {: >9.8} {: >29.28}"
|
|
62
|
-
"".format(*row),
|
|
63
|
-
file=config.stdout,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@reservation.command()
|
|
68
|
-
@click.option(
|
|
69
|
-
"--provider",
|
|
70
|
-
"-p",
|
|
71
|
-
type=click.STRING,
|
|
72
|
-
required=True,
|
|
73
|
-
help="The provider ID of the region.",
|
|
74
|
-
)
|
|
75
|
-
@click.option(
|
|
76
|
-
"--region",
|
|
77
|
-
"-r",
|
|
78
|
-
type=click.STRING,
|
|
79
|
-
required=True,
|
|
80
|
-
help="The region ID to create the reservation in.",
|
|
81
|
-
)
|
|
82
|
-
@click.option(
|
|
83
|
-
"--type",
|
|
84
|
-
"-t",
|
|
85
|
-
type=click.Choice(
|
|
86
|
-
[
|
|
87
|
-
"port",
|
|
88
|
-
],
|
|
89
|
-
case_sensitive=False,
|
|
90
|
-
),
|
|
91
|
-
required=True,
|
|
92
|
-
help="The type of reservation to create.",
|
|
93
|
-
)
|
|
94
|
-
@click.option(
|
|
95
|
-
"--hostname",
|
|
96
|
-
"-h",
|
|
97
|
-
type=click.STRING,
|
|
98
|
-
required=True,
|
|
99
|
-
help="The hostname to make the reservation on",
|
|
100
|
-
)
|
|
101
|
-
@click.option(
|
|
102
|
-
"--resource",
|
|
103
|
-
"-r",
|
|
104
|
-
type=click.STRING,
|
|
105
|
-
required=True,
|
|
106
|
-
help="The resource to reserve",
|
|
107
|
-
)
|
|
108
|
-
@click.argument("name", type=click.STRING, required=True)
|
|
109
|
-
@pass_config
|
|
110
|
-
def create(config, provider, region, type, hostname, resource, name):
|
|
111
|
-
"""
|
|
112
|
-
Creates a reservation.
|
|
113
|
-
"""
|
|
114
|
-
return config.trainml.run(
|
|
115
|
-
config.trainml.client.cloudbender.reservations.create(
|
|
116
|
-
provider_uuid=provider,
|
|
117
|
-
region_uuid=region,
|
|
118
|
-
name=name,
|
|
119
|
-
hostname=hostname,
|
|
120
|
-
resource=resource,
|
|
121
|
-
type=type,
|
|
122
|
-
)
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@reservation.command()
|
|
127
|
-
@click.option(
|
|
128
|
-
"--provider",
|
|
129
|
-
"-p",
|
|
130
|
-
type=click.STRING,
|
|
131
|
-
required=True,
|
|
132
|
-
help="The provider ID of the region.",
|
|
133
|
-
)
|
|
134
|
-
@click.option(
|
|
135
|
-
"--region",
|
|
136
|
-
"-r",
|
|
137
|
-
type=click.STRING,
|
|
138
|
-
required=True,
|
|
139
|
-
help="The region ID to remove the reservation from.",
|
|
140
|
-
)
|
|
141
|
-
@click.argument("reservation", type=click.STRING)
|
|
142
|
-
@pass_config
|
|
143
|
-
def remove(config, provider, region, reservation):
|
|
144
|
-
"""
|
|
145
|
-
Remove a reservation.
|
|
146
|
-
|
|
147
|
-
RESERVATION may be specified by name or ID, but ID is preferred.
|
|
148
|
-
"""
|
|
149
|
-
reservations = config.trainml.run(
|
|
150
|
-
config.trainml.client.cloudbender.reservations.list(
|
|
151
|
-
provider_uuid=provider, region_uuid=region
|
|
152
|
-
)
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
found = search_by_id_name(reservation, reservations)
|
|
156
|
-
if None is found:
|
|
157
|
-
raise click.UsageError("Cannot find specified reservation.")
|
|
158
|
-
|
|
159
|
-
return config.trainml.run(found.remove())
|