trainml 0.5.14__py3-none-any.whl → 0.5.16__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/cloudbender/conftest.py +28 -0
- tests/integration/cloudbender/test_providers_integration.py +3 -8
- tests/integration/cloudbender/test_regions_integration.py +42 -0
- tests/integration/cloudbender/test_services_integration.py +87 -0
- tests/integration/conftest.py +1 -1
- tests/integration/projects/conftest.py +2 -1
- tests/integration/projects/test_projects_credentials_integration.py +1 -0
- tests/integration/projects/test_projects_data_connectors_integration.py +1 -0
- tests/integration/projects/test_projects_datastores_integration.py +1 -0
- tests/integration/projects/test_projects_integration.py +1 -0
- tests/integration/projects/test_projects_members_integration.py +1 -0
- tests/integration/projects/test_projects_secrets_integration.py +1 -0
- tests/integration/projects/test_projects_services_integration.py +1 -0
- tests/integration/test_checkpoints_integration.py +1 -0
- tests/integration/test_datasets_integration.py +1 -0
- tests/integration/test_jobs_integration.py +5 -0
- tests/integration/test_models_integration.py +1 -0
- tests/integration/test_volumes_integration.py +1 -0
- trainml/__init__.py +1 -1
- trainml/cloudbender/services.py +29 -1
- trainml/projects/services.py +17 -0
- {trainml-0.5.14.dist-info → trainml-0.5.16.dist-info}/METADATA +1 -1
- {trainml-0.5.14.dist-info → trainml-0.5.16.dist-info}/RECORD +27 -29
- tests/integration/projects/test_projects_keys_integration.py +0 -43
- tests/unit/cli/projects/test_cli_project_key_unit.py +0 -26
- tests/unit/projects/test_project_keys_unit.py +0 -96
- trainml/cli/project/key.py +0 -124
- trainml/projects/keys.py +0 -71
- {trainml-0.5.14.dist-info → trainml-0.5.16.dist-info}/LICENSE +0 -0
- {trainml-0.5.14.dist-info → trainml-0.5.16.dist-info}/WHEEL +0 -0
- {trainml-0.5.14.dist-info → trainml-0.5.16.dist-info}/entry_points.txt +0 -0
- {trainml-0.5.14.dist-info → trainml-0.5.16.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
from pytest import fixture, mark
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
pytestmark = [mark.integration,mark.cloudbender]
|
|
6
|
+
|
|
7
|
+
@fixture(scope="session")
|
|
8
|
+
@mark.create
|
|
9
|
+
@mark.asyncio
|
|
10
|
+
@mark.xdist_group("cloudbender_resources")
|
|
11
|
+
async def provider( trainml):
|
|
12
|
+
provider = await trainml.cloudbender.providers.enable(type="test")
|
|
13
|
+
await provider.wait_for("ready")
|
|
14
|
+
yield provider
|
|
15
|
+
await provider.remove()
|
|
16
|
+
|
|
17
|
+
@fixture(scope="session")
|
|
18
|
+
@mark.create
|
|
19
|
+
@mark.asyncio
|
|
20
|
+
@mark.xdist_group("cloudbender_resources")
|
|
21
|
+
async def region(trainml, provider):
|
|
22
|
+
region = await trainml.cloudbender.regions.create(provider_uuid=provider.id,name="test-region",
|
|
23
|
+
public=False,
|
|
24
|
+
storage=dict(mode="local"),)
|
|
25
|
+
await region.wait_for("healthy")
|
|
26
|
+
yield region
|
|
27
|
+
await region.remove()
|
|
28
|
+
await region.wait_for("archived")
|
|
@@ -8,14 +8,9 @@ pytestmark = [mark.sdk, mark.integration, mark.cloudbender, mark.providers]
|
|
|
8
8
|
|
|
9
9
|
@mark.create
|
|
10
10
|
@mark.asyncio
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async def
|
|
14
|
-
provider = await trainml.cloudbender.providers.enable(type="test")
|
|
15
|
-
yield provider
|
|
16
|
-
await provider.remove()
|
|
17
|
-
|
|
18
|
-
async def test_get_providers(self, trainml):
|
|
11
|
+
@mark.xdist_group("cloudbender_resources")
|
|
12
|
+
class GetProviderTests:
|
|
13
|
+
async def test_get_providers(self, trainml, provider):
|
|
19
14
|
providers = await trainml.cloudbender.providers.list()
|
|
20
15
|
assert len(providers) > 0
|
|
21
16
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
import asyncio
|
|
4
|
+
from pytest import mark, fixture
|
|
5
|
+
|
|
6
|
+
pytestmark = [mark.sdk, mark.integration, mark.cloudbender, mark.regions]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@mark.create
|
|
10
|
+
@mark.asyncio
|
|
11
|
+
@mark.xdist_group("cloudbender_resources")
|
|
12
|
+
class GetRegionTests:
|
|
13
|
+
async def test_get_regions(self, trainml, provider, region):
|
|
14
|
+
regions = await trainml.cloudbender.regions.list(provider_uuid=provider.id)
|
|
15
|
+
assert len(regions) > 0
|
|
16
|
+
|
|
17
|
+
async def test_get_region(self, trainml, provider, region):
|
|
18
|
+
response = await trainml.cloudbender.regions.get(provider.id, region.id)
|
|
19
|
+
assert response.id == region.id
|
|
20
|
+
|
|
21
|
+
async def test_region_properties(self, provider, region):
|
|
22
|
+
assert isinstance(region.id, str)
|
|
23
|
+
assert isinstance(region.provider_uuid, str)
|
|
24
|
+
assert isinstance(region.type, str)
|
|
25
|
+
assert region.type == "test"
|
|
26
|
+
assert region.provider_uuid == provider.id
|
|
27
|
+
|
|
28
|
+
async def test_region_str(self, region):
|
|
29
|
+
string = str(region)
|
|
30
|
+
regex = r"^{.*\"region_uuid\": \"" + region.id + r"\".*}$"
|
|
31
|
+
assert isinstance(string, str)
|
|
32
|
+
assert re.match(regex, string)
|
|
33
|
+
|
|
34
|
+
async def test_region_repr(self, region):
|
|
35
|
+
string = repr(region)
|
|
36
|
+
regex = (
|
|
37
|
+
r"^Region\( trainml , \*\*{.*'region_uuid': '"
|
|
38
|
+
+ region.id
|
|
39
|
+
+ r"'.*}\)$"
|
|
40
|
+
)
|
|
41
|
+
assert isinstance(string, str)
|
|
42
|
+
assert re.match(regex, string)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
import asyncio
|
|
4
|
+
from pytest import mark, fixture
|
|
5
|
+
from cryptography import x509
|
|
6
|
+
from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID
|
|
7
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
8
|
+
from cryptography.hazmat.primitives import serialization, hashes
|
|
9
|
+
|
|
10
|
+
pytestmark = [mark.sdk, mark.integration, mark.cloudbender, mark.regions]
|
|
11
|
+
|
|
12
|
+
def get_csr(service_id):
|
|
13
|
+
private_key = rsa.generate_private_key(
|
|
14
|
+
public_exponent=65537,
|
|
15
|
+
key_size=4096
|
|
16
|
+
)
|
|
17
|
+
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
|
|
18
|
+
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
|
|
19
|
+
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "proxiML"),
|
|
20
|
+
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, service_id),
|
|
21
|
+
x509.NameAttribute(NameOID.COMMON_NAME, "test-client"), # Client identity
|
|
22
|
+
])).add_extension(
|
|
23
|
+
x509.ExtendedKeyUsage([
|
|
24
|
+
ExtendedKeyUsageOID.CLIENT_AUTH # Client authentication usage
|
|
25
|
+
]),
|
|
26
|
+
critical=True
|
|
27
|
+
).sign(private_key, hashes.SHA256())
|
|
28
|
+
return csr.public_bytes(serialization.Encoding.PEM).decode("utf-8")
|
|
29
|
+
|
|
30
|
+
@mark.create
|
|
31
|
+
@mark.asyncio
|
|
32
|
+
@mark.xdist_group("cloudbender_resources")
|
|
33
|
+
class GetServiceTests:
|
|
34
|
+
@fixture(scope="class")
|
|
35
|
+
async def service(self, trainml, region):
|
|
36
|
+
service = await trainml.cloudbender.services.create(
|
|
37
|
+
provider_uuid=region.provider_uuid,
|
|
38
|
+
region_uuid=region.id,
|
|
39
|
+
name="CLI Automated Service",
|
|
40
|
+
type="tcp",
|
|
41
|
+
port="8989",
|
|
42
|
+
public=False,
|
|
43
|
+
)
|
|
44
|
+
await service.wait_for("active")
|
|
45
|
+
yield service
|
|
46
|
+
await service.remove()
|
|
47
|
+
await service.wait_for("archived")
|
|
48
|
+
|
|
49
|
+
async def test_get_services(self, trainml, region,service):
|
|
50
|
+
services = await trainml.cloudbender.services.list(provider_uuid=region.provider_uuid, region_uuid=region.id)
|
|
51
|
+
assert len(services) > 0
|
|
52
|
+
|
|
53
|
+
async def test_get_service(self, trainml, provider, region, service):
|
|
54
|
+
response = await trainml.cloudbender.services.get(provider.id, region.id, service.id)
|
|
55
|
+
assert response.id == service.id
|
|
56
|
+
|
|
57
|
+
async def test_service_properties(self, region, service):
|
|
58
|
+
assert isinstance(service.id, str)
|
|
59
|
+
assert isinstance(service.provider_uuid, str)
|
|
60
|
+
assert isinstance(service.region_uuid, str)
|
|
61
|
+
assert isinstance(service.public, bool)
|
|
62
|
+
assert service.port == "8989"
|
|
63
|
+
assert service.provider_uuid == region.provider_uuid
|
|
64
|
+
assert service.region_uuid == region.id
|
|
65
|
+
|
|
66
|
+
async def test_service_str(self, service):
|
|
67
|
+
string = str(service)
|
|
68
|
+
regex = r"^{.*\"service_id\": \"" + service.id + r"\".*}$"
|
|
69
|
+
assert isinstance(string, str)
|
|
70
|
+
assert re.match(regex, string)
|
|
71
|
+
|
|
72
|
+
async def test_service_repr(self, service):
|
|
73
|
+
string = repr(service)
|
|
74
|
+
regex = (
|
|
75
|
+
r"^Service\( trainml , \*\*{.*'service_id': '"
|
|
76
|
+
+ service.id
|
|
77
|
+
+ r"'.*}\)$"
|
|
78
|
+
)
|
|
79
|
+
assert isinstance(string, str)
|
|
80
|
+
assert re.match(regex, string)
|
|
81
|
+
|
|
82
|
+
async def test_service_certificate(self, service):
|
|
83
|
+
service = await service.generate_certificate()
|
|
84
|
+
assert isinstance(service._service.get("auth_cert"), str)
|
|
85
|
+
csr = get_csr(service.id)
|
|
86
|
+
certificate = await service.sign_client_certificate(csr)
|
|
87
|
+
assert isinstance(certificate, str)
|
tests/integration/conftest.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from pytest import fixture
|
|
1
|
+
from pytest import fixture, mark
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
@fixture(scope="module")
|
|
5
|
+
@mark.xdist_group("project_resources")
|
|
5
6
|
async def project(trainml):
|
|
6
7
|
project = await trainml.projects.create(
|
|
7
8
|
name="New Project", copy_credentials=False, copy_secrets=False
|
|
@@ -20,6 +20,7 @@ def extract_domain_suffix(hostname):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
@fixture(scope="class")
|
|
23
|
+
@mark.xdist_group("job_lifecycle")
|
|
23
24
|
async def job(trainml):
|
|
24
25
|
job = await trainml.jobs.create(
|
|
25
26
|
name="CLI Automated Tests - Job Lifecycle",
|
|
@@ -38,6 +39,7 @@ async def job(trainml):
|
|
|
38
39
|
|
|
39
40
|
@mark.create
|
|
40
41
|
@mark.asyncio
|
|
42
|
+
@mark.xdist_group("job_lifecycle")
|
|
41
43
|
class JobLifeCycleTests:
|
|
42
44
|
async def test_wait_for_running(self, job):
|
|
43
45
|
assert job.status != "running"
|
|
@@ -413,6 +415,7 @@ class JobAPIWorkerValidationTests:
|
|
|
413
415
|
|
|
414
416
|
@mark.create
|
|
415
417
|
@mark.asyncio
|
|
418
|
+
@mark.xdist_group("job_io")
|
|
416
419
|
class JobIOTests:
|
|
417
420
|
async def test_job_local_output(self, trainml, capsys):
|
|
418
421
|
temp_dir = tempfile.TemporaryDirectory()
|
|
@@ -527,6 +530,7 @@ class JobIOTests:
|
|
|
527
530
|
|
|
528
531
|
@mark.create
|
|
529
532
|
@mark.asyncio
|
|
533
|
+
@mark.xdist_group("job_types")
|
|
530
534
|
class JobTypeTests:
|
|
531
535
|
async def test_endpoint(self, trainml):
|
|
532
536
|
|
|
@@ -648,6 +652,7 @@ class JobTypeTests:
|
|
|
648
652
|
|
|
649
653
|
@mark.create
|
|
650
654
|
@mark.asyncio
|
|
655
|
+
@mark.xdist_group("job_features")
|
|
651
656
|
class JobFeatureTests:
|
|
652
657
|
async def test_cpu_instance(self, trainml, capsys):
|
|
653
658
|
job = await trainml.jobs.create(
|
trainml/__init__.py
CHANGED
trainml/cloudbender/services.py
CHANGED
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
import asyncio
|
|
4
4
|
import math
|
|
5
|
+
from enum import Enum
|
|
5
6
|
|
|
6
7
|
from trainml.exceptions import (
|
|
7
8
|
ApiError,
|
|
@@ -9,6 +10,14 @@ from trainml.exceptions import (
|
|
|
9
10
|
TrainMLException,
|
|
10
11
|
)
|
|
11
12
|
|
|
13
|
+
class SERVICE_CERT_ALGORITHMS(str, Enum):
|
|
14
|
+
RSA_2048 = 'rsa2048'
|
|
15
|
+
RSA_4096 = 'rsa4096'
|
|
16
|
+
ED25519 = 'ed25519'
|
|
17
|
+
P256 = 'p256'
|
|
18
|
+
P384 ='p384'
|
|
19
|
+
P521='p521'
|
|
20
|
+
|
|
12
21
|
|
|
13
22
|
class Services(object):
|
|
14
23
|
def __init__(self, trainml):
|
|
@@ -67,7 +76,7 @@ class Services(object):
|
|
|
67
76
|
|
|
68
77
|
|
|
69
78
|
class Service:
|
|
70
|
-
def __init__(self, trainml,
|
|
79
|
+
def __init__(self, trainml, **kwargs):
|
|
71
80
|
self.trainml = trainml
|
|
72
81
|
self._service = kwargs
|
|
73
82
|
self._id = self._service.get("service_id")
|
|
@@ -177,3 +186,22 @@ class Service:
|
|
|
177
186
|
logging.debug(f"self: {self}, retry count {count}")
|
|
178
187
|
|
|
179
188
|
raise TrainMLException(f"Timeout waiting for {status}")
|
|
189
|
+
|
|
190
|
+
async def generate_certificate(self, algorithm=SERVICE_CERT_ALGORITHMS.ED25519.value, **kwargs):
|
|
191
|
+
resp = await self.trainml._query(
|
|
192
|
+
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}/certificate",
|
|
193
|
+
"POST",
|
|
194
|
+
kwargs,
|
|
195
|
+
dict(algorithm=algorithm)
|
|
196
|
+
)
|
|
197
|
+
self.__init__(self.trainml, **resp)
|
|
198
|
+
return self
|
|
199
|
+
|
|
200
|
+
async def sign_client_certificate(self, csr, **kwargs):
|
|
201
|
+
certificate = await self.trainml._query(
|
|
202
|
+
f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}/certificate/sign",
|
|
203
|
+
"POST",
|
|
204
|
+
kwargs,
|
|
205
|
+
dict(csr=csr)
|
|
206
|
+
)
|
|
207
|
+
return certificate
|
trainml/projects/services.py
CHANGED
|
@@ -77,3 +77,20 @@ class ProjectService:
|
|
|
77
77
|
await self.trainml._query(
|
|
78
78
|
f"/project/{self._project_uuid}/services/{self._id}/disable", "PATCH"
|
|
79
79
|
)
|
|
80
|
+
|
|
81
|
+
async def get_service_ca_certificate(self, **kwargs):
|
|
82
|
+
certificate = await self.trainml._query(
|
|
83
|
+
f"/project/{self._project_uuid}/services/{self._id}/certificate/ca",
|
|
84
|
+
"GET",
|
|
85
|
+
kwargs,
|
|
86
|
+
)
|
|
87
|
+
return certificate
|
|
88
|
+
|
|
89
|
+
async def sign_client_certificate(self, csr, **kwargs):
|
|
90
|
+
certificate = await self.trainml._query(
|
|
91
|
+
f"/project/{self._project_uuid}/services/{self._id}/certificate/sign",
|
|
92
|
+
"POST",
|
|
93
|
+
kwargs,
|
|
94
|
+
dict(csr=csr)
|
|
95
|
+
)
|
|
96
|
+
return certificate
|
|
@@ -3,26 +3,28 @@ examples/create_dataset_and_training_job.py,sha256=Ht6soyBZxt8qA9Fp6zAW2syGEdasv
|
|
|
3
3
|
examples/local_storage.py,sha256=w8iAeqr5CLOCOkNrqGzEDtybjDGGY7SQUqeE0ibMUrM,1745
|
|
4
4
|
examples/training_inference_pipeline.py,sha256=SNr4RFT9y69F9G9tMD8ONUbJmXRFrq1yxynq-FbfEf8,2334
|
|
5
5
|
tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
tests/integration/conftest.py,sha256=
|
|
7
|
-
tests/integration/test_checkpoints_integration.py,sha256=
|
|
8
|
-
tests/integration/test_datasets_integration.py,sha256=
|
|
6
|
+
tests/integration/conftest.py,sha256=otgb7lZu62_5zAMAsPpr0U2j0h5lApPlDRCiu7ZfDr8,1135
|
|
7
|
+
tests/integration/test_checkpoints_integration.py,sha256=RbOHZK-fjj2xvYo1XDa6H0war43Qe_1PbiNFndVY87o,3239
|
|
8
|
+
tests/integration/test_datasets_integration.py,sha256=sV88UAMM0IyVVum3zvxfYFbqmR8W4skNWE7jQxbc9ms,3529
|
|
9
9
|
tests/integration/test_environments_integration.py,sha256=0IckhJvQhd8j4Ouiu0hMq2b7iA1dbZpZYmknyfWjsFM,1403
|
|
10
10
|
tests/integration/test_gpu_types_integration.py,sha256=V2OncokZWWVq_l5FSmKEDM4EsWrmpB-zKiVPt-we0aY,1256
|
|
11
|
-
tests/integration/test_jobs_integration.py,sha256=
|
|
12
|
-
tests/integration/test_models_integration.py,sha256=
|
|
13
|
-
tests/integration/test_volumes_integration.py,sha256=
|
|
11
|
+
tests/integration/test_jobs_integration.py,sha256=_c33hYpub3VoWiFY-dAzTVyB66U3n5yvMxoRR-pskHg,25263
|
|
12
|
+
tests/integration/test_models_integration.py,sha256=Kwh8MQ0hOaecclAPq07LBEtAxoZB3rx-yamq0WGtWEA,2906
|
|
13
|
+
tests/integration/test_volumes_integration.py,sha256=W5DeuuKCBx3C89LRWc0jhAZjJEREuPiawTLUnqpPrjg,3299
|
|
14
14
|
tests/integration/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
tests/integration/cloudbender/
|
|
15
|
+
tests/integration/cloudbender/conftest.py,sha256=jBYUHKJioI-WHM-d0Y4lq5pD4LiOPINj6K9kQkgaGWY,777
|
|
16
|
+
tests/integration/cloudbender/test_providers_integration.py,sha256=mQn2dr4oMpctCVCVs53G5P0Raa0U2uBxEYjZtFFSvTg,1327
|
|
17
|
+
tests/integration/cloudbender/test_regions_integration.py,sha256=Ex1SB8xrl3KQ48n-Cka_1Whj8_uFsmhvJuOSdfK3kPk,1406
|
|
18
|
+
tests/integration/cloudbender/test_services_integration.py,sha256=_cGxEtjTDwz4pne6s1gVyEwoRcYYKcJClNUP5Yalrz0,3367
|
|
16
19
|
tests/integration/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
tests/integration/projects/conftest.py,sha256=
|
|
18
|
-
tests/integration/projects/test_projects_credentials_integration.py,sha256=
|
|
19
|
-
tests/integration/projects/test_projects_data_connectors_integration.py,sha256=
|
|
20
|
-
tests/integration/projects/test_projects_datastores_integration.py,sha256=
|
|
21
|
-
tests/integration/projects/test_projects_integration.py,sha256=
|
|
22
|
-
tests/integration/projects/
|
|
23
|
-
tests/integration/projects/
|
|
24
|
-
tests/integration/projects/
|
|
25
|
-
tests/integration/projects/test_projects_services_integration.py,sha256=lBnrqFpjsL3zfaJJmFh2rCWfNmmX-TjyOPCR3KobDAc,1530
|
|
20
|
+
tests/integration/projects/conftest.py,sha256=v4XqQEmNSmV_hNEjLEIOeGJxFoAl-km8UXO_5jO--6E,294
|
|
21
|
+
tests/integration/projects/test_projects_credentials_integration.py,sha256=DYkd57hxu6wGFAyfgQGQbIR6Ja0501UCsSnjWzxBEkk,1675
|
|
22
|
+
tests/integration/projects/test_projects_data_connectors_integration.py,sha256=0giPCNeMx-Mj6--i0LTEt3m_ZwElSQzhrbxmcpNOthc,1669
|
|
23
|
+
tests/integration/projects/test_projects_datastores_integration.py,sha256=Eln5xPy6qp2JWai97U61fAQa4lGpmYlSTjbuzJl2jYc,1508
|
|
24
|
+
tests/integration/projects/test_projects_integration.py,sha256=1tHXGeF05Bsr5osyMyf4VY8qf1a4xYLUaF7yRaoDoLE,1280
|
|
25
|
+
tests/integration/projects/test_projects_members_integration.py,sha256=bEc9AqC-YZ0hifvVaDmcVGbK3aYuTBNGBj0g4rjBEiQ,1882
|
|
26
|
+
tests/integration/projects/test_projects_secrets_integration.py,sha256=dnIT0KiHnXBVP-azfw8MCspTjX7q1ic03rz8XZNijvU,1520
|
|
27
|
+
tests/integration/projects/test_projects_services_integration.py,sha256=3DpOtVMIdG_Icp4s7JxMT70ZDKC1wMD8imkKjlQChb0,1569
|
|
26
28
|
tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
29
|
tests/unit/conftest.py,sha256=hLfECgT0w4pVZABrpK4UUUeaX1aDzQvj8-erWTGBjHA,35588
|
|
28
30
|
tests/unit/test_auth_unit.py,sha256=nfhlOCR7rUsn_MaD8QQtBc2v0k8pIxqbzGgRAZK1WGc,858
|
|
@@ -56,7 +58,6 @@ tests/unit/cli/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
|
56
58
|
tests/unit/cli/projects/test_cli_project_credential_unit.py,sha256=gnmEpNbpEG5S9cYQUjSGty2e8mqeC_cCKmIUAJCgRXg,943
|
|
57
59
|
tests/unit/cli/projects/test_cli_project_data_connector_unit.py,sha256=_NgnxV8zTIycpHKe7dyL6EXq774puFHQjvgCKsiEMO0,993
|
|
58
60
|
tests/unit/cli/projects/test_cli_project_datastore_unit.py,sha256=E_kLoIZ5U92LQaPcYAKDyUqpjM1Xe6PVPvofU1Yn6Yk,936
|
|
59
|
-
tests/unit/cli/projects/test_cli_project_key_unit.py,sha256=Ma5HjsZt2RaHKgmMdGY59EIc2WdAgbWKWn2LvlYeDqQ,894
|
|
60
61
|
tests/unit/cli/projects/test_cli_project_secret_unit.py,sha256=QBkq1gVqkjGUni2xCihL994bvseNcA-dyUWaJVU9GjI,915
|
|
61
62
|
tests/unit/cli/projects/test_cli_project_service_unit.py,sha256=TRNOwK3RUCtktYdCGzfhQE3fE_mn8LweCN5E4gRn1h4,922
|
|
62
63
|
tests/unit/cli/projects/test_cli_project_unit.py,sha256=0IynsMwFsXBZn-u0gX2iir7AjPsNraHe68PuAe-Lkaw,627
|
|
@@ -73,12 +74,11 @@ tests/unit/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
73
74
|
tests/unit/projects/test_project_credentials_unit.py,sha256=ObTaJ7_g0MP5N-0qHWdeYips0in1j_4UkOhXXI2FFwo,3480
|
|
74
75
|
tests/unit/projects/test_project_data_connectors_unit.py,sha256=uQPFx6rwYMWZz1IJkns_LdM5gccyHSIaKb3k8zmfSkY,3385
|
|
75
76
|
tests/unit/projects/test_project_datastores_unit.py,sha256=kcoaSs54gGqJ9gwPMpP6KHAPRvDJtdJpm49s4aYYt3E,3129
|
|
76
|
-
tests/unit/projects/test_project_keys_unit.py,sha256=2-w_VwmWxWHoLWBCoBAfg5WozyeYJHV361ZndlA0xk4,3161
|
|
77
77
|
tests/unit/projects/test_project_members_unit.py,sha256=C5N6jzT7zM3eL3_bXEddddBHPFJ3617T0lYluBjMy78,3466
|
|
78
78
|
tests/unit/projects/test_project_secrets_unit.py,sha256=StVlY-ZR3CKxXAt9NL8hTkXUEdgGESH0m6foEPXKE-4,3276
|
|
79
79
|
tests/unit/projects/test_project_services_unit.py,sha256=ZK5nz78RAmmaCrAwYBd34t87dh6etU-7snLB_xukZHM,3331
|
|
80
80
|
tests/unit/projects/test_projects_unit.py,sha256=8rJ40bJ7YszEsoL6D02Muey-sgRjqFmMoR-R3IiP_Ig,3810
|
|
81
|
-
trainml/__init__.py,sha256=
|
|
81
|
+
trainml/__init__.py,sha256=5RqjjlFqQb0tJN9ZO6I5XfCCpFj5SC32ic8y55SYHOM,433
|
|
82
82
|
trainml/__main__.py,sha256=JgErYkiskih8Y6oRwowALtR-rwQhAAdqOYWjQraRIPI,59
|
|
83
83
|
trainml/auth.py,sha256=clbx5S5prJ3u62aEESdBXIHF_HmreQ-L1ShxcyWQNDs,26565
|
|
84
84
|
trainml/checkpoints.py,sha256=Hg3_Si7ohzsv4_8JIjoj9pMRpHNZRWKC5R2gtgmp01s,8790
|
|
@@ -113,7 +113,6 @@ trainml/cli/project/__init__.py,sha256=HDcJUbKMHhz4Thrvpst5hnywFqzsv0XWmvfKNRi8z
|
|
|
113
113
|
trainml/cli/project/credential.py,sha256=gByXKiYf5sJeNRtuXWcercWv8P2IzO5TjT8Ypp4mCR8,3443
|
|
114
114
|
trainml/cli/project/data_connector.py,sha256=KLDhpNJfwcJkcmyuJRgcVH70Jf73619O9ddYP8vhMvk,1411
|
|
115
115
|
trainml/cli/project/datastore.py,sha256=IwF0LqsSFn7DrKPRdxQs6kturk9MCI52A1aoWeb7ClA,1336
|
|
116
|
-
trainml/cli/project/key.py,sha256=kQlCs_N-5c27hOyGkmT22_J47x8U6CZaSardsaPYGbw,3203
|
|
117
116
|
trainml/cli/project/secret.py,sha256=tHt7bYDt0MNkLTTePTIJFUh9Mn9ogebPcaSCiNRJFNQ,1927
|
|
118
117
|
trainml/cli/project/service.py,sha256=FzcyGI9MN-UvnjdKW7GmXLTXLUIXtuTFAISR_FmCmJo,1310
|
|
119
118
|
trainml/cloudbender/__init__.py,sha256=iE29obtC0_9f0IhRvHQcG5aY58fVhVYipTakpjAhdss,64
|
|
@@ -125,19 +124,18 @@ trainml/cloudbender/devices.py,sha256=QORNmKdLJoqGZmeWXRnivC1JmNBIw-ebvf4bsoem3r
|
|
|
125
124
|
trainml/cloudbender/nodes.py,sha256=U2sTIL2fuBVsNFPsJrvB2JbBcuLULF1-AwJ4dp5ChmM,5924
|
|
126
125
|
trainml/cloudbender/providers.py,sha256=22ymUl1KLC8UlyoWMsIrOKhUDOwnhklhHQ3EZ_V6eWA,3738
|
|
127
126
|
trainml/cloudbender/regions.py,sha256=nfSY9fIWp_AaRE_1Y0qwXX6WVSyPKxpji-zUfM3BNUo,5157
|
|
128
|
-
trainml/cloudbender/services.py,sha256=
|
|
127
|
+
trainml/cloudbender/services.py,sha256=j--8V_JtzhOrWDFXcuyQCZoSdxYKaNtpxTV9qTsva5E,6051
|
|
129
128
|
trainml/projects/__init__.py,sha256=6NKCcHtQMeGB1IyU-djANphfnDX6MEkrXUM5Fyq9fWg,75
|
|
130
129
|
trainml/projects/credentials.py,sha256=6WqHy_-SZZwqE4rULLF8gSyeRVmfsUxqZBuCjBXyxKw,2255
|
|
131
130
|
trainml/projects/data_connectors.py,sha256=WZATdUq4vE3x47Ny5HDwPD7lIUx0syjaSE9BmFWNuEg,2216
|
|
132
131
|
trainml/projects/datastores.py,sha256=qocqD5mGfm2V_wh36CEh3oldnIeJg57ppc6CM129Dkk,2095
|
|
133
|
-
trainml/projects/keys.py,sha256=qcQAdysTbfVW19tzzxZDvBBWjU9DG0dkViLmG_S0SyM,2157
|
|
134
132
|
trainml/projects/members.py,sha256=7fptZ2leIQEUiRtvd3z15RTOJyPafzc5wwQLNxICElQ,2826
|
|
135
133
|
trainml/projects/projects.py,sha256=5_6HUg9ZYq8v69QPgC4Yfd_DM0OlZd8tnxh2ahjOgm0,2890
|
|
136
134
|
trainml/projects/secrets.py,sha256=TIvBd3rAvd4lF3pm5qR98UslHjldzlnzn_n9yvpmLgg,2160
|
|
137
|
-
trainml/projects/services.py,sha256=
|
|
138
|
-
trainml-0.5.
|
|
139
|
-
trainml-0.5.
|
|
140
|
-
trainml-0.5.
|
|
141
|
-
trainml-0.5.
|
|
142
|
-
trainml-0.5.
|
|
143
|
-
trainml-0.5.
|
|
135
|
+
trainml/projects/services.py,sha256=rI-uFmojqOTNLbqBeX6gaSwMkI6LKzRuJthQCH0A2h4,2771
|
|
136
|
+
trainml-0.5.16.dist-info/LICENSE,sha256=s0lpBxhSSUEpMavwde-Vb6K_K7xDCTTvSpNznVqVGR0,1069
|
|
137
|
+
trainml-0.5.16.dist-info/METADATA,sha256=GDO0AdwQL4W28hICeO73fSvtQLu062dl-qyx3CrMSpY,7346
|
|
138
|
+
trainml-0.5.16.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
139
|
+
trainml-0.5.16.dist-info/entry_points.txt,sha256=OzBDm2wXby1bSGF02jTVxzRFZLejnbFiLHXhKdW3Bds,63
|
|
140
|
+
trainml-0.5.16.dist-info/top_level.txt,sha256=Y1kLFRWKUW7RG8BX7cvejHF_yW8wBOaRYF1JQHENY4w,23
|
|
141
|
+
trainml-0.5.16.dist-info/RECORD,,
|
|
@@ -1,43 +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 ProjectKeysTests:
|
|
12
|
-
@fixture(scope="class")
|
|
13
|
-
async def project_key(self, project):
|
|
14
|
-
project_key = await project.keys.put(
|
|
15
|
-
type="aws", key_id="ASFHALKF", secret="IUHKLHKAHF"
|
|
16
|
-
)
|
|
17
|
-
yield project_key
|
|
18
|
-
await project.keys.remove(type="aws")
|
|
19
|
-
|
|
20
|
-
async def test_list_project_keys(self, project, project_key):
|
|
21
|
-
keys = await project.keys.list()
|
|
22
|
-
assert len(keys) > 0
|
|
23
|
-
|
|
24
|
-
async def test_project_key_properties(self, project, project_key):
|
|
25
|
-
assert isinstance(project_key.project_uuid, str)
|
|
26
|
-
assert isinstance(project_key.type, str)
|
|
27
|
-
assert isinstance(project_key.key_id, str)
|
|
28
|
-
assert project_key.type == "aws"
|
|
29
|
-
assert project.id == project_key.project_uuid
|
|
30
|
-
|
|
31
|
-
async def test_project_key_str(self, project_key):
|
|
32
|
-
string = str(project_key)
|
|
33
|
-
regex = r"^{.*\"type\": \"" + project_key.type + r"\".*}$"
|
|
34
|
-
assert isinstance(string, str)
|
|
35
|
-
assert re.match(regex, string)
|
|
36
|
-
|
|
37
|
-
async def test_project_key_repr(self, project_key):
|
|
38
|
-
string = repr(project_key)
|
|
39
|
-
regex = (
|
|
40
|
-
r"^ProjectKey\( trainml , \*\*{.*'type': '" + project_key.type + r"'.*}\)$"
|
|
41
|
-
)
|
|
42
|
-
assert isinstance(string, str)
|
|
43
|
-
assert re.match(regex, string)
|
|
@@ -1,26 +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.project import key as specimen
|
|
10
|
-
from trainml.projects import (
|
|
11
|
-
Project,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def test_list_keys(runner, mock_project_keys):
|
|
16
|
-
with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
|
|
17
|
-
project = create_autospec(Project)
|
|
18
|
-
mock_trainml.projects = AsyncMock()
|
|
19
|
-
mock_trainml.projects.get = AsyncMock(return_value=project)
|
|
20
|
-
mock_trainml.projects.get_current = AsyncMock(return_value=project)
|
|
21
|
-
project.keys = AsyncMock()
|
|
22
|
-
project.keys.list = AsyncMock(return_value=mock_project_keys)
|
|
23
|
-
result = runner.invoke(specimen, ["list"])
|
|
24
|
-
print(result)
|
|
25
|
-
assert result.exit_code == 0
|
|
26
|
-
project.keys.list.assert_called_once()
|
|
@@ -1,96 +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.keys 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 project_keys(mock_trainml):
|
|
20
|
-
yield specimen.ProjectKeys(mock_trainml, project_id="1")
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@fixture
|
|
24
|
-
def project_key(mock_trainml):
|
|
25
|
-
yield specimen.ProjectKey(
|
|
26
|
-
mock_trainml, project_uuid="proj-id-1", type="aws", key_id="AIYHGFSDLK"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ProjectKeysTests:
|
|
31
|
-
@mark.asyncio
|
|
32
|
-
async def test_project_keys_list(self, project_keys, mock_trainml):
|
|
33
|
-
api_response = [
|
|
34
|
-
{"project_uuid": "proj-id-1", "type": "aws", "key_id": "AIYHGFSDLK"},
|
|
35
|
-
{"project_uuid": "proj-id-1", "type": "gcp", "key_id": "credentials.json"},
|
|
36
|
-
]
|
|
37
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
38
|
-
resp = await project_keys.list()
|
|
39
|
-
mock_trainml._query.assert_called_once_with("/project/1/keys", "GET", dict())
|
|
40
|
-
assert len(resp) == 2
|
|
41
|
-
|
|
42
|
-
@mark.asyncio
|
|
43
|
-
async def test_remove_project_key(
|
|
44
|
-
self,
|
|
45
|
-
project_keys,
|
|
46
|
-
mock_trainml,
|
|
47
|
-
):
|
|
48
|
-
api_response = dict()
|
|
49
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
50
|
-
await project_keys.remove("aws")
|
|
51
|
-
mock_trainml._query.assert_called_once_with(
|
|
52
|
-
"/project/1/key/aws", "DELETE", dict()
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
@mark.asyncio
|
|
56
|
-
async def test_put_project_key(self, project_keys, mock_trainml):
|
|
57
|
-
requested_config = dict(type="aws", key_id="AIUDHADA", secret="ASKHJSLKF")
|
|
58
|
-
expected_payload = dict(key_id="AIUDHADA", secret="ASKHJSLKF")
|
|
59
|
-
api_response = {
|
|
60
|
-
"project_uuid": "project-id-1",
|
|
61
|
-
"type": "aws",
|
|
62
|
-
"key_id": "AIUDHADA",
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
66
|
-
response = await project_keys.put(**requested_config)
|
|
67
|
-
mock_trainml._query.assert_called_once_with(
|
|
68
|
-
"/project/1/key/aws", "PUT", None, expected_payload
|
|
69
|
-
)
|
|
70
|
-
assert response.type == "aws"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class ProjectKeyTests:
|
|
74
|
-
def test_project_key_properties(self, project_key):
|
|
75
|
-
assert isinstance(project_key.type, str)
|
|
76
|
-
assert isinstance(project_key.key_id, str)
|
|
77
|
-
assert isinstance(project_key.project_uuid, str)
|
|
78
|
-
|
|
79
|
-
def test_project_key_str(self, project_key):
|
|
80
|
-
string = str(project_key)
|
|
81
|
-
regex = r"^{.*\"type\": \"" + project_key.type + r"\".*}$"
|
|
82
|
-
assert isinstance(string, str)
|
|
83
|
-
assert re.match(regex, string)
|
|
84
|
-
|
|
85
|
-
def test_project_key_repr(self, project_key):
|
|
86
|
-
string = repr(project_key)
|
|
87
|
-
regex = (
|
|
88
|
-
r"^ProjectKey\( trainml , \*\*{.*'type': '" + project_key.type + r"'.*}\)$"
|
|
89
|
-
)
|
|
90
|
-
assert isinstance(string, str)
|
|
91
|
-
assert re.match(regex, string)
|
|
92
|
-
|
|
93
|
-
def test_project_key_bool(self, project_key, mock_trainml):
|
|
94
|
-
empty_project_key = specimen.ProjectKey(mock_trainml)
|
|
95
|
-
assert bool(project_key)
|
|
96
|
-
assert not bool(empty_project_key)
|
trainml/cli/project/key.py
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
import os
|
|
3
|
-
import json
|
|
4
|
-
import base64
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from trainml.cli import pass_config
|
|
7
|
-
from trainml.cli.project import project
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@project.group()
|
|
11
|
-
@pass_config
|
|
12
|
-
def key(config):
|
|
13
|
-
"""trainML project key commands."""
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@key.command()
|
|
18
|
-
@pass_config
|
|
19
|
-
def list(config):
|
|
20
|
-
"""List keys."""
|
|
21
|
-
data = [
|
|
22
|
-
["TYPE", "KEY ID", "UPDATED AT"],
|
|
23
|
-
[
|
|
24
|
-
"-" * 80,
|
|
25
|
-
"-" * 80,
|
|
26
|
-
"-" * 80,
|
|
27
|
-
],
|
|
28
|
-
]
|
|
29
|
-
project = config.trainml.run(config.trainml.client.projects.get_current())
|
|
30
|
-
keys = config.trainml.run(project.keys.list())
|
|
31
|
-
|
|
32
|
-
for key in keys:
|
|
33
|
-
data.append(
|
|
34
|
-
[
|
|
35
|
-
key.type,
|
|
36
|
-
key.key_id,
|
|
37
|
-
key.updated_at.isoformat(timespec="seconds"),
|
|
38
|
-
]
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
for row in data:
|
|
42
|
-
click.echo(
|
|
43
|
-
"{: >13.11} {: >37.35} {: >28.26}" "".format(*row),
|
|
44
|
-
file=config.stdout,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@key.command()
|
|
49
|
-
@click.argument(
|
|
50
|
-
"type",
|
|
51
|
-
type=click.Choice(
|
|
52
|
-
[
|
|
53
|
-
"aws",
|
|
54
|
-
"azure",
|
|
55
|
-
"docker",
|
|
56
|
-
"gcp",
|
|
57
|
-
"huggingface",
|
|
58
|
-
"kaggle",
|
|
59
|
-
"ngc",
|
|
60
|
-
"wasabi",
|
|
61
|
-
],
|
|
62
|
-
case_sensitive=False,
|
|
63
|
-
),
|
|
64
|
-
)
|
|
65
|
-
@pass_config
|
|
66
|
-
def put(config, type):
|
|
67
|
-
"""
|
|
68
|
-
Set a key.
|
|
69
|
-
|
|
70
|
-
A key is uploaded.
|
|
71
|
-
"""
|
|
72
|
-
project = config.trainml.run(config.trainml.client.projects.get_current())
|
|
73
|
-
|
|
74
|
-
tenant = None
|
|
75
|
-
|
|
76
|
-
if type in ["aws", "wasabi"]:
|
|
77
|
-
key_id = click.prompt("Enter the key ID", type=str, hide_input=False)
|
|
78
|
-
secret = click.prompt("Enter the secret key", type=str, hide_input=True)
|
|
79
|
-
elif type == "azure":
|
|
80
|
-
key_id = click.prompt(
|
|
81
|
-
"Enter the Application (client) ID", type=str, hide_input=False
|
|
82
|
-
)
|
|
83
|
-
tenant = click.prompt(
|
|
84
|
-
"Enter the Directory (tenant) ley", type=str, hide_input=False
|
|
85
|
-
)
|
|
86
|
-
secret = click.prompt("Enter the client secret", type=str, hide_input=True)
|
|
87
|
-
elif type in ["docker", "huggingface"]:
|
|
88
|
-
key_id = click.prompt("Enter the username", type=str, hide_input=False)
|
|
89
|
-
secret = click.prompt("Enter the access token", type=str, hide_input=True)
|
|
90
|
-
elif type in ["gcp", "kaggle"]:
|
|
91
|
-
file_name = click.prompt(
|
|
92
|
-
"Enter the path of the credentials file",
|
|
93
|
-
type=click.Path(
|
|
94
|
-
exists=True, file_okay=True, dir_okay=False, resolve_path=True
|
|
95
|
-
),
|
|
96
|
-
hide_input=False,
|
|
97
|
-
)
|
|
98
|
-
key_id = os.path.basename(file_name)
|
|
99
|
-
with open(file_name) as f:
|
|
100
|
-
secret = json.load(f)
|
|
101
|
-
secret = json.dumps(secret)
|
|
102
|
-
elif type == "ngc":
|
|
103
|
-
key_id = "$oauthtoken"
|
|
104
|
-
secret = click.prompt("Enter the access token", type=str, hide_input=True)
|
|
105
|
-
else:
|
|
106
|
-
raise click.UsageError("Unsupported key type")
|
|
107
|
-
|
|
108
|
-
return config.trainml.run(
|
|
109
|
-
project.keys.put(type=type, key_id=key_id, secret=secret, tenant=tenant)
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
@key.command()
|
|
114
|
-
@click.argument("name", type=click.STRING)
|
|
115
|
-
@pass_config
|
|
116
|
-
def remove(config, name):
|
|
117
|
-
"""
|
|
118
|
-
Remove a key.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"""
|
|
122
|
-
project = config.trainml.run(config.trainml.client.projects.get_current())
|
|
123
|
-
|
|
124
|
-
return config.trainml.run(project.key.remove(name))
|
trainml/projects/keys.py
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import logging
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from dateutil import parser, tz
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ProjectKeys(object):
|
|
8
|
-
def __init__(self, trainml, project_id):
|
|
9
|
-
self.trainml = trainml
|
|
10
|
-
self.project_id = project_id
|
|
11
|
-
|
|
12
|
-
async def list(self, **kwargs):
|
|
13
|
-
resp = await self.trainml._query(
|
|
14
|
-
f"/project/{self.project_id}/keys", "GET", kwargs
|
|
15
|
-
)
|
|
16
|
-
keys = [ProjectKey(self.trainml, **service) for service in resp]
|
|
17
|
-
return keys
|
|
18
|
-
|
|
19
|
-
async def put(self, type, key_id, secret, tenant=None, **kwargs):
|
|
20
|
-
data = dict(key_id=key_id, secret=secret, tenant=tenant)
|
|
21
|
-
payload = {k: v for k, v in data.items() if v is not None}
|
|
22
|
-
logging.info(f"Creating Project Key {type}")
|
|
23
|
-
resp = await self.trainml._query(
|
|
24
|
-
f"/project/{self.project_id}/key/{type}", "PUT", None, payload
|
|
25
|
-
)
|
|
26
|
-
key = ProjectKey(self.trainml, **resp)
|
|
27
|
-
logging.info(f"Created Project Key {type} in project {self.project_id}")
|
|
28
|
-
|
|
29
|
-
return key
|
|
30
|
-
|
|
31
|
-
async def remove(self, type, **kwargs):
|
|
32
|
-
await self.trainml._query(
|
|
33
|
-
f"/project/{self.project_id}/key/{type}", "DELETE", kwargs
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class ProjectKey:
|
|
38
|
-
def __init__(self, trainml, **kwargs):
|
|
39
|
-
self.trainml = trainml
|
|
40
|
-
self._entity = kwargs
|
|
41
|
-
self._type = self._entity.get("type")
|
|
42
|
-
self._project_uuid = self._entity.get("project_uuid")
|
|
43
|
-
self._key_id = self._entity.get("key_id")
|
|
44
|
-
self._updated_at = self._entity.get("updatedAt")
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def type(self) -> str:
|
|
48
|
-
return self._type
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def project_uuid(self) -> str:
|
|
52
|
-
return self._project_uuid
|
|
53
|
-
|
|
54
|
-
@property
|
|
55
|
-
def key_id(self) -> str:
|
|
56
|
-
return self._key_id
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def updated_at(self) -> datetime:
|
|
60
|
-
timestamp = parser.isoparse(self._updated_at)
|
|
61
|
-
timezone = tz.tzlocal()
|
|
62
|
-
return timestamp.astimezone(timezone)
|
|
63
|
-
|
|
64
|
-
def __str__(self):
|
|
65
|
-
return json.dumps({k: v for k, v in self._entity.items()})
|
|
66
|
-
|
|
67
|
-
def __repr__(self):
|
|
68
|
-
return f"ProjectKey( trainml , **{self._entity.__repr__()})"
|
|
69
|
-
|
|
70
|
-
def __bool__(self):
|
|
71
|
-
return bool(self._type)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|