dtlpy 1.115.44__py3-none-any.whl → 1.116.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dtlpy/__init__.py +491 -491
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__init__.py +26 -26
- dtlpy/assets/code_server/config.yaml +2 -2
- dtlpy/assets/code_server/installation.sh +24 -24
- dtlpy/assets/code_server/launch.json +13 -13
- dtlpy/assets/code_server/settings.json +2 -2
- dtlpy/assets/main.py +53 -53
- dtlpy/assets/main_partial.py +18 -18
- dtlpy/assets/mock.json +11 -11
- dtlpy/assets/model_adapter.py +83 -83
- dtlpy/assets/package.json +61 -61
- dtlpy/assets/package_catalog.json +29 -29
- dtlpy/assets/package_gitignore +307 -307
- dtlpy/assets/service_runners/__init__.py +33 -33
- dtlpy/assets/service_runners/converter.py +96 -96
- dtlpy/assets/service_runners/multi_method.py +49 -49
- dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
- dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
- dtlpy/assets/service_runners/multi_method_item.py +52 -52
- dtlpy/assets/service_runners/multi_method_json.py +52 -52
- dtlpy/assets/service_runners/single_method.py +37 -37
- dtlpy/assets/service_runners/single_method_annotation.py +43 -43
- dtlpy/assets/service_runners/single_method_dataset.py +43 -43
- dtlpy/assets/service_runners/single_method_item.py +41 -41
- dtlpy/assets/service_runners/single_method_json.py +42 -42
- dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
- dtlpy/assets/voc_annotation_template.xml +23 -23
- dtlpy/caches/base_cache.py +32 -32
- dtlpy/caches/cache.py +473 -473
- dtlpy/caches/dl_cache.py +201 -201
- dtlpy/caches/filesystem_cache.py +89 -89
- dtlpy/caches/redis_cache.py +84 -84
- dtlpy/dlp/__init__.py +20 -20
- dtlpy/dlp/cli_utilities.py +367 -367
- dtlpy/dlp/command_executor.py +764 -764
- dtlpy/dlp/dlp +1 -1
- dtlpy/dlp/dlp.bat +1 -1
- dtlpy/dlp/dlp.py +128 -128
- dtlpy/dlp/parser.py +651 -651
- dtlpy/entities/__init__.py +83 -83
- dtlpy/entities/analytic.py +347 -347
- dtlpy/entities/annotation.py +1879 -1879
- dtlpy/entities/annotation_collection.py +699 -699
- dtlpy/entities/annotation_definitions/__init__.py +20 -20
- dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
- dtlpy/entities/annotation_definitions/box.py +195 -195
- dtlpy/entities/annotation_definitions/classification.py +67 -67
- dtlpy/entities/annotation_definitions/comparison.py +72 -72
- dtlpy/entities/annotation_definitions/cube.py +204 -204
- dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
- dtlpy/entities/annotation_definitions/description.py +32 -32
- dtlpy/entities/annotation_definitions/ellipse.py +124 -124
- dtlpy/entities/annotation_definitions/free_text.py +62 -62
- dtlpy/entities/annotation_definitions/gis.py +69 -69
- dtlpy/entities/annotation_definitions/note.py +139 -139
- dtlpy/entities/annotation_definitions/point.py +117 -117
- dtlpy/entities/annotation_definitions/polygon.py +182 -182
- dtlpy/entities/annotation_definitions/polyline.py +111 -111
- dtlpy/entities/annotation_definitions/pose.py +92 -92
- dtlpy/entities/annotation_definitions/ref_image.py +86 -86
- dtlpy/entities/annotation_definitions/segmentation.py +240 -240
- dtlpy/entities/annotation_definitions/subtitle.py +34 -34
- dtlpy/entities/annotation_definitions/text.py +85 -85
- dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
- dtlpy/entities/app.py +220 -220
- dtlpy/entities/app_module.py +107 -107
- dtlpy/entities/artifact.py +174 -174
- dtlpy/entities/assignment.py +399 -399
- dtlpy/entities/base_entity.py +214 -214
- dtlpy/entities/bot.py +113 -113
- dtlpy/entities/codebase.py +292 -292
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +449 -449
- dtlpy/entities/dataset.py +1299 -1299
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +235 -235
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +145 -145
- dtlpy/entities/filters.py +798 -798
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +959 -959
- dtlpy/entities/label.py +123 -123
- dtlpy/entities/links.py +85 -85
- dtlpy/entities/message.py +175 -175
- dtlpy/entities/model.py +684 -684
- dtlpy/entities/node.py +1005 -1005
- dtlpy/entities/ontology.py +810 -803
- dtlpy/entities/organization.py +287 -287
- dtlpy/entities/package.py +657 -657
- dtlpy/entities/package_defaults.py +5 -5
- dtlpy/entities/package_function.py +185 -185
- dtlpy/entities/package_module.py +113 -113
- dtlpy/entities/package_slot.py +118 -118
- dtlpy/entities/paged_entities.py +299 -299
- dtlpy/entities/pipeline.py +624 -624
- dtlpy/entities/pipeline_execution.py +279 -279
- dtlpy/entities/project.py +394 -394
- dtlpy/entities/prompt_item.py +505 -505
- dtlpy/entities/recipe.py +301 -301
- dtlpy/entities/reflect_dict.py +102 -102
- dtlpy/entities/resource_execution.py +138 -138
- dtlpy/entities/service.py +963 -963
- dtlpy/entities/service_driver.py +117 -117
- dtlpy/entities/setting.py +294 -294
- dtlpy/entities/task.py +495 -495
- dtlpy/entities/time_series.py +143 -143
- dtlpy/entities/trigger.py +426 -426
- dtlpy/entities/user.py +118 -118
- dtlpy/entities/webhook.py +124 -124
- dtlpy/examples/__init__.py +19 -19
- dtlpy/examples/add_labels.py +135 -135
- dtlpy/examples/add_metadata_to_item.py +21 -21
- dtlpy/examples/annotate_items_using_model.py +65 -65
- dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
- dtlpy/examples/annotations_convert_to_voc.py +9 -9
- dtlpy/examples/annotations_convert_to_yolo.py +9 -9
- dtlpy/examples/convert_annotation_types.py +51 -51
- dtlpy/examples/converter.py +143 -143
- dtlpy/examples/copy_annotations.py +22 -22
- dtlpy/examples/copy_folder.py +31 -31
- dtlpy/examples/create_annotations.py +51 -51
- dtlpy/examples/create_video_annotations.py +83 -83
- dtlpy/examples/delete_annotations.py +26 -26
- dtlpy/examples/filters.py +113 -113
- dtlpy/examples/move_item.py +23 -23
- dtlpy/examples/play_video_annotation.py +13 -13
- dtlpy/examples/show_item_and_mask.py +53 -53
- dtlpy/examples/triggers.py +49 -49
- dtlpy/examples/upload_batch_of_items.py +20 -20
- dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
- dtlpy/examples/upload_items_with_modalities.py +43 -43
- dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
- dtlpy/examples/upload_yolo_format_annotations.py +70 -70
- dtlpy/exceptions.py +125 -125
- dtlpy/miscellaneous/__init__.py +20 -20
- dtlpy/miscellaneous/dict_differ.py +95 -95
- dtlpy/miscellaneous/git_utils.py +217 -217
- dtlpy/miscellaneous/json_utils.py +14 -14
- dtlpy/miscellaneous/list_print.py +105 -105
- dtlpy/miscellaneous/zipping.py +130 -130
- dtlpy/ml/__init__.py +20 -20
- dtlpy/ml/base_feature_extractor_adapter.py +27 -27
- dtlpy/ml/base_model_adapter.py +1257 -1230
- dtlpy/ml/metrics.py +461 -461
- dtlpy/ml/predictions_utils.py +274 -274
- dtlpy/ml/summary_writer.py +57 -57
- dtlpy/ml/train_utils.py +60 -60
- dtlpy/new_instance.py +252 -252
- dtlpy/repositories/__init__.py +56 -56
- dtlpy/repositories/analytics.py +85 -85
- dtlpy/repositories/annotations.py +916 -916
- dtlpy/repositories/apps.py +383 -383
- dtlpy/repositories/artifacts.py +452 -452
- dtlpy/repositories/assignments.py +599 -599
- dtlpy/repositories/bots.py +213 -213
- dtlpy/repositories/codebases.py +559 -559
- dtlpy/repositories/collections.py +332 -332
- dtlpy/repositories/commands.py +152 -152
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +439 -439
- dtlpy/repositories/datasets.py +1504 -1504
- dtlpy/repositories/downloader.py +976 -923
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -482
- dtlpy/repositories/executions.py +815 -815
- dtlpy/repositories/feature_sets.py +226 -226
- dtlpy/repositories/features.py +255 -255
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +912 -912
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +1000 -1000
- dtlpy/repositories/nodes.py +80 -80
- dtlpy/repositories/ontologies.py +511 -511
- dtlpy/repositories/organizations.py +525 -525
- dtlpy/repositories/packages.py +1941 -1941
- dtlpy/repositories/pipeline_executions.py +451 -451
- dtlpy/repositories/pipelines.py +640 -640
- dtlpy/repositories/projects.py +539 -539
- dtlpy/repositories/recipes.py +419 -399
- dtlpy/repositories/resource_executions.py +137 -137
- dtlpy/repositories/schema.py +120 -120
- dtlpy/repositories/service_drivers.py +213 -213
- dtlpy/repositories/services.py +1704 -1704
- dtlpy/repositories/settings.py +339 -339
- dtlpy/repositories/tasks.py +1477 -1477
- dtlpy/repositories/times_series.py +278 -278
- dtlpy/repositories/triggers.py +536 -536
- dtlpy/repositories/upload_element.py +257 -257
- dtlpy/repositories/uploader.py +661 -661
- dtlpy/repositories/webhooks.py +249 -249
- dtlpy/services/__init__.py +22 -22
- dtlpy/services/aihttp_retry.py +131 -131
- dtlpy/services/api_client.py +1785 -1785
- dtlpy/services/api_reference.py +40 -40
- dtlpy/services/async_utils.py +133 -133
- dtlpy/services/calls_counter.py +44 -44
- dtlpy/services/check_sdk.py +68 -68
- dtlpy/services/cookie.py +115 -115
- dtlpy/services/create_logger.py +156 -156
- dtlpy/services/events.py +84 -84
- dtlpy/services/logins.py +235 -235
- dtlpy/services/reporter.py +256 -256
- dtlpy/services/service_defaults.py +91 -91
- dtlpy/utilities/__init__.py +20 -20
- dtlpy/utilities/annotations/__init__.py +16 -16
- dtlpy/utilities/annotations/annotation_converters.py +269 -269
- dtlpy/utilities/base_package_runner.py +285 -264
- dtlpy/utilities/converter.py +1650 -1650
- dtlpy/utilities/dataset_generators/__init__.py +1 -1
- dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
- dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
- dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
- dtlpy/utilities/local_development/__init__.py +1 -1
- dtlpy/utilities/local_development/local_session.py +179 -179
- dtlpy/utilities/reports/__init__.py +2 -2
- dtlpy/utilities/reports/figures.py +343 -343
- dtlpy/utilities/reports/report.py +71 -71
- dtlpy/utilities/videos/__init__.py +17 -17
- dtlpy/utilities/videos/video_player.py +598 -598
- dtlpy/utilities/videos/videos.py +470 -470
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp +1 -1
- dtlpy-1.116.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.115.44.data → dtlpy-1.116.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/METADATA +186 -186
- dtlpy-1.116.6.dist-info/RECORD +239 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/licenses/LICENSE +200 -200
- tests/features/environment.py +551 -551
- dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
- dtlpy-1.115.44.data/scripts/dlp.bat +0 -2
- dtlpy-1.115.44.dist-info/RECORD +0 -240
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.115.44.dist-info → dtlpy-1.116.6.dist-info}/top_level.txt +0 -0
|
@@ -1,484 +1,484 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Integrations Repository
|
|
3
|
-
"""
|
|
4
|
-
import base64
|
|
5
|
-
import json
|
|
6
|
-
import logging
|
|
7
|
-
from .. import entities, exceptions, miscellaneous, _api_reference
|
|
8
|
-
from ..services.api_client import ApiClient
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(name='dtlpy')
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Integrations:
|
|
14
|
-
"""
|
|
15
|
-
Integrations Repository
|
|
16
|
-
|
|
17
|
-
The Integrations class allows you to manage data integrations from your external storage (e.g., S3, GCS, Azure)
|
|
18
|
-
into your Dataloop's Dataset storage, as well as sync data in your Dataloop's Datasets with data in your external
|
|
19
|
-
storage.
|
|
20
|
-
|
|
21
|
-
For more information on Organization Storage Integration see the `Dataloop documentation <https://dataloop.ai/docs/organization-integrations>`_ and `developers' docs <https://developers.dataloop.ai/tutorials/data_management/>`_.
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def __init__(self, client_api: ApiClient, org: entities.Organization = None,
|
|
26
|
-
project: entities.Project = None):
|
|
27
|
-
self._client_api = client_api
|
|
28
|
-
self._org = org
|
|
29
|
-
self._project = project
|
|
30
|
-
|
|
31
|
-
@property
|
|
32
|
-
def project(self) -> entities.Project:
|
|
33
|
-
return self._project
|
|
34
|
-
|
|
35
|
-
@project.setter
|
|
36
|
-
def project(self, project: entities.Project):
|
|
37
|
-
if not isinstance(project, entities.Project):
|
|
38
|
-
raise ValueError('Must input a valid Project entity')
|
|
39
|
-
self._project = project
|
|
40
|
-
|
|
41
|
-
@property
|
|
42
|
-
def org(self) -> entities.Organization:
|
|
43
|
-
if self._org is None:
|
|
44
|
-
if self.project is not None:
|
|
45
|
-
self._org = entities.Organization.from_json(_json=self.project.org, client_api=self._client_api)
|
|
46
|
-
return self._org
|
|
47
|
-
|
|
48
|
-
@org.setter
|
|
49
|
-
def org(self, org: entities.Organization):
|
|
50
|
-
if not isinstance(org, entities.Organization):
|
|
51
|
-
raise ValueError('Must input a valid Organization entity')
|
|
52
|
-
self._org = org
|
|
53
|
-
|
|
54
|
-
@_api_reference.add(path='/orgs/{orgId}/integrations/{integrationId}', method='delete')
|
|
55
|
-
def delete(self,
|
|
56
|
-
integrations_id: str,
|
|
57
|
-
sure: bool = False,
|
|
58
|
-
really: bool = False,
|
|
59
|
-
organization_id: str = None
|
|
60
|
-
) -> bool:
|
|
61
|
-
"""
|
|
62
|
-
Delete integrations from the organization.
|
|
63
|
-
|
|
64
|
-
**Prerequisites**: You must be an organization *owner* to delete an integration.
|
|
65
|
-
|
|
66
|
-
:param organization_id: organization id
|
|
67
|
-
:param str integrations_id: integrations id
|
|
68
|
-
:param bool sure: Are you sure you want to delete?
|
|
69
|
-
:param bool really: Really really sure?
|
|
70
|
-
:return: success
|
|
71
|
-
:rtype: bool
|
|
72
|
-
|
|
73
|
-
**Example**:
|
|
74
|
-
|
|
75
|
-
.. code-block:: python
|
|
76
|
-
|
|
77
|
-
project.integrations.delete(integrations_id='integrations_id', sure=True, really=True)
|
|
78
|
-
"""
|
|
79
|
-
if sure and really:
|
|
80
|
-
if self.project is None and self.org is None and organization_id is None:
|
|
81
|
-
raise exceptions.PlatformException(
|
|
82
|
-
error='400',
|
|
83
|
-
message='Must provide an identifier in inputs')
|
|
84
|
-
|
|
85
|
-
if organization_id is None:
|
|
86
|
-
if self.project is not None:
|
|
87
|
-
organization_id = self.project.org.get('id')
|
|
88
|
-
else:
|
|
89
|
-
organization_id = self.org.id
|
|
90
|
-
|
|
91
|
-
url_path = '/orgs/{}/integrations/{}'.format(organization_id, integrations_id)
|
|
92
|
-
success, response = self._client_api.gen_request(req_type='delete',
|
|
93
|
-
path=url_path)
|
|
94
|
-
if not success:
|
|
95
|
-
raise exceptions.PlatformException(response)
|
|
96
|
-
else:
|
|
97
|
-
return True
|
|
98
|
-
else:
|
|
99
|
-
raise exceptions.PlatformException(
|
|
100
|
-
error='403',
|
|
101
|
-
message='Cant delete integrations from SDK. Please login to platform to delete')
|
|
102
|
-
|
|
103
|
-
@_api_reference.add(path='/orgs/{orgId}/integrations', method='post')
|
|
104
|
-
def create(self,
|
|
105
|
-
integrations_type: entities.IntegrationType,
|
|
106
|
-
name: str,
|
|
107
|
-
options: dict,
|
|
108
|
-
metadata: dict = None,
|
|
109
|
-
organization_id: str = None,
|
|
110
|
-
):
|
|
111
|
-
"""
|
|
112
|
-
Create an integration between an external storage and the organization.
|
|
113
|
-
|
|
114
|
-
**Examples for options include**:
|
|
115
|
-
s3 - {key: "", secret: ""};
|
|
116
|
-
gcs - {key: "", secret: "", content: ""};
|
|
117
|
-
azureblob - {key: "", secret: "", clientId: "", tenantId: ""};
|
|
118
|
-
key_value - {key: "", value: ""}
|
|
119
|
-
aws-sts - {key: "", secret: "", roleArns: ""}
|
|
120
|
-
aws-cross - {}
|
|
121
|
-
gcp-cross - {}
|
|
122
|
-
gcp-workload-identity-federation - {"secret": "", "content": "{}", "clientId": ""}
|
|
123
|
-
private-registry (ECR) - can use generate_ecr_options to generate the options
|
|
124
|
-
private-registry (GAR) - use generate_gar_options to generate the options
|
|
125
|
-
private-registry (ACR) - use generate_azure_container_registry_options to generate the options
|
|
126
|
-
private-registry (DockerHub) - use generate_docker_hub_options to generate the options
|
|
127
|
-
|
|
128
|
-
**Prerequisites**: You must be an *owner* in the organization.
|
|
129
|
-
|
|
130
|
-
:param IntegrationType integrations_type: integrations type dl.IntegrationType
|
|
131
|
-
:param str name: integrations name
|
|
132
|
-
:param dict options: dict of storage secrets
|
|
133
|
-
:param dict metadata: metadata
|
|
134
|
-
:param str organization_id: organization id
|
|
135
|
-
:return: success
|
|
136
|
-
:rtype: bool
|
|
137
|
-
|
|
138
|
-
**Example**:
|
|
139
|
-
|
|
140
|
-
.. code-block:: python
|
|
141
|
-
|
|
142
|
-
project.integrations.create(integrations_type=dl.IntegrationType.S3,
|
|
143
|
-
name='S3Integration',
|
|
144
|
-
options={key: "Access key ID", secret: "Secret access key"})
|
|
145
|
-
"""
|
|
146
|
-
|
|
147
|
-
if self.project is None and self.org is None and organization_id is None:
|
|
148
|
-
raise exceptions.PlatformException(
|
|
149
|
-
error='400',
|
|
150
|
-
message='Must have an organization or project')
|
|
151
|
-
|
|
152
|
-
if organization_id is None:
|
|
153
|
-
if self.project is not None:
|
|
154
|
-
organization_id = self.project.org.get('id')
|
|
155
|
-
else:
|
|
156
|
-
organization_id = self.org.id
|
|
157
|
-
|
|
158
|
-
url_path = '/orgs/{}/integrations'.format(organization_id)
|
|
159
|
-
payload = {"type": integrations_type.value if isinstance(integrations_type,
|
|
160
|
-
entities.IntegrationType) else integrations_type,
|
|
161
|
-
'name': name, 'options': options}
|
|
162
|
-
if metadata is not None:
|
|
163
|
-
payload['metadata'] = metadata
|
|
164
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
165
|
-
path=url_path,
|
|
166
|
-
json_req=payload)
|
|
167
|
-
if not success:
|
|
168
|
-
raise exceptions.PlatformException(response)
|
|
169
|
-
else:
|
|
170
|
-
integration = entities.Integration.from_json(_json=response.json(), client_api=self._client_api)
|
|
171
|
-
if integration.metadata and isinstance(integration.metadata, list) and len(integration.metadata) > 0:
|
|
172
|
-
for m in integration.metadata:
|
|
173
|
-
if m['name'] == 'status':
|
|
174
|
-
integration_status = m['value']
|
|
175
|
-
logger.info('Integration status: {}'.format(integration_status))
|
|
176
|
-
return integration
|
|
177
|
-
|
|
178
|
-
@_api_reference.add(path='/orgs/{orgId}/integrations', method='patch')
|
|
179
|
-
def update(self,
|
|
180
|
-
new_name: str = None,
|
|
181
|
-
integrations_id: str = None,
|
|
182
|
-
integration: entities.Integration = None,
|
|
183
|
-
new_options: dict = None,
|
|
184
|
-
organization_id: str = None,
|
|
185
|
-
reload_services: bool = None,
|
|
186
|
-
):
|
|
187
|
-
"""
|
|
188
|
-
Update the integration's name.
|
|
189
|
-
|
|
190
|
-
**Prerequisites**: You must be an *owner* in the organization.
|
|
191
|
-
|
|
192
|
-
:param str new_name: new name
|
|
193
|
-
:param str integrations_id: integrations id
|
|
194
|
-
:param Integration integration: integration object
|
|
195
|
-
:param dict new_options: new value
|
|
196
|
-
:param str organization_id: organization id
|
|
197
|
-
:param bool reload_services: reload services associated with this integration
|
|
198
|
-
:return: Integration object
|
|
199
|
-
:rtype: dtlpy.entities.integration.Integration
|
|
200
|
-
|
|
201
|
-
**Examples for options include**:
|
|
202
|
-
s3 - {key: "", secret: ""};
|
|
203
|
-
gcs - {key: "", secret: "", content: ""};
|
|
204
|
-
azureblob - {key: "", secret: "", clientId: "", tenantId: ""};
|
|
205
|
-
key_value - {key: "", value: ""}
|
|
206
|
-
aws-sts - {key: "", secret: "", roleArns: ""}
|
|
207
|
-
aws-cross - {roleArn: ""}
|
|
208
|
-
gcp-cross - {"email: "", "resourceName": ""}
|
|
209
|
-
|
|
210
|
-
**Example**:
|
|
211
|
-
|
|
212
|
-
.. code-block:: python
|
|
213
|
-
|
|
214
|
-
project.integrations.update(integrations_id='integrations_id', new_options={roleArn: ""})
|
|
215
|
-
"""
|
|
216
|
-
|
|
217
|
-
if self.project is None and self.org is None and organization_id is None:
|
|
218
|
-
raise exceptions.PlatformException(
|
|
219
|
-
error='400',
|
|
220
|
-
message='Must have an organization or project')
|
|
221
|
-
if integrations_id is None and integration is None:
|
|
222
|
-
raise exceptions.PlatformException(
|
|
223
|
-
error='400',
|
|
224
|
-
message='Must have an integrations_id or integration')
|
|
225
|
-
|
|
226
|
-
if organization_id is None:
|
|
227
|
-
if self.project is not None:
|
|
228
|
-
organization_id = self.project.org.get('id')
|
|
229
|
-
else:
|
|
230
|
-
organization_id = self.org.id
|
|
231
|
-
|
|
232
|
-
if reload_services is None:
|
|
233
|
-
logger.warning(
|
|
234
|
-
"Param reload_services was not provided. If the integration you are updating is used\n"
|
|
235
|
-
"in FaaS services these services will keep using the old value until updated."
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
url_path = '/orgs/{org_id}/integrations{query_params}'.format(
|
|
239
|
-
org_id=organization_id,
|
|
240
|
-
query_params='?reloadServices=true' if reload_services else ''
|
|
241
|
-
)
|
|
242
|
-
payload = dict(integrationId=integrations_id if integrations_id is not None else integration.id)
|
|
243
|
-
if new_name is not None:
|
|
244
|
-
payload['name'] = new_name
|
|
245
|
-
if new_options is not None:
|
|
246
|
-
if integration is None:
|
|
247
|
-
integration = self.get(integrations_id=integrations_id)
|
|
248
|
-
payload['credentials'] = dict(options=new_options, type=integration.type)
|
|
249
|
-
|
|
250
|
-
success, response = self._client_api.gen_request(req_type='patch',
|
|
251
|
-
path=url_path,
|
|
252
|
-
json_req=payload)
|
|
253
|
-
if not success:
|
|
254
|
-
raise exceptions.PlatformException(response)
|
|
255
|
-
|
|
256
|
-
return entities.Integration.from_json(_json=response.json(), client_api=self._client_api)
|
|
257
|
-
|
|
258
|
-
@_api_reference.add(path='/orgs/{orgId}/integrations/{integrationId}', method='get')
|
|
259
|
-
def get(self, integrations_id: str, organization_id: str = None):
|
|
260
|
-
"""
|
|
261
|
-
Get organization integrations. Use this method to access your integration and be able to use it in your code.
|
|
262
|
-
|
|
263
|
-
**Prerequisites**: You must be an *owner* in the organization.
|
|
264
|
-
|
|
265
|
-
:param str integrations_id: integrations id
|
|
266
|
-
:param str organization_id: organization id
|
|
267
|
-
:return: Integration object
|
|
268
|
-
:rtype: dtlpy.entities.integration.Integration
|
|
269
|
-
|
|
270
|
-
**Example**:
|
|
271
|
-
|
|
272
|
-
.. code-block:: python
|
|
273
|
-
|
|
274
|
-
project.integrations.get(integrations_id='integrations_id')
|
|
275
|
-
"""
|
|
276
|
-
if self.project is None and self.org is None and organization_id is None:
|
|
277
|
-
raise exceptions.PlatformException(
|
|
278
|
-
error='400',
|
|
279
|
-
message='Must have an organization or project')
|
|
280
|
-
|
|
281
|
-
if organization_id is None:
|
|
282
|
-
if self.project is not None:
|
|
283
|
-
organization_id = self.project.org.get('id')
|
|
284
|
-
else:
|
|
285
|
-
organization_id = self.org.id
|
|
286
|
-
|
|
287
|
-
url_path = '/orgs/{}/integrations/{}'.format(organization_id, integrations_id)
|
|
288
|
-
|
|
289
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
290
|
-
path=url_path)
|
|
291
|
-
if not success:
|
|
292
|
-
raise exceptions.PlatformException(response)
|
|
293
|
-
return entities.Integration.from_json(_json=response.json(), client_api=self._client_api)
|
|
294
|
-
|
|
295
|
-
@_api_reference.add(path='/orgs/{orgId}/integrations', method='get')
|
|
296
|
-
def list(self, only_available=False, organization_id: str = None):
|
|
297
|
-
"""
|
|
298
|
-
List all the organization's integrations with external storage.
|
|
299
|
-
|
|
300
|
-
**Prerequisites**: You must be an *owner* in the organization.
|
|
301
|
-
|
|
302
|
-
:param bool only_available: if True list only the available integrations.
|
|
303
|
-
:param str organization_id: organization id
|
|
304
|
-
:return: groups list
|
|
305
|
-
:rtype: list
|
|
306
|
-
|
|
307
|
-
**Example**:
|
|
308
|
-
|
|
309
|
-
.. code-block:: python
|
|
310
|
-
|
|
311
|
-
project.integrations.list(only_available=True)
|
|
312
|
-
"""
|
|
313
|
-
if self.project is None and self.org is None and organization_id is None:
|
|
314
|
-
raise exceptions.PlatformException(
|
|
315
|
-
error='400',
|
|
316
|
-
message='Must have an organization or project')
|
|
317
|
-
|
|
318
|
-
if organization_id is None:
|
|
319
|
-
if self.project is not None:
|
|
320
|
-
organization_id = self.project.org.get('id')
|
|
321
|
-
else:
|
|
322
|
-
organization_id = self.org.id
|
|
323
|
-
|
|
324
|
-
if only_available:
|
|
325
|
-
url_path = '/orgs/{}/availableIntegrations'.format(organization_id)
|
|
326
|
-
else:
|
|
327
|
-
url_path = '/orgs/{}/integrations'.format(organization_id)
|
|
328
|
-
|
|
329
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
330
|
-
path=url_path)
|
|
331
|
-
if not success:
|
|
332
|
-
raise exceptions.PlatformException(response)
|
|
333
|
-
|
|
334
|
-
available_integrations = miscellaneous.List(response.json())
|
|
335
|
-
return available_integrations
|
|
336
|
-
|
|
337
|
-
@staticmethod
|
|
338
|
-
def generate_gar_options(service_account: str, location: str, email: str = None) -> dict:
|
|
339
|
-
"""
|
|
340
|
-
Generates a Google Artifact Registry JSON configuration and returns it as a base64-encoded string.
|
|
341
|
-
|
|
342
|
-
Parameters:
|
|
343
|
-
location (str): The region where the repository will be created (e.g., 'us-central1').
|
|
344
|
-
service_account (str): The service_account parameter represents the Google Cloud service account credentials
|
|
345
|
-
in the form of a JSON key file. This JSON contains the private key and other metadata
|
|
346
|
-
required for authenticating with Google Artifact Registry. It is used to generate a Kubernetes secret
|
|
347
|
-
that stores the credentials for pulling container images from the registry.
|
|
348
|
-
The JSON key must include fields such as client_email, private_key, and project_id,
|
|
349
|
-
and it is typically downloaded from the Google Cloud Console when creating the service account
|
|
350
|
-
|
|
351
|
-
Returns:
|
|
352
|
-
str: A base64-encoded string representation of the repository JSON configuration.
|
|
353
|
-
"""
|
|
354
|
-
return IntegrationUtils.generate_gar_options(service_account=service_account, location=location, email=email)
|
|
355
|
-
|
|
356
|
-
@staticmethod
|
|
357
|
-
def generate_docker_hub_options(username: str, password: str, email: str = None) -> dict:
|
|
358
|
-
"""
|
|
359
|
-
Generates a Docker Hub JSON configuration and returns it as a base64-encoded string.
|
|
360
|
-
|
|
361
|
-
Parameters:
|
|
362
|
-
username (str): The Docker Hub username.
|
|
363
|
-
password (str): The Docker Hub password.
|
|
364
|
-
email (str): Optional - Docker Hub email.
|
|
365
|
-
|
|
366
|
-
Returns:
|
|
367
|
-
str: A base64-encoded string representation of the repository JSON configuration.
|
|
368
|
-
"""
|
|
369
|
-
return IntegrationUtils.generate_docker_hub_options(username=username, password=password, email=email)
|
|
370
|
-
|
|
371
|
-
@staticmethod
|
|
372
|
-
def generate_azure_container_registry_options(username: str, password: str, location: str) -> dict:
|
|
373
|
-
"""
|
|
374
|
-
Generates an Azure Container Registry JSON configuration and returns it as a base64-encoded string.
|
|
375
|
-
|
|
376
|
-
Parameters:
|
|
377
|
-
username (str): The Azure username.
|
|
378
|
-
password (str): The Azure password.
|
|
379
|
-
location (str): server URL of Azure Container Registry
|
|
380
|
-
|
|
381
|
-
Returns:
|
|
382
|
-
str: A base64-encoded string representation of the repository JSON configuration.
|
|
383
|
-
"""
|
|
384
|
-
return IntegrationUtils.generate_docker_hub_options(username=username, password=password, location=location)
|
|
385
|
-
|
|
386
|
-
@staticmethod
|
|
387
|
-
def generate_ecr_options(access_key_id: str, secret_access_key: str, account: str, region: str) -> dict:
|
|
388
|
-
"""
|
|
389
|
-
Generates an Amazon Elastic Container Registry (ECR) JSON configuration and returns it as a base64-encoded string.
|
|
390
|
-
|
|
391
|
-
Parameters:
|
|
392
|
-
access_key_id (str): The AWS access key ID.
|
|
393
|
-
secret_access_key (str): The AWS secret access key.
|
|
394
|
-
account (str): The AWS account ID.
|
|
395
|
-
region (str): The AWS region.
|
|
396
|
-
|
|
397
|
-
Returns:
|
|
398
|
-
str: A base64-encoded string representation of the repository JSON configuration.
|
|
399
|
-
"""
|
|
400
|
-
return IntegrationUtils.generate_ecr_options(
|
|
401
|
-
access_key_id=access_key_id,
|
|
402
|
-
secret_access_key=secret_access_key,
|
|
403
|
-
account=account,
|
|
404
|
-
region=region
|
|
405
|
-
)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
class IntegrationUtils:
|
|
409
|
-
|
|
410
|
-
@staticmethod
|
|
411
|
-
def encode(st: str):
|
|
412
|
-
return str(base64.b64encode(bytes(st, 'utf-8')))[2:-1]
|
|
413
|
-
|
|
414
|
-
@staticmethod
|
|
415
|
-
def generate_json_key_options(location: str, username: str, password: str, auth: str, email: str = None):
|
|
416
|
-
encoded_pass = {
|
|
417
|
-
"auths": {
|
|
418
|
-
f"{location}": {
|
|
419
|
-
"username": username,
|
|
420
|
-
"password": password,
|
|
421
|
-
"auth": auth
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if email:
|
|
427
|
-
encoded_pass['auths'][f'{location}']['email'] = email
|
|
428
|
-
|
|
429
|
-
return {
|
|
430
|
-
"name": "_json_key",
|
|
431
|
-
"spec": {
|
|
432
|
-
"password": IntegrationUtils.encode(json.dumps(encoded_pass))
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
@staticmethod
|
|
437
|
-
def generate_gar_options(service_account: str, location: str, email: str = None) -> dict:
|
|
438
|
-
|
|
439
|
-
if not service_account:
|
|
440
|
-
raise ValueError('Missing Service Account')
|
|
441
|
-
if not location:
|
|
442
|
-
raise ValueError('Missing Location')
|
|
443
|
-
|
|
444
|
-
username = "_json_key"
|
|
445
|
-
cred = f"{username}:{service_account}"
|
|
446
|
-
auth = IntegrationUtils.encode(cred)
|
|
447
|
-
|
|
448
|
-
return IntegrationUtils.generate_json_key_options(
|
|
449
|
-
location=location,
|
|
450
|
-
username=username,
|
|
451
|
-
password=service_account,
|
|
452
|
-
auth=auth,
|
|
453
|
-
email=email
|
|
454
|
-
)
|
|
455
|
-
|
|
456
|
-
@staticmethod
|
|
457
|
-
def generate_docker_hub_options(username: str, password: str, email: str = None, location='docker.io') -> dict:
|
|
458
|
-
|
|
459
|
-
if not username:
|
|
460
|
-
raise ValueError('Missing Username')
|
|
461
|
-
if not password:
|
|
462
|
-
raise ValueError('Missing Password')
|
|
463
|
-
|
|
464
|
-
auth = IntegrationUtils.encode('{}:{}'.format(username, password))
|
|
465
|
-
|
|
466
|
-
return IntegrationUtils.generate_json_key_options(
|
|
467
|
-
location=location,
|
|
468
|
-
username=username,
|
|
469
|
-
password=password,
|
|
470
|
-
auth=auth,
|
|
471
|
-
email=email
|
|
472
|
-
)
|
|
473
|
-
|
|
474
|
-
@staticmethod
|
|
475
|
-
def generate_ecr_options(access_key_id: str, secret_access_key: str, account: str, region: str) -> dict:
|
|
476
|
-
return {
|
|
477
|
-
"name": "AWS",
|
|
478
|
-
"spec": {
|
|
479
|
-
"accessKeyId": access_key_id,
|
|
480
|
-
"secretAccessKey": secret_access_key,
|
|
481
|
-
"account": account,
|
|
482
|
-
"region": region,
|
|
483
|
-
}
|
|
484
|
-
}
|
|
1
|
+
"""
|
|
2
|
+
Integrations Repository
|
|
3
|
+
"""
|
|
4
|
+
import base64
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from .. import entities, exceptions, miscellaneous, _api_reference
|
|
8
|
+
from ..services.api_client import ApiClient
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(name='dtlpy')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Integrations:
|
|
14
|
+
"""
|
|
15
|
+
Integrations Repository
|
|
16
|
+
|
|
17
|
+
The Integrations class allows you to manage data integrations from your external storage (e.g., S3, GCS, Azure)
|
|
18
|
+
into your Dataloop's Dataset storage, as well as sync data in your Dataloop's Datasets with data in your external
|
|
19
|
+
storage.
|
|
20
|
+
|
|
21
|
+
For more information on Organization Storage Integration see the `Dataloop documentation <https://dataloop.ai/docs/organization-integrations>`_ and `developers' docs <https://developers.dataloop.ai/tutorials/data_management/>`_.
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, client_api: ApiClient, org: entities.Organization = None,
|
|
26
|
+
project: entities.Project = None):
|
|
27
|
+
self._client_api = client_api
|
|
28
|
+
self._org = org
|
|
29
|
+
self._project = project
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def project(self) -> entities.Project:
|
|
33
|
+
return self._project
|
|
34
|
+
|
|
35
|
+
@project.setter
|
|
36
|
+
def project(self, project: entities.Project):
|
|
37
|
+
if not isinstance(project, entities.Project):
|
|
38
|
+
raise ValueError('Must input a valid Project entity')
|
|
39
|
+
self._project = project
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def org(self) -> entities.Organization:
|
|
43
|
+
if self._org is None:
|
|
44
|
+
if self.project is not None:
|
|
45
|
+
self._org = entities.Organization.from_json(_json=self.project.org, client_api=self._client_api)
|
|
46
|
+
return self._org
|
|
47
|
+
|
|
48
|
+
@org.setter
|
|
49
|
+
def org(self, org: entities.Organization):
|
|
50
|
+
if not isinstance(org, entities.Organization):
|
|
51
|
+
raise ValueError('Must input a valid Organization entity')
|
|
52
|
+
self._org = org
|
|
53
|
+
|
|
54
|
+
@_api_reference.add(path='/orgs/{orgId}/integrations/{integrationId}', method='delete')
|
|
55
|
+
def delete(self,
|
|
56
|
+
integrations_id: str,
|
|
57
|
+
sure: bool = False,
|
|
58
|
+
really: bool = False,
|
|
59
|
+
organization_id: str = None
|
|
60
|
+
) -> bool:
|
|
61
|
+
"""
|
|
62
|
+
Delete integrations from the organization.
|
|
63
|
+
|
|
64
|
+
**Prerequisites**: You must be an organization *owner* to delete an integration.
|
|
65
|
+
|
|
66
|
+
:param organization_id: organization id
|
|
67
|
+
:param str integrations_id: integrations id
|
|
68
|
+
:param bool sure: Are you sure you want to delete?
|
|
69
|
+
:param bool really: Really really sure?
|
|
70
|
+
:return: success
|
|
71
|
+
:rtype: bool
|
|
72
|
+
|
|
73
|
+
**Example**:
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
project.integrations.delete(integrations_id='integrations_id', sure=True, really=True)
|
|
78
|
+
"""
|
|
79
|
+
if sure and really:
|
|
80
|
+
if self.project is None and self.org is None and organization_id is None:
|
|
81
|
+
raise exceptions.PlatformException(
|
|
82
|
+
error='400',
|
|
83
|
+
message='Must provide an identifier in inputs')
|
|
84
|
+
|
|
85
|
+
if organization_id is None:
|
|
86
|
+
if self.project is not None:
|
|
87
|
+
organization_id = self.project.org.get('id')
|
|
88
|
+
else:
|
|
89
|
+
organization_id = self.org.id
|
|
90
|
+
|
|
91
|
+
url_path = '/orgs/{}/integrations/{}'.format(organization_id, integrations_id)
|
|
92
|
+
success, response = self._client_api.gen_request(req_type='delete',
|
|
93
|
+
path=url_path)
|
|
94
|
+
if not success:
|
|
95
|
+
raise exceptions.PlatformException(response)
|
|
96
|
+
else:
|
|
97
|
+
return True
|
|
98
|
+
else:
|
|
99
|
+
raise exceptions.PlatformException(
|
|
100
|
+
error='403',
|
|
101
|
+
message='Cant delete integrations from SDK. Please login to platform to delete')
|
|
102
|
+
|
|
103
|
+
@_api_reference.add(path='/orgs/{orgId}/integrations', method='post')
|
|
104
|
+
def create(self,
|
|
105
|
+
integrations_type: entities.IntegrationType,
|
|
106
|
+
name: str,
|
|
107
|
+
options: dict,
|
|
108
|
+
metadata: dict = None,
|
|
109
|
+
organization_id: str = None,
|
|
110
|
+
):
|
|
111
|
+
"""
|
|
112
|
+
Create an integration between an external storage and the organization.
|
|
113
|
+
|
|
114
|
+
**Examples for options include**:
|
|
115
|
+
s3 - {key: "", secret: ""};
|
|
116
|
+
gcs - {key: "", secret: "", content: ""};
|
|
117
|
+
azureblob - {key: "", secret: "", clientId: "", tenantId: ""};
|
|
118
|
+
key_value - {key: "", value: ""}
|
|
119
|
+
aws-sts - {key: "", secret: "", roleArns: ""}
|
|
120
|
+
aws-cross - {}
|
|
121
|
+
gcp-cross - {}
|
|
122
|
+
gcp-workload-identity-federation - {"secret": "", "content": "{}", "clientId": ""}
|
|
123
|
+
private-registry (ECR) - can use generate_ecr_options to generate the options
|
|
124
|
+
private-registry (GAR) - use generate_gar_options to generate the options
|
|
125
|
+
private-registry (ACR) - use generate_azure_container_registry_options to generate the options
|
|
126
|
+
private-registry (DockerHub) - use generate_docker_hub_options to generate the options
|
|
127
|
+
|
|
128
|
+
**Prerequisites**: You must be an *owner* in the organization.
|
|
129
|
+
|
|
130
|
+
:param IntegrationType integrations_type: integrations type dl.IntegrationType
|
|
131
|
+
:param str name: integrations name
|
|
132
|
+
:param dict options: dict of storage secrets
|
|
133
|
+
:param dict metadata: metadata
|
|
134
|
+
:param str organization_id: organization id
|
|
135
|
+
:return: success
|
|
136
|
+
:rtype: bool
|
|
137
|
+
|
|
138
|
+
**Example**:
|
|
139
|
+
|
|
140
|
+
.. code-block:: python
|
|
141
|
+
|
|
142
|
+
project.integrations.create(integrations_type=dl.IntegrationType.S3,
|
|
143
|
+
name='S3Integration',
|
|
144
|
+
options={key: "Access key ID", secret: "Secret access key"})
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
if self.project is None and self.org is None and organization_id is None:
|
|
148
|
+
raise exceptions.PlatformException(
|
|
149
|
+
error='400',
|
|
150
|
+
message='Must have an organization or project')
|
|
151
|
+
|
|
152
|
+
if organization_id is None:
|
|
153
|
+
if self.project is not None:
|
|
154
|
+
organization_id = self.project.org.get('id')
|
|
155
|
+
else:
|
|
156
|
+
organization_id = self.org.id
|
|
157
|
+
|
|
158
|
+
url_path = '/orgs/{}/integrations'.format(organization_id)
|
|
159
|
+
payload = {"type": integrations_type.value if isinstance(integrations_type,
|
|
160
|
+
entities.IntegrationType) else integrations_type,
|
|
161
|
+
'name': name, 'options': options}
|
|
162
|
+
if metadata is not None:
|
|
163
|
+
payload['metadata'] = metadata
|
|
164
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
165
|
+
path=url_path,
|
|
166
|
+
json_req=payload)
|
|
167
|
+
if not success:
|
|
168
|
+
raise exceptions.PlatformException(response)
|
|
169
|
+
else:
|
|
170
|
+
integration = entities.Integration.from_json(_json=response.json(), client_api=self._client_api)
|
|
171
|
+
if integration.metadata and isinstance(integration.metadata, list) and len(integration.metadata) > 0:
|
|
172
|
+
for m in integration.metadata:
|
|
173
|
+
if m['name'] == 'status':
|
|
174
|
+
integration_status = m['value']
|
|
175
|
+
logger.info('Integration status: {}'.format(integration_status))
|
|
176
|
+
return integration
|
|
177
|
+
|
|
178
|
+
@_api_reference.add(path='/orgs/{orgId}/integrations', method='patch')
|
|
179
|
+
def update(self,
|
|
180
|
+
new_name: str = None,
|
|
181
|
+
integrations_id: str = None,
|
|
182
|
+
integration: entities.Integration = None,
|
|
183
|
+
new_options: dict = None,
|
|
184
|
+
organization_id: str = None,
|
|
185
|
+
reload_services: bool = None,
|
|
186
|
+
):
|
|
187
|
+
"""
|
|
188
|
+
Update the integration's name.
|
|
189
|
+
|
|
190
|
+
**Prerequisites**: You must be an *owner* in the organization.
|
|
191
|
+
|
|
192
|
+
:param str new_name: new name
|
|
193
|
+
:param str integrations_id: integrations id
|
|
194
|
+
:param Integration integration: integration object
|
|
195
|
+
:param dict new_options: new value
|
|
196
|
+
:param str organization_id: organization id
|
|
197
|
+
:param bool reload_services: reload services associated with this integration
|
|
198
|
+
:return: Integration object
|
|
199
|
+
:rtype: dtlpy.entities.integration.Integration
|
|
200
|
+
|
|
201
|
+
**Examples for options include**:
|
|
202
|
+
s3 - {key: "", secret: ""};
|
|
203
|
+
gcs - {key: "", secret: "", content: ""};
|
|
204
|
+
azureblob - {key: "", secret: "", clientId: "", tenantId: ""};
|
|
205
|
+
key_value - {key: "", value: ""}
|
|
206
|
+
aws-sts - {key: "", secret: "", roleArns: ""}
|
|
207
|
+
aws-cross - {roleArn: ""}
|
|
208
|
+
gcp-cross - {"email: "", "resourceName": ""}
|
|
209
|
+
|
|
210
|
+
**Example**:
|
|
211
|
+
|
|
212
|
+
.. code-block:: python
|
|
213
|
+
|
|
214
|
+
project.integrations.update(integrations_id='integrations_id', new_options={roleArn: ""})
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
if self.project is None and self.org is None and organization_id is None:
|
|
218
|
+
raise exceptions.PlatformException(
|
|
219
|
+
error='400',
|
|
220
|
+
message='Must have an organization or project')
|
|
221
|
+
if integrations_id is None and integration is None:
|
|
222
|
+
raise exceptions.PlatformException(
|
|
223
|
+
error='400',
|
|
224
|
+
message='Must have an integrations_id or integration')
|
|
225
|
+
|
|
226
|
+
if organization_id is None:
|
|
227
|
+
if self.project is not None:
|
|
228
|
+
organization_id = self.project.org.get('id')
|
|
229
|
+
else:
|
|
230
|
+
organization_id = self.org.id
|
|
231
|
+
|
|
232
|
+
if reload_services is None:
|
|
233
|
+
logger.warning(
|
|
234
|
+
"Param reload_services was not provided. If the integration you are updating is used\n"
|
|
235
|
+
"in FaaS services these services will keep using the old value until updated."
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
url_path = '/orgs/{org_id}/integrations{query_params}'.format(
|
|
239
|
+
org_id=organization_id,
|
|
240
|
+
query_params='?reloadServices=true' if reload_services else ''
|
|
241
|
+
)
|
|
242
|
+
payload = dict(integrationId=integrations_id if integrations_id is not None else integration.id)
|
|
243
|
+
if new_name is not None:
|
|
244
|
+
payload['name'] = new_name
|
|
245
|
+
if new_options is not None:
|
|
246
|
+
if integration is None:
|
|
247
|
+
integration = self.get(integrations_id=integrations_id)
|
|
248
|
+
payload['credentials'] = dict(options=new_options, type=integration.type)
|
|
249
|
+
|
|
250
|
+
success, response = self._client_api.gen_request(req_type='patch',
|
|
251
|
+
path=url_path,
|
|
252
|
+
json_req=payload)
|
|
253
|
+
if not success:
|
|
254
|
+
raise exceptions.PlatformException(response)
|
|
255
|
+
|
|
256
|
+
return entities.Integration.from_json(_json=response.json(), client_api=self._client_api)
|
|
257
|
+
|
|
258
|
+
@_api_reference.add(path='/orgs/{orgId}/integrations/{integrationId}', method='get')
|
|
259
|
+
def get(self, integrations_id: str, organization_id: str = None):
|
|
260
|
+
"""
|
|
261
|
+
Get organization integrations. Use this method to access your integration and be able to use it in your code.
|
|
262
|
+
|
|
263
|
+
**Prerequisites**: You must be an *owner* in the organization.
|
|
264
|
+
|
|
265
|
+
:param str integrations_id: integrations id
|
|
266
|
+
:param str organization_id: organization id
|
|
267
|
+
:return: Integration object
|
|
268
|
+
:rtype: dtlpy.entities.integration.Integration
|
|
269
|
+
|
|
270
|
+
**Example**:
|
|
271
|
+
|
|
272
|
+
.. code-block:: python
|
|
273
|
+
|
|
274
|
+
project.integrations.get(integrations_id='integrations_id')
|
|
275
|
+
"""
|
|
276
|
+
if self.project is None and self.org is None and organization_id is None:
|
|
277
|
+
raise exceptions.PlatformException(
|
|
278
|
+
error='400',
|
|
279
|
+
message='Must have an organization or project')
|
|
280
|
+
|
|
281
|
+
if organization_id is None:
|
|
282
|
+
if self.project is not None:
|
|
283
|
+
organization_id = self.project.org.get('id')
|
|
284
|
+
else:
|
|
285
|
+
organization_id = self.org.id
|
|
286
|
+
|
|
287
|
+
url_path = '/orgs/{}/integrations/{}'.format(organization_id, integrations_id)
|
|
288
|
+
|
|
289
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
290
|
+
path=url_path)
|
|
291
|
+
if not success:
|
|
292
|
+
raise exceptions.PlatformException(response)
|
|
293
|
+
return entities.Integration.from_json(_json=response.json(), client_api=self._client_api)
|
|
294
|
+
|
|
295
|
+
@_api_reference.add(path='/orgs/{orgId}/integrations', method='get')
|
|
296
|
+
def list(self, only_available=False, organization_id: str = None):
|
|
297
|
+
"""
|
|
298
|
+
List all the organization's integrations with external storage.
|
|
299
|
+
|
|
300
|
+
**Prerequisites**: You must be an *owner* in the organization.
|
|
301
|
+
|
|
302
|
+
:param bool only_available: if True list only the available integrations.
|
|
303
|
+
:param str organization_id: organization id
|
|
304
|
+
:return: groups list
|
|
305
|
+
:rtype: list
|
|
306
|
+
|
|
307
|
+
**Example**:
|
|
308
|
+
|
|
309
|
+
.. code-block:: python
|
|
310
|
+
|
|
311
|
+
project.integrations.list(only_available=True)
|
|
312
|
+
"""
|
|
313
|
+
if self.project is None and self.org is None and organization_id is None:
|
|
314
|
+
raise exceptions.PlatformException(
|
|
315
|
+
error='400',
|
|
316
|
+
message='Must have an organization or project')
|
|
317
|
+
|
|
318
|
+
if organization_id is None:
|
|
319
|
+
if self.project is not None:
|
|
320
|
+
organization_id = self.project.org.get('id')
|
|
321
|
+
else:
|
|
322
|
+
organization_id = self.org.id
|
|
323
|
+
|
|
324
|
+
if only_available:
|
|
325
|
+
url_path = '/orgs/{}/availableIntegrations'.format(organization_id)
|
|
326
|
+
else:
|
|
327
|
+
url_path = '/orgs/{}/integrations'.format(organization_id)
|
|
328
|
+
|
|
329
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
330
|
+
path=url_path)
|
|
331
|
+
if not success:
|
|
332
|
+
raise exceptions.PlatformException(response)
|
|
333
|
+
|
|
334
|
+
available_integrations = miscellaneous.List(response.json())
|
|
335
|
+
return available_integrations
|
|
336
|
+
|
|
337
|
+
@staticmethod
|
|
338
|
+
def generate_gar_options(service_account: str, location: str, email: str = None) -> dict:
|
|
339
|
+
"""
|
|
340
|
+
Generates a Google Artifact Registry JSON configuration and returns it as a base64-encoded string.
|
|
341
|
+
|
|
342
|
+
Parameters:
|
|
343
|
+
location (str): The region where the repository will be created (e.g., 'us-central1').
|
|
344
|
+
service_account (str): The service_account parameter represents the Google Cloud service account credentials
|
|
345
|
+
in the form of a JSON key file. This JSON contains the private key and other metadata
|
|
346
|
+
required for authenticating with Google Artifact Registry. It is used to generate a Kubernetes secret
|
|
347
|
+
that stores the credentials for pulling container images from the registry.
|
|
348
|
+
The JSON key must include fields such as client_email, private_key, and project_id,
|
|
349
|
+
and it is typically downloaded from the Google Cloud Console when creating the service account
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
str: A base64-encoded string representation of the repository JSON configuration.
|
|
353
|
+
"""
|
|
354
|
+
return IntegrationUtils.generate_gar_options(service_account=service_account, location=location, email=email)
|
|
355
|
+
|
|
356
|
+
@staticmethod
|
|
357
|
+
def generate_docker_hub_options(username: str, password: str, email: str = None) -> dict:
|
|
358
|
+
"""
|
|
359
|
+
Generates a Docker Hub JSON configuration and returns it as a base64-encoded string.
|
|
360
|
+
|
|
361
|
+
Parameters:
|
|
362
|
+
username (str): The Docker Hub username.
|
|
363
|
+
password (str): The Docker Hub password.
|
|
364
|
+
email (str): Optional - Docker Hub email.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
str: A base64-encoded string representation of the repository JSON configuration.
|
|
368
|
+
"""
|
|
369
|
+
return IntegrationUtils.generate_docker_hub_options(username=username, password=password, email=email)
|
|
370
|
+
|
|
371
|
+
@staticmethod
|
|
372
|
+
def generate_azure_container_registry_options(username: str, password: str, location: str) -> dict:
|
|
373
|
+
"""
|
|
374
|
+
Generates an Azure Container Registry JSON configuration and returns it as a base64-encoded string.
|
|
375
|
+
|
|
376
|
+
Parameters:
|
|
377
|
+
username (str): The Azure username.
|
|
378
|
+
password (str): The Azure password.
|
|
379
|
+
location (str): server URL of Azure Container Registry
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
str: A base64-encoded string representation of the repository JSON configuration.
|
|
383
|
+
"""
|
|
384
|
+
return IntegrationUtils.generate_docker_hub_options(username=username, password=password, location=location)
|
|
385
|
+
|
|
386
|
+
@staticmethod
|
|
387
|
+
def generate_ecr_options(access_key_id: str, secret_access_key: str, account: str, region: str) -> dict:
|
|
388
|
+
"""
|
|
389
|
+
Generates an Amazon Elastic Container Registry (ECR) JSON configuration and returns it as a base64-encoded string.
|
|
390
|
+
|
|
391
|
+
Parameters:
|
|
392
|
+
access_key_id (str): The AWS access key ID.
|
|
393
|
+
secret_access_key (str): The AWS secret access key.
|
|
394
|
+
account (str): The AWS account ID.
|
|
395
|
+
region (str): The AWS region.
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
str: A base64-encoded string representation of the repository JSON configuration.
|
|
399
|
+
"""
|
|
400
|
+
return IntegrationUtils.generate_ecr_options(
|
|
401
|
+
access_key_id=access_key_id,
|
|
402
|
+
secret_access_key=secret_access_key,
|
|
403
|
+
account=account,
|
|
404
|
+
region=region
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class IntegrationUtils:
|
|
409
|
+
|
|
410
|
+
@staticmethod
|
|
411
|
+
def encode(st: str):
|
|
412
|
+
return str(base64.b64encode(bytes(st, 'utf-8')))[2:-1]
|
|
413
|
+
|
|
414
|
+
@staticmethod
|
|
415
|
+
def generate_json_key_options(location: str, username: str, password: str, auth: str, email: str = None):
|
|
416
|
+
encoded_pass = {
|
|
417
|
+
"auths": {
|
|
418
|
+
f"{location}": {
|
|
419
|
+
"username": username,
|
|
420
|
+
"password": password,
|
|
421
|
+
"auth": auth
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if email:
|
|
427
|
+
encoded_pass['auths'][f'{location}']['email'] = email
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
"name": "_json_key",
|
|
431
|
+
"spec": {
|
|
432
|
+
"password": IntegrationUtils.encode(json.dumps(encoded_pass))
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
@staticmethod
|
|
437
|
+
def generate_gar_options(service_account: str, location: str, email: str = None) -> dict:
|
|
438
|
+
|
|
439
|
+
if not service_account:
|
|
440
|
+
raise ValueError('Missing Service Account')
|
|
441
|
+
if not location:
|
|
442
|
+
raise ValueError('Missing Location')
|
|
443
|
+
|
|
444
|
+
username = "_json_key"
|
|
445
|
+
cred = f"{username}:{service_account}"
|
|
446
|
+
auth = IntegrationUtils.encode(cred)
|
|
447
|
+
|
|
448
|
+
return IntegrationUtils.generate_json_key_options(
|
|
449
|
+
location=location,
|
|
450
|
+
username=username,
|
|
451
|
+
password=service_account,
|
|
452
|
+
auth=auth,
|
|
453
|
+
email=email
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
@staticmethod
|
|
457
|
+
def generate_docker_hub_options(username: str, password: str, email: str = None, location='docker.io') -> dict:
|
|
458
|
+
|
|
459
|
+
if not username:
|
|
460
|
+
raise ValueError('Missing Username')
|
|
461
|
+
if not password:
|
|
462
|
+
raise ValueError('Missing Password')
|
|
463
|
+
|
|
464
|
+
auth = IntegrationUtils.encode('{}:{}'.format(username, password))
|
|
465
|
+
|
|
466
|
+
return IntegrationUtils.generate_json_key_options(
|
|
467
|
+
location=location,
|
|
468
|
+
username=username,
|
|
469
|
+
password=password,
|
|
470
|
+
auth=auth,
|
|
471
|
+
email=email
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
@staticmethod
|
|
475
|
+
def generate_ecr_options(access_key_id: str, secret_access_key: str, account: str, region: str) -> dict:
|
|
476
|
+
return {
|
|
477
|
+
"name": "AWS",
|
|
478
|
+
"spec": {
|
|
479
|
+
"accessKeyId": access_key_id,
|
|
480
|
+
"secretAccessKey": secret_access_key,
|
|
481
|
+
"account": account,
|
|
482
|
+
"region": region,
|
|
483
|
+
}
|
|
484
|
+
}
|