dtlpy 1.115.44__py3-none-any.whl → 1.117.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.
Files changed (238) hide show
  1. dtlpy/__init__.py +491 -491
  2. dtlpy/__version__.py +1 -1
  3. dtlpy/assets/__init__.py +26 -26
  4. dtlpy/assets/code_server/config.yaml +2 -2
  5. dtlpy/assets/code_server/installation.sh +24 -24
  6. dtlpy/assets/code_server/launch.json +13 -13
  7. dtlpy/assets/code_server/settings.json +2 -2
  8. dtlpy/assets/main.py +53 -53
  9. dtlpy/assets/main_partial.py +18 -18
  10. dtlpy/assets/mock.json +11 -11
  11. dtlpy/assets/model_adapter.py +83 -83
  12. dtlpy/assets/package.json +61 -61
  13. dtlpy/assets/package_catalog.json +29 -29
  14. dtlpy/assets/package_gitignore +307 -307
  15. dtlpy/assets/service_runners/__init__.py +33 -33
  16. dtlpy/assets/service_runners/converter.py +96 -96
  17. dtlpy/assets/service_runners/multi_method.py +49 -49
  18. dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
  19. dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
  20. dtlpy/assets/service_runners/multi_method_item.py +52 -52
  21. dtlpy/assets/service_runners/multi_method_json.py +52 -52
  22. dtlpy/assets/service_runners/single_method.py +37 -37
  23. dtlpy/assets/service_runners/single_method_annotation.py +43 -43
  24. dtlpy/assets/service_runners/single_method_dataset.py +43 -43
  25. dtlpy/assets/service_runners/single_method_item.py +41 -41
  26. dtlpy/assets/service_runners/single_method_json.py +42 -42
  27. dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
  28. dtlpy/assets/voc_annotation_template.xml +23 -23
  29. dtlpy/caches/base_cache.py +32 -32
  30. dtlpy/caches/cache.py +473 -473
  31. dtlpy/caches/dl_cache.py +201 -201
  32. dtlpy/caches/filesystem_cache.py +89 -89
  33. dtlpy/caches/redis_cache.py +84 -84
  34. dtlpy/dlp/__init__.py +20 -20
  35. dtlpy/dlp/cli_utilities.py +367 -367
  36. dtlpy/dlp/command_executor.py +764 -764
  37. dtlpy/dlp/dlp +1 -1
  38. dtlpy/dlp/dlp.bat +1 -1
  39. dtlpy/dlp/dlp.py +128 -128
  40. dtlpy/dlp/parser.py +651 -651
  41. dtlpy/entities/__init__.py +83 -83
  42. dtlpy/entities/analytic.py +347 -347
  43. dtlpy/entities/annotation.py +1879 -1879
  44. dtlpy/entities/annotation_collection.py +699 -699
  45. dtlpy/entities/annotation_definitions/__init__.py +20 -20
  46. dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
  47. dtlpy/entities/annotation_definitions/box.py +195 -195
  48. dtlpy/entities/annotation_definitions/classification.py +67 -67
  49. dtlpy/entities/annotation_definitions/comparison.py +72 -72
  50. dtlpy/entities/annotation_definitions/cube.py +204 -204
  51. dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
  52. dtlpy/entities/annotation_definitions/description.py +32 -32
  53. dtlpy/entities/annotation_definitions/ellipse.py +124 -124
  54. dtlpy/entities/annotation_definitions/free_text.py +62 -62
  55. dtlpy/entities/annotation_definitions/gis.py +69 -69
  56. dtlpy/entities/annotation_definitions/note.py +139 -139
  57. dtlpy/entities/annotation_definitions/point.py +117 -117
  58. dtlpy/entities/annotation_definitions/polygon.py +182 -182
  59. dtlpy/entities/annotation_definitions/polyline.py +111 -111
  60. dtlpy/entities/annotation_definitions/pose.py +92 -92
  61. dtlpy/entities/annotation_definitions/ref_image.py +86 -86
  62. dtlpy/entities/annotation_definitions/segmentation.py +240 -240
  63. dtlpy/entities/annotation_definitions/subtitle.py +34 -34
  64. dtlpy/entities/annotation_definitions/text.py +85 -85
  65. dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
  66. dtlpy/entities/app.py +220 -220
  67. dtlpy/entities/app_module.py +107 -107
  68. dtlpy/entities/artifact.py +174 -174
  69. dtlpy/entities/assignment.py +399 -399
  70. dtlpy/entities/base_entity.py +214 -214
  71. dtlpy/entities/bot.py +113 -113
  72. dtlpy/entities/codebase.py +292 -292
  73. dtlpy/entities/collection.py +38 -38
  74. dtlpy/entities/command.py +169 -169
  75. dtlpy/entities/compute.py +449 -449
  76. dtlpy/entities/dataset.py +1299 -1299
  77. dtlpy/entities/directory_tree.py +44 -44
  78. dtlpy/entities/dpk.py +470 -470
  79. dtlpy/entities/driver.py +235 -235
  80. dtlpy/entities/execution.py +397 -397
  81. dtlpy/entities/feature.py +124 -124
  82. dtlpy/entities/feature_set.py +152 -145
  83. dtlpy/entities/filters.py +798 -798
  84. dtlpy/entities/gis_item.py +107 -107
  85. dtlpy/entities/integration.py +184 -184
  86. dtlpy/entities/item.py +975 -959
  87. dtlpy/entities/label.py +123 -123
  88. dtlpy/entities/links.py +85 -85
  89. dtlpy/entities/message.py +175 -175
  90. dtlpy/entities/model.py +684 -684
  91. dtlpy/entities/node.py +1005 -1005
  92. dtlpy/entities/ontology.py +810 -803
  93. dtlpy/entities/organization.py +287 -287
  94. dtlpy/entities/package.py +657 -657
  95. dtlpy/entities/package_defaults.py +5 -5
  96. dtlpy/entities/package_function.py +185 -185
  97. dtlpy/entities/package_module.py +113 -113
  98. dtlpy/entities/package_slot.py +118 -118
  99. dtlpy/entities/paged_entities.py +299 -299
  100. dtlpy/entities/pipeline.py +624 -624
  101. dtlpy/entities/pipeline_execution.py +279 -279
  102. dtlpy/entities/project.py +394 -394
  103. dtlpy/entities/prompt_item.py +505 -505
  104. dtlpy/entities/recipe.py +301 -301
  105. dtlpy/entities/reflect_dict.py +102 -102
  106. dtlpy/entities/resource_execution.py +138 -138
  107. dtlpy/entities/service.py +974 -963
  108. dtlpy/entities/service_driver.py +117 -117
  109. dtlpy/entities/setting.py +294 -294
  110. dtlpy/entities/task.py +495 -495
  111. dtlpy/entities/time_series.py +143 -143
  112. dtlpy/entities/trigger.py +426 -426
  113. dtlpy/entities/user.py +118 -118
  114. dtlpy/entities/webhook.py +124 -124
  115. dtlpy/examples/__init__.py +19 -19
  116. dtlpy/examples/add_labels.py +135 -135
  117. dtlpy/examples/add_metadata_to_item.py +21 -21
  118. dtlpy/examples/annotate_items_using_model.py +65 -65
  119. dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
  120. dtlpy/examples/annotations_convert_to_voc.py +9 -9
  121. dtlpy/examples/annotations_convert_to_yolo.py +9 -9
  122. dtlpy/examples/convert_annotation_types.py +51 -51
  123. dtlpy/examples/converter.py +143 -143
  124. dtlpy/examples/copy_annotations.py +22 -22
  125. dtlpy/examples/copy_folder.py +31 -31
  126. dtlpy/examples/create_annotations.py +51 -51
  127. dtlpy/examples/create_video_annotations.py +83 -83
  128. dtlpy/examples/delete_annotations.py +26 -26
  129. dtlpy/examples/filters.py +113 -113
  130. dtlpy/examples/move_item.py +23 -23
  131. dtlpy/examples/play_video_annotation.py +13 -13
  132. dtlpy/examples/show_item_and_mask.py +53 -53
  133. dtlpy/examples/triggers.py +49 -49
  134. dtlpy/examples/upload_batch_of_items.py +20 -20
  135. dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
  136. dtlpy/examples/upload_items_with_modalities.py +43 -43
  137. dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
  138. dtlpy/examples/upload_yolo_format_annotations.py +70 -70
  139. dtlpy/exceptions.py +125 -125
  140. dtlpy/miscellaneous/__init__.py +20 -20
  141. dtlpy/miscellaneous/dict_differ.py +95 -95
  142. dtlpy/miscellaneous/git_utils.py +217 -217
  143. dtlpy/miscellaneous/json_utils.py +14 -14
  144. dtlpy/miscellaneous/list_print.py +105 -105
  145. dtlpy/miscellaneous/zipping.py +130 -130
  146. dtlpy/ml/__init__.py +20 -20
  147. dtlpy/ml/base_feature_extractor_adapter.py +27 -27
  148. dtlpy/ml/base_model_adapter.py +1287 -1230
  149. dtlpy/ml/metrics.py +461 -461
  150. dtlpy/ml/predictions_utils.py +274 -274
  151. dtlpy/ml/summary_writer.py +57 -57
  152. dtlpy/ml/train_utils.py +60 -60
  153. dtlpy/new_instance.py +252 -252
  154. dtlpy/repositories/__init__.py +56 -56
  155. dtlpy/repositories/analytics.py +85 -85
  156. dtlpy/repositories/annotations.py +916 -916
  157. dtlpy/repositories/apps.py +383 -383
  158. dtlpy/repositories/artifacts.py +452 -452
  159. dtlpy/repositories/assignments.py +599 -599
  160. dtlpy/repositories/bots.py +213 -213
  161. dtlpy/repositories/codebases.py +559 -559
  162. dtlpy/repositories/collections.py +332 -332
  163. dtlpy/repositories/commands.py +152 -152
  164. dtlpy/repositories/compositions.py +61 -61
  165. dtlpy/repositories/computes.py +439 -439
  166. dtlpy/repositories/datasets.py +1585 -1504
  167. dtlpy/repositories/downloader.py +1157 -923
  168. dtlpy/repositories/dpks.py +433 -433
  169. dtlpy/repositories/drivers.py +482 -482
  170. dtlpy/repositories/executions.py +815 -815
  171. dtlpy/repositories/feature_sets.py +256 -226
  172. dtlpy/repositories/features.py +255 -255
  173. dtlpy/repositories/integrations.py +484 -484
  174. dtlpy/repositories/items.py +912 -912
  175. dtlpy/repositories/messages.py +94 -94
  176. dtlpy/repositories/models.py +1000 -1000
  177. dtlpy/repositories/nodes.py +80 -80
  178. dtlpy/repositories/ontologies.py +511 -511
  179. dtlpy/repositories/organizations.py +525 -525
  180. dtlpy/repositories/packages.py +1941 -1941
  181. dtlpy/repositories/pipeline_executions.py +451 -451
  182. dtlpy/repositories/pipelines.py +640 -640
  183. dtlpy/repositories/projects.py +539 -539
  184. dtlpy/repositories/recipes.py +429 -399
  185. dtlpy/repositories/resource_executions.py +137 -137
  186. dtlpy/repositories/schema.py +120 -120
  187. dtlpy/repositories/service_drivers.py +213 -213
  188. dtlpy/repositories/services.py +1704 -1704
  189. dtlpy/repositories/settings.py +339 -339
  190. dtlpy/repositories/tasks.py +1477 -1477
  191. dtlpy/repositories/times_series.py +278 -278
  192. dtlpy/repositories/triggers.py +536 -536
  193. dtlpy/repositories/upload_element.py +257 -257
  194. dtlpy/repositories/uploader.py +661 -661
  195. dtlpy/repositories/webhooks.py +249 -249
  196. dtlpy/services/__init__.py +22 -22
  197. dtlpy/services/aihttp_retry.py +131 -131
  198. dtlpy/services/api_client.py +1786 -1785
  199. dtlpy/services/api_reference.py +40 -40
  200. dtlpy/services/async_utils.py +133 -133
  201. dtlpy/services/calls_counter.py +44 -44
  202. dtlpy/services/check_sdk.py +68 -68
  203. dtlpy/services/cookie.py +115 -115
  204. dtlpy/services/create_logger.py +156 -156
  205. dtlpy/services/events.py +84 -84
  206. dtlpy/services/logins.py +235 -235
  207. dtlpy/services/reporter.py +256 -256
  208. dtlpy/services/service_defaults.py +91 -91
  209. dtlpy/utilities/__init__.py +20 -20
  210. dtlpy/utilities/annotations/__init__.py +16 -16
  211. dtlpy/utilities/annotations/annotation_converters.py +269 -269
  212. dtlpy/utilities/base_package_runner.py +285 -264
  213. dtlpy/utilities/converter.py +1650 -1650
  214. dtlpy/utilities/dataset_generators/__init__.py +1 -1
  215. dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
  216. dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
  217. dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
  218. dtlpy/utilities/local_development/__init__.py +1 -1
  219. dtlpy/utilities/local_development/local_session.py +179 -179
  220. dtlpy/utilities/reports/__init__.py +2 -2
  221. dtlpy/utilities/reports/figures.py +343 -343
  222. dtlpy/utilities/reports/report.py +71 -71
  223. dtlpy/utilities/videos/__init__.py +17 -17
  224. dtlpy/utilities/videos/video_player.py +598 -598
  225. dtlpy/utilities/videos/videos.py +470 -470
  226. {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp +1 -1
  227. dtlpy-1.117.6.data/scripts/dlp.bat +2 -0
  228. {dtlpy-1.115.44.data → dtlpy-1.117.6.data}/scripts/dlp.py +128 -128
  229. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/METADATA +186 -186
  230. dtlpy-1.117.6.dist-info/RECORD +239 -0
  231. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/WHEEL +1 -1
  232. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/licenses/LICENSE +200 -200
  233. tests/features/environment.py +551 -551
  234. dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
  235. dtlpy-1.115.44.data/scripts/dlp.bat +0 -2
  236. dtlpy-1.115.44.dist-info/RECORD +0 -240
  237. {dtlpy-1.115.44.dist-info → dtlpy-1.117.6.dist-info}/entry_points.txt +0 -0
  238. {dtlpy-1.115.44.dist-info → dtlpy-1.117.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
+ }