digitalhub 0.13.0b3__py3-none-any.whl → 0.14.9__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.
- digitalhub/__init__.py +3 -8
- digitalhub/context/api.py +43 -6
- digitalhub/context/builder.py +1 -5
- digitalhub/context/context.py +28 -13
- digitalhub/entities/_base/_base/entity.py +0 -15
- digitalhub/entities/_base/context/entity.py +1 -4
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/entity/entity.py +0 -8
- digitalhub/entities/_base/executable/entity.py +195 -87
- digitalhub/entities/_base/material/entity.py +11 -23
- digitalhub/entities/_base/material/utils.py +28 -4
- digitalhub/entities/_base/runtime_entity/builder.py +53 -18
- digitalhub/entities/_base/unversioned/entity.py +1 -1
- digitalhub/entities/_base/versioned/entity.py +1 -1
- digitalhub/entities/_commons/enums.py +1 -31
- digitalhub/entities/_commons/metrics.py +64 -30
- digitalhub/entities/_commons/utils.py +119 -30
- digitalhub/entities/_constructors/_resources.py +151 -0
- digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +18 -0
- digitalhub/entities/_processors/base/crud.py +381 -0
- digitalhub/entities/_processors/base/import_export.py +118 -0
- digitalhub/entities/_processors/base/processor.py +299 -0
- digitalhub/entities/_processors/base/special_ops.py +104 -0
- digitalhub/entities/_processors/context/crud.py +652 -0
- digitalhub/entities/_processors/context/import_export.py +242 -0
- digitalhub/entities/_processors/context/material.py +123 -0
- digitalhub/entities/_processors/context/processor.py +400 -0
- digitalhub/entities/_processors/context/special_ops.py +476 -0
- digitalhub/entities/_processors/processors.py +12 -0
- digitalhub/entities/_processors/utils.py +38 -102
- digitalhub/entities/artifact/crud.py +58 -22
- digitalhub/entities/artifact/utils.py +28 -13
- digitalhub/entities/builders.py +2 -0
- digitalhub/entities/dataitem/crud.py +63 -20
- digitalhub/entities/dataitem/table/entity.py +27 -22
- digitalhub/entities/dataitem/utils.py +82 -32
- digitalhub/entities/function/_base/entity.py +3 -6
- digitalhub/entities/function/crud.py +55 -24
- digitalhub/entities/model/_base/entity.py +62 -20
- digitalhub/entities/model/crud.py +59 -23
- digitalhub/entities/model/mlflow/utils.py +29 -20
- digitalhub/entities/model/utils.py +28 -13
- digitalhub/entities/project/_base/builder.py +0 -6
- digitalhub/entities/project/_base/entity.py +337 -164
- digitalhub/entities/project/_base/spec.py +4 -4
- digitalhub/entities/project/crud.py +28 -71
- digitalhub/entities/project/utils.py +7 -3
- digitalhub/entities/run/_base/builder.py +0 -4
- digitalhub/entities/run/_base/entity.py +70 -63
- digitalhub/entities/run/crud.py +79 -26
- digitalhub/entities/secret/_base/entity.py +1 -5
- digitalhub/entities/secret/crud.py +31 -28
- digitalhub/entities/task/_base/builder.py +0 -4
- digitalhub/entities/task/_base/entity.py +5 -5
- digitalhub/entities/task/_base/models.py +13 -16
- digitalhub/entities/task/crud.py +61 -29
- digitalhub/entities/trigger/_base/entity.py +1 -5
- digitalhub/entities/trigger/crud.py +89 -30
- digitalhub/entities/workflow/_base/entity.py +3 -8
- digitalhub/entities/workflow/crud.py +55 -24
- digitalhub/factory/entity.py +283 -0
- digitalhub/factory/enums.py +18 -0
- digitalhub/factory/registry.py +197 -0
- digitalhub/factory/runtime.py +44 -0
- digitalhub/factory/utils.py +3 -54
- digitalhub/runtimes/_base.py +2 -2
- digitalhub/stores/client/{dhcore/api_builder.py → api_builder.py} +3 -3
- digitalhub/stores/client/builder.py +19 -31
- digitalhub/stores/client/client.py +322 -0
- digitalhub/stores/client/configurator.py +408 -0
- digitalhub/stores/client/enums.py +50 -0
- digitalhub/stores/client/{dhcore/error_parser.py → error_parser.py} +0 -4
- digitalhub/stores/client/header_manager.py +61 -0
- digitalhub/stores/client/http_handler.py +152 -0
- digitalhub/stores/client/{_base/key_builder.py → key_builder.py} +14 -14
- digitalhub/stores/client/params_builder.py +330 -0
- digitalhub/stores/client/response_processor.py +102 -0
- digitalhub/stores/client/utils.py +35 -0
- digitalhub/stores/{credentials → configurator}/api.py +5 -9
- digitalhub/stores/configurator/configurator.py +123 -0
- digitalhub/stores/{credentials → configurator}/enums.py +27 -10
- digitalhub/stores/configurator/handler.py +213 -0
- digitalhub/stores/{credentials → configurator}/ini_module.py +31 -22
- digitalhub/stores/data/_base/store.py +0 -20
- digitalhub/stores/data/api.py +5 -7
- digitalhub/stores/data/builder.py +53 -27
- digitalhub/stores/data/local/store.py +0 -103
- digitalhub/stores/data/remote/store.py +0 -4
- digitalhub/stores/data/s3/configurator.py +39 -77
- digitalhub/stores/data/s3/store.py +57 -37
- digitalhub/stores/data/sql/configurator.py +66 -46
- digitalhub/stores/data/sql/store.py +171 -104
- digitalhub/stores/readers/data/factory.py +0 -8
- digitalhub/stores/readers/data/pandas/reader.py +9 -19
- digitalhub/utils/file_utils.py +0 -17
- digitalhub/utils/generic_utils.py +1 -14
- digitalhub/utils/git_utils.py +0 -8
- digitalhub/utils/io_utils.py +0 -12
- digitalhub/utils/store_utils.py +44 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/METADATA +5 -4
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/RECORD +112 -113
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/WHEEL +1 -1
- digitalhub/entities/_commons/types.py +0 -9
- digitalhub/entities/_processors/base.py +0 -531
- digitalhub/entities/_processors/context.py +0 -1299
- digitalhub/entities/task/_base/utils.py +0 -22
- digitalhub/factory/factory.py +0 -381
- digitalhub/stores/client/_base/api_builder.py +0 -34
- digitalhub/stores/client/_base/client.py +0 -243
- digitalhub/stores/client/_base/params_builder.py +0 -34
- digitalhub/stores/client/api.py +0 -36
- digitalhub/stores/client/dhcore/client.py +0 -613
- digitalhub/stores/client/dhcore/configurator.py +0 -675
- digitalhub/stores/client/dhcore/enums.py +0 -34
- digitalhub/stores/client/dhcore/key_builder.py +0 -62
- digitalhub/stores/client/dhcore/models.py +0 -40
- digitalhub/stores/client/dhcore/params_builder.py +0 -278
- digitalhub/stores/client/dhcore/utils.py +0 -94
- digitalhub/stores/client/local/api_builder.py +0 -116
- digitalhub/stores/client/local/client.py +0 -573
- digitalhub/stores/client/local/enums.py +0 -15
- digitalhub/stores/client/local/key_builder.py +0 -62
- digitalhub/stores/client/local/params_builder.py +0 -120
- digitalhub/stores/credentials/__init__.py +0 -3
- digitalhub/stores/credentials/configurator.py +0 -210
- digitalhub/stores/credentials/handler.py +0 -176
- digitalhub/stores/credentials/store.py +0 -81
- digitalhub/stores/data/enums.py +0 -15
- digitalhub/stores/data/s3/utils.py +0 -78
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/__init__.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/metadata.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/spec.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/status.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/uuid.py +0 -0
- /digitalhub/{stores/client/_base → entities/_processors/base}/__init__.py +0 -0
- /digitalhub/{stores/client/dhcore → entities/_processors/context}/__init__.py +0 -0
- /digitalhub/stores/{client/local → configurator}/__init__.py +0 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,112 +4,74 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
from datetime import datetime, timezone
|
|
8
|
-
|
|
9
7
|
from botocore.config import Config
|
|
10
8
|
|
|
11
|
-
from digitalhub.stores.
|
|
12
|
-
from digitalhub.stores.
|
|
13
|
-
from digitalhub.stores.credentials.enums import CredsEnvVar
|
|
9
|
+
from digitalhub.stores.configurator.configurator import configurator
|
|
10
|
+
from digitalhub.stores.configurator.enums import ConfigurationVars, CredentialsVars
|
|
14
11
|
|
|
15
12
|
|
|
16
|
-
class S3StoreConfigurator
|
|
13
|
+
class S3StoreConfigurator:
|
|
17
14
|
"""
|
|
18
|
-
|
|
19
|
-
provided config or from environment.
|
|
15
|
+
Configurator class for S3 store configuration and credentials management.
|
|
20
16
|
"""
|
|
21
17
|
|
|
22
|
-
keys = [
|
|
23
|
-
CredsEnvVar.S3_ENDPOINT_URL.value,
|
|
24
|
-
CredsEnvVar.S3_ACCESS_KEY_ID.value,
|
|
25
|
-
CredsEnvVar.S3_SECRET_ACCESS_KEY.value,
|
|
26
|
-
CredsEnvVar.S3_REGION.value,
|
|
27
|
-
CredsEnvVar.S3_SIGNATURE_VERSION.value,
|
|
28
|
-
CredsEnvVar.S3_SESSION_TOKEN.value,
|
|
29
|
-
CredsEnvVar.S3_PATH_STYLE.value,
|
|
30
|
-
CredsEnvVar.S3_CREDENTIALS_EXPIRATION.value,
|
|
31
|
-
]
|
|
32
|
-
required_keys = [
|
|
33
|
-
CredsEnvVar.S3_ENDPOINT_URL.value,
|
|
34
|
-
CredsEnvVar.S3_ACCESS_KEY_ID.value,
|
|
35
|
-
CredsEnvVar.S3_SECRET_ACCESS_KEY.value,
|
|
36
|
-
]
|
|
37
|
-
|
|
38
18
|
def __init__(self):
|
|
39
|
-
|
|
40
|
-
self.load_configs()
|
|
19
|
+
self._validate()
|
|
41
20
|
|
|
42
21
|
##############################
|
|
43
22
|
# Configuration methods
|
|
44
23
|
##############################
|
|
45
24
|
|
|
46
|
-
def load_env_vars(self) -> None:
|
|
47
|
-
"""
|
|
48
|
-
Loads the credentials from the environment variables.
|
|
49
|
-
|
|
50
|
-
Returns
|
|
51
|
-
-------
|
|
52
|
-
None
|
|
53
|
-
"""
|
|
54
|
-
env_creds = self._creds_handler.load_from_env(self.keys)
|
|
55
|
-
self._creds_handler.set_credentials(self._env, env_creds)
|
|
56
|
-
|
|
57
|
-
def load_file_vars(self) -> None:
|
|
58
|
-
"""
|
|
59
|
-
Loads the credentials from a file.
|
|
60
|
-
|
|
61
|
-
Returns
|
|
62
|
-
-------
|
|
63
|
-
None
|
|
64
|
-
"""
|
|
65
|
-
file_creds = self._creds_handler.load_from_file(self.keys)
|
|
66
|
-
self._creds_handler.set_credentials(self._file, file_creds)
|
|
67
|
-
|
|
68
25
|
def get_client_config(self) -> dict:
|
|
69
26
|
"""
|
|
70
27
|
Gets S3 credentials (access key, secret key, session token, and other config).
|
|
71
28
|
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
creds : dict
|
|
32
|
+
The credentials dictionary.
|
|
33
|
+
|
|
72
34
|
Returns
|
|
73
35
|
-------
|
|
74
36
|
dict
|
|
75
|
-
|
|
37
|
+
A dictionary containing the S3 credentials.
|
|
76
38
|
"""
|
|
77
|
-
creds =
|
|
78
|
-
expired = creds[CredsEnvVar.S3_CREDENTIALS_EXPIRATION.value]
|
|
79
|
-
if self._origin == self._file and self._is_expired(expired):
|
|
80
|
-
refresh_token()
|
|
81
|
-
self.load_file_vars()
|
|
82
|
-
creds = self.get_credentials(self._origin)
|
|
39
|
+
creds = configurator.get_config_creds()
|
|
83
40
|
return {
|
|
84
|
-
"endpoint_url": creds[
|
|
85
|
-
"aws_access_key_id": creds[
|
|
86
|
-
"aws_secret_access_key": creds[
|
|
87
|
-
"aws_session_token": creds[
|
|
41
|
+
"endpoint_url": creds[ConfigurationVars.S3_ENDPOINT_URL.value],
|
|
42
|
+
"aws_access_key_id": creds[CredentialsVars.S3_ACCESS_KEY_ID.value],
|
|
43
|
+
"aws_secret_access_key": creds[CredentialsVars.S3_SECRET_ACCESS_KEY.value],
|
|
44
|
+
"aws_session_token": creds[CredentialsVars.S3_SESSION_TOKEN.value],
|
|
88
45
|
"config": Config(
|
|
89
|
-
region_name=creds[
|
|
90
|
-
signature_version=creds[
|
|
46
|
+
region_name=creds[ConfigurationVars.S3_REGION.value],
|
|
47
|
+
signature_version=creds[ConfigurationVars.S3_SIGNATURE_VERSION.value],
|
|
91
48
|
),
|
|
92
49
|
}
|
|
93
50
|
|
|
94
|
-
|
|
95
|
-
def _is_expired(timestamp: str | None) -> bool:
|
|
51
|
+
def _validate(self) -> None:
|
|
96
52
|
"""
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
53
|
+
Validate if all required keys are present in the configuration.
|
|
54
|
+
"""
|
|
55
|
+
required_keys = [
|
|
56
|
+
ConfigurationVars.S3_ENDPOINT_URL.value,
|
|
57
|
+
CredentialsVars.S3_ACCESS_KEY_ID.value,
|
|
58
|
+
CredentialsVars.S3_SECRET_ACCESS_KEY.value,
|
|
59
|
+
]
|
|
60
|
+
current_keys = configurator.get_config_creds()
|
|
61
|
+
missing_keys = []
|
|
62
|
+
for key in required_keys:
|
|
63
|
+
if key not in current_keys or current_keys[key] is None:
|
|
64
|
+
missing_keys.append(key)
|
|
65
|
+
if missing_keys:
|
|
66
|
+
raise ValueError(f"Missing required variables for S3 store: {', '.join(missing_keys)}")
|
|
67
|
+
|
|
68
|
+
def eval_retry(self) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Evaluate the status of retry lifecycle.
|
|
103
71
|
|
|
104
72
|
Returns
|
|
105
73
|
-------
|
|
106
74
|
bool
|
|
107
|
-
True if
|
|
108
|
-
otherwise False.
|
|
75
|
+
True if a retry action was performed, otherwise False.
|
|
109
76
|
"""
|
|
110
|
-
|
|
111
|
-
return False
|
|
112
|
-
dt = datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%SZ")
|
|
113
|
-
dt = dt.replace(tzinfo=timezone.utc)
|
|
114
|
-
now = datetime.now(timezone.utc) + datetime.timedelta(seconds=120)
|
|
115
|
-
return dt < now
|
|
77
|
+
return configurator.eval_retry()
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import typing
|
|
8
7
|
from io import BytesIO
|
|
9
8
|
from pathlib import Path
|
|
10
9
|
from typing import Any, Type
|
|
@@ -16,20 +15,17 @@ from boto3.s3.transfer import TransferConfig
|
|
|
16
15
|
from botocore.exceptions import ClientError, NoCredentialsError
|
|
17
16
|
|
|
18
17
|
from digitalhub.stores.data._base.store import Store
|
|
19
|
-
from digitalhub.stores.data.s3.
|
|
18
|
+
from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
|
|
20
19
|
from digitalhub.stores.readers.data.api import get_reader_by_object
|
|
21
20
|
from digitalhub.utils.exceptions import ConfigError, StoreError
|
|
22
21
|
from digitalhub.utils.file_utils import get_file_info_from_s3, get_file_mime_type
|
|
23
22
|
from digitalhub.utils.types import SourcesOrListOfSources
|
|
24
23
|
|
|
25
|
-
if typing.TYPE_CHECKING:
|
|
26
|
-
from digitalhub.stores.credentials.configurator import Configurator
|
|
27
|
-
from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
|
|
28
|
-
|
|
29
|
-
|
|
30
24
|
# Type aliases
|
|
31
25
|
S3Client = Type["botocore.client.S3"]
|
|
32
26
|
|
|
27
|
+
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
28
|
+
|
|
33
29
|
|
|
34
30
|
class S3Store(Store):
|
|
35
31
|
"""
|
|
@@ -37,9 +33,9 @@ class S3Store(Store):
|
|
|
37
33
|
artifacts on S3 based storage.
|
|
38
34
|
"""
|
|
39
35
|
|
|
40
|
-
def __init__(self
|
|
41
|
-
super().__init__(
|
|
42
|
-
self._configurator: S3StoreConfigurator
|
|
36
|
+
def __init__(self) -> None:
|
|
37
|
+
super().__init__()
|
|
38
|
+
self._configurator: S3StoreConfigurator = S3StoreConfigurator()
|
|
43
39
|
|
|
44
40
|
##############################
|
|
45
41
|
# I/O methods
|
|
@@ -332,10 +328,50 @@ class S3Store(Store):
|
|
|
332
328
|
str
|
|
333
329
|
The S3 path where the dataframe was saved.
|
|
334
330
|
"""
|
|
335
|
-
fileobj = BytesIO()
|
|
336
331
|
reader = get_reader_by_object(df)
|
|
337
|
-
|
|
338
|
-
|
|
332
|
+
with BytesIO() as fileobj:
|
|
333
|
+
reader.write_df(df, fileobj, extension=extension, **kwargs)
|
|
334
|
+
fileobj.seek(0)
|
|
335
|
+
return self.upload_fileobject(fileobj, dst)
|
|
336
|
+
|
|
337
|
+
##############################
|
|
338
|
+
# Wrapper methods
|
|
339
|
+
##############################
|
|
340
|
+
|
|
341
|
+
def get_s3_source(self, src: str, filename: Path) -> None:
|
|
342
|
+
"""
|
|
343
|
+
Download a file from S3 and save it to a local file.
|
|
344
|
+
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
src : str
|
|
348
|
+
S3 path of the object to be downloaded (e.g., 's3://bucket
|
|
349
|
+
filename : Path
|
|
350
|
+
Local path where the downloaded object will be saved.
|
|
351
|
+
"""
|
|
352
|
+
client, bucket = self._check_factory(src)
|
|
353
|
+
key = self._get_key(src)
|
|
354
|
+
self._download_file(key, filename, client, bucket)
|
|
355
|
+
|
|
356
|
+
def get_s3_client(self, file: bool = True) -> S3Client:
|
|
357
|
+
"""
|
|
358
|
+
Get an S3 client object.
|
|
359
|
+
|
|
360
|
+
Parameters
|
|
361
|
+
----------
|
|
362
|
+
file : bool
|
|
363
|
+
Whether to use file-based credentials. Default is True.
|
|
364
|
+
|
|
365
|
+
Returns
|
|
366
|
+
-------
|
|
367
|
+
S3Client
|
|
368
|
+
Returns a client object that interacts with the S3 storage service.
|
|
369
|
+
"""
|
|
370
|
+
if file:
|
|
371
|
+
cfg = self._configurator.get_file_config()
|
|
372
|
+
else:
|
|
373
|
+
cfg = self._configurator.get_env_config()
|
|
374
|
+
return self._get_client(cfg)
|
|
339
375
|
|
|
340
376
|
##############################
|
|
341
377
|
# Private I/O methods
|
|
@@ -533,10 +569,6 @@ class S3Store(Store):
|
|
|
533
569
|
The S3 client object.
|
|
534
570
|
bucket : str
|
|
535
571
|
The name of the S3 bucket.
|
|
536
|
-
|
|
537
|
-
Returns
|
|
538
|
-
-------
|
|
539
|
-
None
|
|
540
572
|
"""
|
|
541
573
|
extra_args = {}
|
|
542
574
|
mime_type = get_file_mime_type(src)
|
|
@@ -547,7 +579,7 @@ class S3Store(Store):
|
|
|
547
579
|
Bucket=bucket,
|
|
548
580
|
Key=key,
|
|
549
581
|
ExtraArgs=extra_args,
|
|
550
|
-
Config=TransferConfig(multipart_threshold=
|
|
582
|
+
Config=TransferConfig(multipart_threshold=MULTIPART_THRESHOLD),
|
|
551
583
|
)
|
|
552
584
|
|
|
553
585
|
@staticmethod
|
|
@@ -570,16 +602,12 @@ class S3Store(Store):
|
|
|
570
602
|
The S3 client object.
|
|
571
603
|
bucket : str
|
|
572
604
|
The name of the S3 bucket.
|
|
573
|
-
|
|
574
|
-
Returns
|
|
575
|
-
-------
|
|
576
|
-
None
|
|
577
605
|
"""
|
|
578
606
|
client.upload_fileobj(
|
|
579
607
|
Fileobj=fileobj,
|
|
580
608
|
Bucket=bucket,
|
|
581
609
|
Key=key,
|
|
582
|
-
Config=TransferConfig(multipart_threshold=
|
|
610
|
+
Config=TransferConfig(multipart_threshold=MULTIPART_THRESHOLD),
|
|
583
611
|
)
|
|
584
612
|
|
|
585
613
|
##############################
|
|
@@ -595,7 +623,7 @@ class S3Store(Store):
|
|
|
595
623
|
str
|
|
596
624
|
The name of the S3 bucket.
|
|
597
625
|
"""
|
|
598
|
-
return
|
|
626
|
+
return urlparse(root).netloc
|
|
599
627
|
|
|
600
628
|
def _get_client(self, cfg: dict) -> S3Client:
|
|
601
629
|
"""
|
|
@@ -613,7 +641,7 @@ class S3Store(Store):
|
|
|
613
641
|
"""
|
|
614
642
|
return boto3.client("s3", **cfg)
|
|
615
643
|
|
|
616
|
-
def _check_factory(self, s3_path: str
|
|
644
|
+
def _check_factory(self, s3_path: str) -> tuple[S3Client, str]:
|
|
617
645
|
"""
|
|
618
646
|
Checks if the S3 bucket collected from the URI is accessible.
|
|
619
647
|
|
|
@@ -621,29 +649,21 @@ class S3Store(Store):
|
|
|
621
649
|
----------
|
|
622
650
|
s3_path : str
|
|
623
651
|
Path to the S3 bucket (e.g., 's3://bucket/path').
|
|
624
|
-
retry : bool, optional
|
|
625
|
-
Whether to retry the operation if a ConfigError is raised. Default is True.
|
|
626
652
|
|
|
627
653
|
Returns
|
|
628
654
|
-------
|
|
629
655
|
tuple of S3Client and str
|
|
630
656
|
Tuple containing the S3 client object and the name of the S3 bucket.
|
|
631
|
-
|
|
632
|
-
Raises
|
|
633
|
-
------
|
|
634
|
-
ConfigError
|
|
635
|
-
If access to the specified bucket is not available and retry is False.
|
|
636
657
|
"""
|
|
637
658
|
bucket = self._get_bucket(s3_path)
|
|
659
|
+
cfg = self._configurator.get_client_config()
|
|
660
|
+
client = self._get_client(cfg)
|
|
638
661
|
try:
|
|
639
|
-
cfg = self._configurator.get_client_config()
|
|
640
|
-
client = self._get_client(cfg)
|
|
641
662
|
self._check_access_to_storage(client, bucket)
|
|
642
663
|
return client, bucket
|
|
643
664
|
except ConfigError as e:
|
|
644
|
-
if
|
|
645
|
-
self.
|
|
646
|
-
return self._check_factory(s3_path, False)
|
|
665
|
+
if self._configurator.eval_retry():
|
|
666
|
+
return self._check_factory(s3_path)
|
|
647
667
|
raise e
|
|
648
668
|
|
|
649
669
|
def _check_access_to_storage(self, client: S3Client, bucket: str) -> None:
|
|
@@ -4,67 +4,87 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
from digitalhub.stores.
|
|
8
|
-
from digitalhub.stores.
|
|
7
|
+
from digitalhub.stores.configurator.configurator import configurator
|
|
8
|
+
from digitalhub.stores.configurator.enums import ConfigurationVars, CredentialsVars
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class SqlStoreConfigurator
|
|
11
|
+
class SqlStoreConfigurator:
|
|
12
12
|
"""
|
|
13
|
-
|
|
14
|
-
provided config or from environment.
|
|
13
|
+
Configurator class for SQL store configuration and credentials management.
|
|
15
14
|
"""
|
|
16
15
|
|
|
17
|
-
keys = [
|
|
18
|
-
CredsEnvVar.DB_USERNAME.value,
|
|
19
|
-
CredsEnvVar.DB_PASSWORD.value,
|
|
20
|
-
CredsEnvVar.DB_HOST.value,
|
|
21
|
-
CredsEnvVar.DB_PORT.value,
|
|
22
|
-
CredsEnvVar.DB_DATABASE.value,
|
|
23
|
-
CredsEnvVar.DB_PLATFORM.value,
|
|
24
|
-
]
|
|
25
|
-
required_keys = [
|
|
26
|
-
CredsEnvVar.DB_USERNAME.value,
|
|
27
|
-
CredsEnvVar.DB_PASSWORD.value,
|
|
28
|
-
CredsEnvVar.DB_HOST.value,
|
|
29
|
-
CredsEnvVar.DB_PORT.value,
|
|
30
|
-
CredsEnvVar.DB_DATABASE.value,
|
|
31
|
-
]
|
|
32
|
-
|
|
33
16
|
def __init__(self):
|
|
34
|
-
|
|
35
|
-
self.load_configs()
|
|
36
|
-
|
|
37
|
-
##############################
|
|
38
|
-
# Configuration methods
|
|
39
|
-
##############################
|
|
17
|
+
self._validate()
|
|
40
18
|
|
|
41
|
-
def
|
|
19
|
+
def get_sql_conn_string(self) -> str:
|
|
42
20
|
"""
|
|
43
|
-
|
|
21
|
+
Generate PostgreSQL connection string from stored credentials.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
str
|
|
26
|
+
A PostgreSQL connection string in the format:
|
|
27
|
+
'postgresql://username:password@host:port/database'
|
|
44
28
|
"""
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
creds = self.get_sql_credentials()
|
|
30
|
+
user = creds[CredentialsVars.DB_USERNAME.value]
|
|
31
|
+
password = creds[CredentialsVars.DB_PASSWORD.value]
|
|
32
|
+
host = creds[ConfigurationVars.DB_HOST.value]
|
|
33
|
+
port = creds[ConfigurationVars.DB_PORT.value]
|
|
34
|
+
database = creds[ConfigurationVars.DB_DATABASE.value]
|
|
35
|
+
return f"postgresql://{user}:{password}@{host}:{port}/{database}"
|
|
47
36
|
|
|
48
|
-
def
|
|
37
|
+
def get_sql_credentials(self) -> dict:
|
|
49
38
|
"""
|
|
50
|
-
|
|
39
|
+
Get all configured database credentials as a dictionary.
|
|
40
|
+
|
|
41
|
+
Retrieves all available database credentials from the configured
|
|
42
|
+
source and returns them as a dictionary with all credential keys
|
|
43
|
+
from self.keys mapped to their values.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
dict
|
|
48
|
+
Dictionary containing all credential key-value pairs from self.keys.
|
|
49
|
+
Keys correspond to database connection parameters such as
|
|
50
|
+
username, password, host, port, database, and platform.
|
|
51
51
|
"""
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
keys = [
|
|
53
|
+
CredentialsVars.DB_USERNAME.value,
|
|
54
|
+
CredentialsVars.DB_PASSWORD.value,
|
|
55
|
+
ConfigurationVars.DB_HOST.value,
|
|
56
|
+
ConfigurationVars.DB_PORT.value,
|
|
57
|
+
ConfigurationVars.DB_DATABASE.value,
|
|
58
|
+
]
|
|
59
|
+
creds = configurator.get_config_creds()
|
|
60
|
+
return {key: creds.get(key) for key in keys}
|
|
54
61
|
|
|
55
|
-
def
|
|
62
|
+
def eval_retry(self) -> bool:
|
|
56
63
|
"""
|
|
57
|
-
|
|
64
|
+
Evaluate the status of retry lifecycle.
|
|
58
65
|
|
|
59
66
|
Returns
|
|
60
67
|
-------
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
bool
|
|
69
|
+
True if a retry should be attempted, False otherwise.
|
|
63
70
|
"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
return configurator.eval_retry()
|
|
72
|
+
|
|
73
|
+
def _validate(self) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Validate if all required keys are present in the configuration.
|
|
76
|
+
"""
|
|
77
|
+
required_keys = [
|
|
78
|
+
ConfigurationVars.DB_HOST.value,
|
|
79
|
+
ConfigurationVars.DB_PORT.value,
|
|
80
|
+
ConfigurationVars.DB_DATABASE.value,
|
|
81
|
+
CredentialsVars.DB_USERNAME.value,
|
|
82
|
+
CredentialsVars.DB_PASSWORD.value,
|
|
83
|
+
]
|
|
84
|
+
current_keys = configurator.get_config_creds()
|
|
85
|
+
missing_keys = []
|
|
86
|
+
for key in required_keys:
|
|
87
|
+
if key not in current_keys or current_keys[key] is None:
|
|
88
|
+
missing_keys.append(key)
|
|
89
|
+
if missing_keys:
|
|
90
|
+
raise ValueError(f"Missing required variables for SQL store: {', '.join(missing_keys)}")
|