proximl 0.5.10__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.
- proximl/__init__.py +1 -1
- proximl/checkpoints.py +46 -28
- proximl/cli/cloudbender/__init__.py +2 -1
- proximl/cli/cloudbender/datastore.py +2 -7
- proximl/cli/cloudbender/service.py +19 -2
- proximl/cli/project/__init__.py +3 -72
- proximl/cli/project/data_connector.py +61 -0
- proximl/cli/project/datastore.py +61 -0
- proximl/cli/project/service.py +61 -0
- proximl/cloudbender/cloudbender.py +4 -2
- proximl/cloudbender/data_connectors.py +8 -0
- proximl/cloudbender/datastores.py +9 -19
- proximl/cloudbender/nodes.py +44 -1
- proximl/cloudbender/providers.py +53 -0
- proximl/cloudbender/regions.py +48 -0
- proximl/cloudbender/services.py +65 -1
- proximl/datasets.py +41 -12
- proximl/exceptions.py +51 -0
- proximl/jobs.py +15 -19
- proximl/models.py +41 -22
- proximl/volumes.py +24 -5
- {proximl-0.5.10.dist-info → proximl-0.5.11.dist-info}/METADATA +1 -1
- {proximl-0.5.10.dist-info → proximl-0.5.11.dist-info}/RECORD +48 -46
- tests/integration/projects/conftest.py +3 -1
- tests/integration/projects/test_projects_data_connectors_integration.py +44 -0
- tests/integration/projects/test_projects_datastores_integration.py +42 -0
- tests/integration/projects/test_projects_services_integration.py +44 -0
- tests/integration/test_checkpoints_integration.py +1 -2
- tests/integration/test_jobs_integration.py +13 -0
- 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/cloudbender/test_services_unit.py +6 -0
- tests/unit/conftest.py +158 -15
- 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
- proximl/cli/cloudbender/reservation.py +0 -159
- proximl/cli/project.py +0 -154
- proximl/cloudbender/reservations.py +0 -126
- proximl/projects.py +0 -187
- tests/integration/test_projects_integration.py +0 -44
- tests/unit/cli/cloudbender/test_cli_reservation_unit.py +0 -38
- tests/unit/cli/test_cli_project_unit.py +0 -46
- tests/unit/cloudbender/test_reservations_unit.py +0 -173
- tests/unit/test_auth.py +0 -30
- tests/unit/test_projects_unit.py +0 -294
- tests/unit/test_proximl.py +0 -54
- {proximl-0.5.10.dist-info → proximl-0.5.11.dist-info}/LICENSE +0 -0
- {proximl-0.5.10.dist-info → proximl-0.5.11.dist-info}/WHEEL +0 -0
- {proximl-0.5.10.dist-info → proximl-0.5.11.dist-info}/entry_points.txt +0 -0
- {proximl-0.5.10.dist-info → proximl-0.5.11.dist-info}/top_level.txt +0 -0
|
@@ -1,159 +0,0 @@
|
|
|
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 reservation(config):
|
|
9
|
-
"""proxiML 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.proximl.run(
|
|
43
|
-
config.proximl.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.proximl.run(
|
|
115
|
-
config.proximl.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.proximl.run(
|
|
150
|
-
config.proximl.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.proximl.run(found.remove())
|
proximl/cli/project.py
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
from proximl.cli import cli, pass_config, search_by_id_name
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@cli.group()
|
|
6
|
-
@pass_config
|
|
7
|
-
def project(config):
|
|
8
|
-
"""proxiML project commands."""
|
|
9
|
-
pass
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@project.command()
|
|
13
|
-
@pass_config
|
|
14
|
-
def list(config):
|
|
15
|
-
"""List projects."""
|
|
16
|
-
data = [
|
|
17
|
-
["ID", "NAME", "OWNER", "MINE"],
|
|
18
|
-
[
|
|
19
|
-
"-" * 80,
|
|
20
|
-
"-" * 80,
|
|
21
|
-
"-" * 80,
|
|
22
|
-
"-" * 80,
|
|
23
|
-
],
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
projects = config.proximl.run(config.proximl.client.projects.list())
|
|
27
|
-
|
|
28
|
-
for project in projects:
|
|
29
|
-
data.append(
|
|
30
|
-
[
|
|
31
|
-
project.id,
|
|
32
|
-
project.name,
|
|
33
|
-
project.owner_name,
|
|
34
|
-
"X" if project.is_owner else "",
|
|
35
|
-
]
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
for row in data:
|
|
39
|
-
click.echo(
|
|
40
|
-
"{: >38.36} {: >30.28} {: >15.13} {: >4.4}" "".format(*row),
|
|
41
|
-
file=config.stdout,
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@project.command()
|
|
46
|
-
@click.argument("name", type=click.STRING)
|
|
47
|
-
@pass_config
|
|
48
|
-
def create(config, name):
|
|
49
|
-
"""
|
|
50
|
-
Create a project.
|
|
51
|
-
|
|
52
|
-
Project is created with the specified NAME.
|
|
53
|
-
"""
|
|
54
|
-
|
|
55
|
-
return config.proximl.run(
|
|
56
|
-
config.proximl.client.projects.create(
|
|
57
|
-
name=name,
|
|
58
|
-
)
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@project.command()
|
|
63
|
-
@click.argument("project", type=click.STRING)
|
|
64
|
-
@pass_config
|
|
65
|
-
def remove(config, project):
|
|
66
|
-
"""
|
|
67
|
-
Remove a project.
|
|
68
|
-
|
|
69
|
-
PROJECT may be specified by name or ID, but ID is preferred.
|
|
70
|
-
"""
|
|
71
|
-
projects = config.proximl.run(config.proximl.client.projects.list())
|
|
72
|
-
|
|
73
|
-
found = search_by_id_name(project, projects)
|
|
74
|
-
if None is found:
|
|
75
|
-
raise click.UsageError("Cannot find specified project.")
|
|
76
|
-
|
|
77
|
-
return config.proximl.run(found.remove())
|
|
78
|
-
|
|
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_reservations(config):
|
|
119
|
-
"""List project reservations."""
|
|
120
|
-
data = [
|
|
121
|
-
["ID", "NAME", "TYPE", "RESOURCE", "HOSTNAME", "REGION_UUID"],
|
|
122
|
-
[
|
|
123
|
-
"-" * 80,
|
|
124
|
-
"-" * 80,
|
|
125
|
-
"-" * 80,
|
|
126
|
-
"-" * 80,
|
|
127
|
-
"-" * 80,
|
|
128
|
-
"-" * 80,
|
|
129
|
-
],
|
|
130
|
-
]
|
|
131
|
-
project = config.proximl.run(
|
|
132
|
-
config.proximl.client.projects.get(config.proximl.client.project)
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
reservations = config.proximl.run(project.list_reservations())
|
|
136
|
-
|
|
137
|
-
for reservation in reservations:
|
|
138
|
-
data.append(
|
|
139
|
-
[
|
|
140
|
-
reservation.id,
|
|
141
|
-
reservation.name,
|
|
142
|
-
reservation.type,
|
|
143
|
-
reservation.resource,
|
|
144
|
-
reservation.hostname,
|
|
145
|
-
reservation.region_uuid,
|
|
146
|
-
]
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
for row in data:
|
|
150
|
-
click.echo(
|
|
151
|
-
"{: >38.36} {: >30.28} {: >8.6} {: >15.13} {: >30.28} {: >38.36}"
|
|
152
|
-
"".format(*row),
|
|
153
|
-
file=config.stdout,
|
|
154
|
-
)
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import logging
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Reservations(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}/reservation/{id}",
|
|
12
|
-
"GET",
|
|
13
|
-
kwargs,
|
|
14
|
-
)
|
|
15
|
-
return Reservation(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}/reservation",
|
|
20
|
-
"GET",
|
|
21
|
-
kwargs,
|
|
22
|
-
)
|
|
23
|
-
reservations = [
|
|
24
|
-
Reservation(self.proximl, **reservation) for reservation in resp
|
|
25
|
-
]
|
|
26
|
-
return reservations
|
|
27
|
-
|
|
28
|
-
async def create(
|
|
29
|
-
self,
|
|
30
|
-
provider_uuid,
|
|
31
|
-
region_uuid,
|
|
32
|
-
name,
|
|
33
|
-
type,
|
|
34
|
-
resource,
|
|
35
|
-
hostname,
|
|
36
|
-
**kwargs,
|
|
37
|
-
):
|
|
38
|
-
logging.info(f"Creating Reservation {name}")
|
|
39
|
-
data = dict(
|
|
40
|
-
name=name,
|
|
41
|
-
type=type,
|
|
42
|
-
resource=resource,
|
|
43
|
-
hostname=hostname,
|
|
44
|
-
**kwargs,
|
|
45
|
-
)
|
|
46
|
-
payload = {k: v for k, v in data.items() if v is not None}
|
|
47
|
-
resp = await self.proximl._query(
|
|
48
|
-
f"/provider/{provider_uuid}/region/{region_uuid}/reservation",
|
|
49
|
-
"POST",
|
|
50
|
-
None,
|
|
51
|
-
payload,
|
|
52
|
-
)
|
|
53
|
-
reservation = Reservation(self.proximl, **resp)
|
|
54
|
-
logging.info(f"Created Reservation {name} with id {reservation.id}")
|
|
55
|
-
return reservation
|
|
56
|
-
|
|
57
|
-
async def remove(self, provider_uuid, region_uuid, id, **kwargs):
|
|
58
|
-
await self.proximl._query(
|
|
59
|
-
f"/provider/{provider_uuid}/region/{region_uuid}/reservation/{id}",
|
|
60
|
-
"DELETE",
|
|
61
|
-
kwargs,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class Reservation:
|
|
66
|
-
def __init__(self, proximl, **kwargs):
|
|
67
|
-
self.proximl = proximl
|
|
68
|
-
self._reservation = kwargs
|
|
69
|
-
self._id = self._reservation.get("reservation_id")
|
|
70
|
-
self._provider_uuid = self._reservation.get("provider_uuid")
|
|
71
|
-
self._region_uuid = self._reservation.get("region_uuid")
|
|
72
|
-
self._type = self._reservation.get("type")
|
|
73
|
-
self._name = self._reservation.get("name")
|
|
74
|
-
self._resource = self._reservation.get("resource")
|
|
75
|
-
self._hostname = self._reservation.get("hostname")
|
|
76
|
-
|
|
77
|
-
@property
|
|
78
|
-
def id(self) -> str:
|
|
79
|
-
return self._id
|
|
80
|
-
|
|
81
|
-
@property
|
|
82
|
-
def provider_uuid(self) -> str:
|
|
83
|
-
return self._provider_uuid
|
|
84
|
-
|
|
85
|
-
@property
|
|
86
|
-
def region_uuid(self) -> str:
|
|
87
|
-
return self._region_uuid
|
|
88
|
-
|
|
89
|
-
@property
|
|
90
|
-
def type(self) -> str:
|
|
91
|
-
return self._type
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def name(self) -> str:
|
|
95
|
-
return self._name
|
|
96
|
-
|
|
97
|
-
@property
|
|
98
|
-
def resource(self) -> str:
|
|
99
|
-
return self._resource
|
|
100
|
-
|
|
101
|
-
@property
|
|
102
|
-
def hostname(self) -> str:
|
|
103
|
-
return self._hostname
|
|
104
|
-
|
|
105
|
-
def __str__(self):
|
|
106
|
-
return json.dumps({k: v for k, v in self._reservation.items()})
|
|
107
|
-
|
|
108
|
-
def __repr__(self):
|
|
109
|
-
return f"Reservation( proximl , **{self._reservation.__repr__()})"
|
|
110
|
-
|
|
111
|
-
def __bool__(self):
|
|
112
|
-
return bool(self._id)
|
|
113
|
-
|
|
114
|
-
async def remove(self):
|
|
115
|
-
await self.proximl._query(
|
|
116
|
-
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/reservation/{self._id}",
|
|
117
|
-
"DELETE",
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
async def refresh(self):
|
|
121
|
-
resp = await self.proximl._query(
|
|
122
|
-
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/reservation/{self._id}",
|
|
123
|
-
"GET",
|
|
124
|
-
)
|
|
125
|
-
self.__init__(self.proximl, **resp)
|
|
126
|
-
return self
|
proximl/projects.py
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import logging
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Projects(object):
|
|
6
|
-
def __init__(self, proximl):
|
|
7
|
-
self.proximl = proximl
|
|
8
|
-
|
|
9
|
-
async def get(self, id, **kwargs):
|
|
10
|
-
resp = await self.proximl._query(f"/project/{id}", "GET", kwargs)
|
|
11
|
-
return Project(self.proximl, **resp)
|
|
12
|
-
|
|
13
|
-
async def list(self, **kwargs):
|
|
14
|
-
resp = await self.proximl._query(f"/project", "GET", kwargs)
|
|
15
|
-
projects = [Project(self.proximl, **project) for project in resp]
|
|
16
|
-
return projects
|
|
17
|
-
|
|
18
|
-
async def create(self, name, copy_keys=False, **kwargs):
|
|
19
|
-
data = dict(
|
|
20
|
-
name=name,
|
|
21
|
-
copy_keys=copy_keys,
|
|
22
|
-
)
|
|
23
|
-
payload = {k: v for k, v in data.items() if v is not None}
|
|
24
|
-
logging.info(f"Creating Project {name}")
|
|
25
|
-
resp = await self.proximl._query("/project", "POST", None, payload)
|
|
26
|
-
project = Project(self.proximl, **resp)
|
|
27
|
-
logging.info(f"Created Project {name} with id {project.id}")
|
|
28
|
-
|
|
29
|
-
return project
|
|
30
|
-
|
|
31
|
-
async def remove(self, id, **kwargs):
|
|
32
|
-
await self.proximl._query(f"/project/{id}", "DELETE", kwargs)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class ProjectDatastore:
|
|
36
|
-
def __init__(self, proximl, **kwargs):
|
|
37
|
-
self.proximl = proximl
|
|
38
|
-
self._datastore = kwargs
|
|
39
|
-
self._id = self._datastore.get("id")
|
|
40
|
-
self._project_uuid = self._datastore.get("project_uuid")
|
|
41
|
-
self._name = self._datastore.get("name")
|
|
42
|
-
self._type = self._datastore.get("type")
|
|
43
|
-
self._region_uuid = self._datastore.get("region_uuid")
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def id(self) -> str:
|
|
47
|
-
return self._id
|
|
48
|
-
|
|
49
|
-
@property
|
|
50
|
-
def project_uuid(self) -> str:
|
|
51
|
-
return self._project_uuid
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
def name(self) -> str:
|
|
55
|
-
return self._name
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def type(self) -> str:
|
|
59
|
-
return self._type
|
|
60
|
-
|
|
61
|
-
@property
|
|
62
|
-
def region_uuid(self) -> str:
|
|
63
|
-
return self._region_uuid
|
|
64
|
-
|
|
65
|
-
def __str__(self):
|
|
66
|
-
return json.dumps({k: v for k, v in self._datastore.items()})
|
|
67
|
-
|
|
68
|
-
def __repr__(self):
|
|
69
|
-
return f"ProjectDatastore( proximl , **{self._datastore.__repr__()})"
|
|
70
|
-
|
|
71
|
-
def __bool__(self):
|
|
72
|
-
return bool(self._id)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class ProjectReservation:
|
|
76
|
-
def __init__(self, proximl, **kwargs):
|
|
77
|
-
self.proximl = proximl
|
|
78
|
-
self._reservation = kwargs
|
|
79
|
-
self._id = self._reservation.get("id")
|
|
80
|
-
self._project_uuid = self._reservation.get("project_uuid")
|
|
81
|
-
self._name = self._reservation.get("name")
|
|
82
|
-
self._type = self._reservation.get("type")
|
|
83
|
-
self._hostname = self._reservation.get("hostname")
|
|
84
|
-
self._resource = self._reservation.get("resource")
|
|
85
|
-
self._region_uuid = self._reservation.get("region_uuid")
|
|
86
|
-
|
|
87
|
-
@property
|
|
88
|
-
def id(self) -> str:
|
|
89
|
-
return self._id
|
|
90
|
-
|
|
91
|
-
@property
|
|
92
|
-
def project_uuid(self) -> str:
|
|
93
|
-
return self._project_uuid
|
|
94
|
-
|
|
95
|
-
@property
|
|
96
|
-
def name(self) -> str:
|
|
97
|
-
return self._name
|
|
98
|
-
|
|
99
|
-
@property
|
|
100
|
-
def type(self) -> str:
|
|
101
|
-
return self._type
|
|
102
|
-
|
|
103
|
-
@property
|
|
104
|
-
def hostname(self) -> str:
|
|
105
|
-
return self._hostname
|
|
106
|
-
|
|
107
|
-
@property
|
|
108
|
-
def resource(self) -> str:
|
|
109
|
-
return self._resource
|
|
110
|
-
|
|
111
|
-
@property
|
|
112
|
-
def region_uuid(self) -> str:
|
|
113
|
-
return self._region_uuid
|
|
114
|
-
|
|
115
|
-
def __str__(self):
|
|
116
|
-
return json.dumps({k: v for k, v in self._reservation.items()})
|
|
117
|
-
|
|
118
|
-
def __repr__(self):
|
|
119
|
-
return (
|
|
120
|
-
f"ProjectReservation( proximl , **{self._reservation.__repr__()})"
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
def __bool__(self):
|
|
124
|
-
return bool(self._id)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class Project:
|
|
128
|
-
def __init__(self, proximl, **kwargs):
|
|
129
|
-
self.proximl = proximl
|
|
130
|
-
self._project = kwargs
|
|
131
|
-
self._id = self._project.get("id")
|
|
132
|
-
self._name = self._project.get("name")
|
|
133
|
-
self._is_owner = self._project.get("owner")
|
|
134
|
-
self._owner_name = self._project.get("owner_name")
|
|
135
|
-
|
|
136
|
-
@property
|
|
137
|
-
def id(self) -> str:
|
|
138
|
-
return self._id
|
|
139
|
-
|
|
140
|
-
@property
|
|
141
|
-
def name(self) -> str:
|
|
142
|
-
return self._name
|
|
143
|
-
|
|
144
|
-
@property
|
|
145
|
-
def is_owner(self) -> bool:
|
|
146
|
-
return self._is_owner
|
|
147
|
-
|
|
148
|
-
@property
|
|
149
|
-
def owner_name(self) -> str:
|
|
150
|
-
return self._owner_name
|
|
151
|
-
|
|
152
|
-
def __str__(self):
|
|
153
|
-
return json.dumps({k: v for k, v in self._project.items()})
|
|
154
|
-
|
|
155
|
-
def __repr__(self):
|
|
156
|
-
return f"Project( proximl , **{self._project.__repr__()})"
|
|
157
|
-
|
|
158
|
-
def __bool__(self):
|
|
159
|
-
return bool(self._id)
|
|
160
|
-
|
|
161
|
-
async def remove(self):
|
|
162
|
-
await self.proximl._query(f"/project/{self._id}", "DELETE")
|
|
163
|
-
|
|
164
|
-
async def list_datastores(self):
|
|
165
|
-
resp = await self.proximl._query(
|
|
166
|
-
f"/project/{self._id}/datastores", "GET"
|
|
167
|
-
)
|
|
168
|
-
datastores = [
|
|
169
|
-
ProjectDatastore(self.proximl, **datastore) for datastore in resp
|
|
170
|
-
]
|
|
171
|
-
return datastores
|
|
172
|
-
|
|
173
|
-
async def list_reservations(self):
|
|
174
|
-
resp = await self.proximl._query(
|
|
175
|
-
f"/project/{self._id}/reservations", "GET"
|
|
176
|
-
)
|
|
177
|
-
reservations = [
|
|
178
|
-
ProjectReservation(self.proximl, **reservation)
|
|
179
|
-
for reservation in resp
|
|
180
|
-
]
|
|
181
|
-
return reservations
|
|
182
|
-
|
|
183
|
-
async def refresh_datastores(self):
|
|
184
|
-
await self.proximl._query(f"/project/{self._id}/datastores", "PATCH")
|
|
185
|
-
|
|
186
|
-
async def refresh_reservations(self):
|
|
187
|
-
await self.proximl._query(f"/project/{self._id}/reservations", "PATCH")
|
|
@@ -1,44 +0,0 @@
|
|
|
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 GetProjectsTests:
|
|
12
|
-
@fixture(scope="class")
|
|
13
|
-
async def project(self, proximl):
|
|
14
|
-
project = await proximl.projects.create(name="New Project", copy_keys=False)
|
|
15
|
-
yield project
|
|
16
|
-
await project.remove()
|
|
17
|
-
|
|
18
|
-
async def test_get_projects(self, proximl):
|
|
19
|
-
projects = await proximl.projects.list()
|
|
20
|
-
assert len(projects) > 0
|
|
21
|
-
|
|
22
|
-
async def test_get_project(self, proximl, project):
|
|
23
|
-
response = await proximl.projects.get(project.id)
|
|
24
|
-
assert response.id == project.id
|
|
25
|
-
|
|
26
|
-
async def test_project_properties(self, project):
|
|
27
|
-
assert isinstance(project.id, str)
|
|
28
|
-
assert isinstance(project.name, str)
|
|
29
|
-
assert isinstance(project.owner_name, str)
|
|
30
|
-
assert isinstance(project.is_owner, bool)
|
|
31
|
-
assert project.name == "New Project"
|
|
32
|
-
assert project.is_owner
|
|
33
|
-
|
|
34
|
-
async def test_project_str(self, project):
|
|
35
|
-
string = str(project)
|
|
36
|
-
regex = r"^{.*\"id\": \"" + project.id + r"\".*}$"
|
|
37
|
-
assert isinstance(string, str)
|
|
38
|
-
assert re.match(regex, string)
|
|
39
|
-
|
|
40
|
-
async def test_project_repr(self, project):
|
|
41
|
-
string = repr(project)
|
|
42
|
-
regex = r"^Project\( proximl , \*\*{.*'id': '" + project.id + r"'.*}\)$"
|
|
43
|
-
assert isinstance(string, str)
|
|
44
|
-
assert re.match(regex, string)
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import json
|
|
3
|
-
import click
|
|
4
|
-
from unittest.mock import AsyncMock, patch
|
|
5
|
-
from pytest import mark, fixture, raises
|
|
6
|
-
|
|
7
|
-
pytestmark = [mark.cli, mark.unit, mark.cloudbender, mark.reservations]
|
|
8
|
-
|
|
9
|
-
from proximl.cli.cloudbender import reservation as specimen
|
|
10
|
-
from proximl.cloudbender.reservations import Reservation
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def test_list(runner, mock_reservations):
|
|
14
|
-
with patch("proximl.cli.ProxiML", new=AsyncMock) as mock_proximl:
|
|
15
|
-
mock_proximl.cloudbender = AsyncMock()
|
|
16
|
-
mock_proximl.cloudbender.reservations = AsyncMock()
|
|
17
|
-
mock_proximl.cloudbender.reservations.list = AsyncMock(
|
|
18
|
-
return_value=mock_reservations
|
|
19
|
-
)
|
|
20
|
-
result = runner.invoke(
|
|
21
|
-
specimen,
|
|
22
|
-
args=["list", "--provider=prov-id-1", "--region=reg-id-1"],
|
|
23
|
-
)
|
|
24
|
-
assert result.exit_code == 0
|
|
25
|
-
mock_proximl.cloudbender.reservations.list.assert_called_once_with(
|
|
26
|
-
provider_uuid="prov-id-1", region_uuid="reg-id-1"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def test_list_no_provider(runner, mock_reservations):
|
|
31
|
-
with patch("proximl.cli.ProxiML", new=AsyncMock) as mock_proximl:
|
|
32
|
-
mock_proximl.cloudbender = AsyncMock()
|
|
33
|
-
mock_proximl.cloudbender.reservations = AsyncMock()
|
|
34
|
-
mock_proximl.cloudbender.reservations.list = AsyncMock(
|
|
35
|
-
return_value=mock_reservations
|
|
36
|
-
)
|
|
37
|
-
result = runner.invoke(specimen, ["list"])
|
|
38
|
-
assert result.exit_code != 0
|