digitalhub 0.14.0b5__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 +2 -2
- digitalhub/context/api.py +43 -6
- digitalhub/context/builder.py +1 -1
- digitalhub/context/context.py +3 -6
- digitalhub/entities/_base/context/entity.py +0 -3
- digitalhub/entities/_base/executable/entity.py +29 -11
- digitalhub/entities/_base/material/entity.py +2 -2
- digitalhub/entities/_base/material/utils.py +0 -4
- digitalhub/entities/_commons/enums.py +1 -0
- digitalhub/entities/_commons/utils.py +19 -0
- digitalhub/entities/_processors/base/crud.py +15 -24
- digitalhub/entities/_processors/base/import_export.py +3 -7
- digitalhub/entities/_processors/base/processor.py +4 -7
- digitalhub/entities/_processors/base/special_ops.py +4 -8
- digitalhub/entities/_processors/context/crud.py +27 -29
- digitalhub/entities/_processors/context/import_export.py +7 -7
- digitalhub/entities/_processors/context/material.py +2 -2
- digitalhub/entities/_processors/context/special_ops.py +25 -25
- digitalhub/entities/_processors/utils.py +7 -116
- digitalhub/entities/artifact/crud.py +3 -3
- digitalhub/entities/artifact/utils.py +2 -2
- digitalhub/entities/builders.py +2 -0
- digitalhub/entities/dataitem/crud.py +3 -3
- digitalhub/entities/dataitem/utils.py +10 -14
- digitalhub/entities/function/_base/entity.py +0 -3
- digitalhub/entities/function/crud.py +3 -3
- digitalhub/entities/model/crud.py +3 -3
- digitalhub/entities/model/mlflow/utils.py +29 -20
- digitalhub/entities/model/utils.py +2 -2
- digitalhub/entities/project/_base/builder.py +0 -6
- digitalhub/entities/project/_base/entity.py +264 -114
- digitalhub/entities/project/_base/spec.py +4 -4
- digitalhub/entities/project/crud.py +16 -51
- digitalhub/entities/project/utils.py +7 -3
- digitalhub/entities/secret/crud.py +2 -2
- digitalhub/entities/task/_base/models.py +13 -16
- digitalhub/entities/trigger/crud.py +28 -9
- digitalhub/entities/workflow/_base/entity.py +0 -5
- digitalhub/entities/workflow/crud.py +3 -6
- digitalhub/stores/client/{dhcore/api_builder.py → api_builder.py} +2 -3
- digitalhub/stores/client/builder.py +20 -32
- digitalhub/stores/client/client.py +322 -0
- digitalhub/stores/client/{dhcore/configurator.py → configurator.py} +148 -195
- digitalhub/stores/client/{_base/enums.py → enums.py} +11 -0
- 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/{dhcore/params_builder.py → params_builder.py} +51 -12
- 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 +26 -10
- digitalhub/stores/configurator/handler.py +213 -0
- digitalhub/stores/{credentials → configurator}/ini_module.py +31 -6
- digitalhub/stores/data/_base/store.py +0 -4
- digitalhub/stores/data/api.py +4 -6
- digitalhub/stores/data/builder.py +6 -38
- digitalhub/stores/data/s3/configurator.py +30 -114
- digitalhub/stores/data/s3/store.py +9 -22
- digitalhub/stores/data/sql/configurator.py +49 -71
- digitalhub/stores/data/sql/store.py +26 -61
- digitalhub/utils/generic_utils.py +0 -12
- digitalhub/utils/git_utils.py +0 -8
- digitalhub/utils/io_utils.py +0 -8
- digitalhub/utils/store_utils.py +1 -1
- {digitalhub-0.14.0b5.dist-info → digitalhub-0.14.9.dist-info}/METADATA +3 -3
- {digitalhub-0.14.0b5.dist-info → digitalhub-0.14.9.dist-info}/RECORD +73 -86
- {digitalhub-0.14.0b5.dist-info → digitalhub-0.14.9.dist-info}/WHEEL +1 -1
- 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 -82
- digitalhub/stores/client/api.py +0 -32
- digitalhub/stores/client/dhcore/__init__.py +0 -3
- digitalhub/stores/client/dhcore/client.py +0 -553
- digitalhub/stores/client/dhcore/enums.py +0 -18
- digitalhub/stores/client/dhcore/key_builder.py +0 -62
- digitalhub/stores/client/dhcore/utils.py +0 -86
- digitalhub/stores/client/local/__init__.py +0 -3
- digitalhub/stores/client/local/api_builder.py +0 -116
- digitalhub/stores/client/local/client.py +0 -605
- 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 -97
- digitalhub/stores/credentials/__init__.py +0 -3
- digitalhub/stores/credentials/configurator.py +0 -185
- digitalhub/stores/credentials/handler.py +0 -164
- digitalhub/stores/credentials/store.py +0 -77
- digitalhub/stores/data/enums.py +0 -15
- /digitalhub/stores/client/{dhcore/error_parser.py → error_parser.py} +0 -0
- /digitalhub/stores/{client/_base → configurator}/__init__.py +0 -0
- {digitalhub-0.14.0b5.dist-info → digitalhub-0.14.9.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.14.0b5.dist-info → digitalhub-0.14.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from requests import request
|
|
8
|
+
|
|
9
|
+
from digitalhub.stores.client.configurator import ClientConfigurator
|
|
10
|
+
from digitalhub.stores.client.response_processor import ResponseProcessor
|
|
11
|
+
from digitalhub.utils.exceptions import BackendError
|
|
12
|
+
|
|
13
|
+
# Default timeout for requests (in seconds)
|
|
14
|
+
DEFAULT_TIMEOUT = 60
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HttpRequestHandler:
|
|
18
|
+
"""
|
|
19
|
+
Handles HTTP request execution for DHCore client.
|
|
20
|
+
|
|
21
|
+
Encapsulates all HTTP communication logic including request execution,
|
|
22
|
+
automatic token refresh on authentication failures, and response processing.
|
|
23
|
+
Works in coordination with configurator for authentication and response
|
|
24
|
+
processor for parsing.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self._configurator = ClientConfigurator()
|
|
29
|
+
self._response_processor = ResponseProcessor()
|
|
30
|
+
|
|
31
|
+
def prepare_request(self, method: str, api: str, **kwargs) -> dict:
|
|
32
|
+
"""
|
|
33
|
+
Execute API call with full URL construction and authentication.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
method : str
|
|
38
|
+
HTTP method type (GET, POST, PUT, DELETE, etc.).
|
|
39
|
+
api : str
|
|
40
|
+
API endpoint path to call.
|
|
41
|
+
**kwargs : dict
|
|
42
|
+
Additional HTTP request arguments.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
dict
|
|
47
|
+
Response from the API call.
|
|
48
|
+
"""
|
|
49
|
+
full_kwargs = self._set_auth(**kwargs)
|
|
50
|
+
url = self._build_url(api)
|
|
51
|
+
return self._execute_request(method, url, **full_kwargs)
|
|
52
|
+
|
|
53
|
+
def _execute_request(
|
|
54
|
+
self,
|
|
55
|
+
method: str,
|
|
56
|
+
url: str,
|
|
57
|
+
**kwargs,
|
|
58
|
+
) -> dict:
|
|
59
|
+
"""
|
|
60
|
+
Execute HTTP request with automatic handling.
|
|
61
|
+
|
|
62
|
+
Sends HTTP request with authentication, handles token refresh on 401 errors,
|
|
63
|
+
validates API version compatibility, and parses response. Uses 60-second
|
|
64
|
+
timeout by default.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
method : str
|
|
69
|
+
HTTP method (GET, POST, PUT, DELETE, etc.).
|
|
70
|
+
url : str
|
|
71
|
+
Complete URL to request.
|
|
72
|
+
**kwargs : dict
|
|
73
|
+
Additional HTTP request arguments (headers, params, data, etc.).
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
dict
|
|
78
|
+
Parsed response body as dictionary.
|
|
79
|
+
"""
|
|
80
|
+
# Execute HTTP request
|
|
81
|
+
response = request(method, url, timeout=DEFAULT_TIMEOUT, **kwargs)
|
|
82
|
+
|
|
83
|
+
# Process response (version check, error parsing, dictify)
|
|
84
|
+
try:
|
|
85
|
+
return self._response_processor.process(response)
|
|
86
|
+
except BackendError as e:
|
|
87
|
+
# Handle authentication errors with token refresh
|
|
88
|
+
if response.status_code == 401 and self._configurator.evaluate_refresh():
|
|
89
|
+
kwargs = self._configurator.get_auth_parameters(kwargs)
|
|
90
|
+
return self._execute_request(method, url, **kwargs)
|
|
91
|
+
raise e
|
|
92
|
+
|
|
93
|
+
def _set_auth(self, **kwargs) -> dict:
|
|
94
|
+
"""
|
|
95
|
+
Prepare kwargs with authentication parameters.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
**kwargs : dict
|
|
100
|
+
Request parameters to augment with authentication.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
dict
|
|
105
|
+
kwargs enhanced with authentication parameters.
|
|
106
|
+
"""
|
|
107
|
+
return self._configurator.get_auth_parameters(kwargs)
|
|
108
|
+
|
|
109
|
+
def _build_url(self, api: str) -> str:
|
|
110
|
+
"""
|
|
111
|
+
Build complete URL for API call.
|
|
112
|
+
|
|
113
|
+
Combines configured endpoint with API path, automatically removing
|
|
114
|
+
leading slashes for proper URL construction.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
api : str
|
|
119
|
+
API endpoint path. Leading slashes are automatically handled.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
str
|
|
124
|
+
Complete URL for the API call.
|
|
125
|
+
"""
|
|
126
|
+
endpoint = self._configurator.get_endpoint()
|
|
127
|
+
return f"{endpoint}/{api.removeprefix('/')}"
|
|
128
|
+
|
|
129
|
+
###############################
|
|
130
|
+
# Utility methods
|
|
131
|
+
###############################
|
|
132
|
+
|
|
133
|
+
def refresh_token(self) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Manually trigger OAuth2 token refresh.
|
|
136
|
+
"""
|
|
137
|
+
self._configurator.evaluate_refresh()
|
|
138
|
+
|
|
139
|
+
def get_credentials_and_config(self) -> dict:
|
|
140
|
+
"""
|
|
141
|
+
Get current authentication credentials and configuration.
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
dict
|
|
146
|
+
Current authentication credentials and configuration.
|
|
147
|
+
"""
|
|
148
|
+
creds = self._configurator.get_credentials_and_config()
|
|
149
|
+
|
|
150
|
+
# Test connection to ensure validity
|
|
151
|
+
self.prepare_request("GET", "/api/auth")
|
|
152
|
+
return creds
|
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
from digitalhub.stores.client._base.enums import ApiCategories
|
|
7
|
+
from digitalhub.stores.client.enums import ApiCategories
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
class ClientKeyBuilder:
|
|
@@ -36,7 +34,6 @@ class ClientKeyBuilder:
|
|
|
36
34
|
return self.base_entity_key(*args, **kwargs)
|
|
37
35
|
return self.context_entity_key(*args, **kwargs)
|
|
38
36
|
|
|
39
|
-
@abstractmethod
|
|
40
37
|
def base_entity_key(self, entity_id: str) -> str:
|
|
41
38
|
"""
|
|
42
39
|
Build for base entity key.
|
|
@@ -44,15 +41,15 @@ class ClientKeyBuilder:
|
|
|
44
41
|
Parameters
|
|
45
42
|
----------
|
|
46
43
|
entity_id : str
|
|
47
|
-
|
|
44
|
+
Entity id.
|
|
48
45
|
|
|
49
46
|
Returns
|
|
50
47
|
-------
|
|
51
48
|
str
|
|
52
|
-
|
|
49
|
+
Key.
|
|
53
50
|
"""
|
|
51
|
+
return f"store://{entity_id}"
|
|
54
52
|
|
|
55
|
-
@abstractmethod
|
|
56
53
|
def context_entity_key(
|
|
57
54
|
self,
|
|
58
55
|
project: str,
|
|
@@ -67,18 +64,21 @@ class ClientKeyBuilder:
|
|
|
67
64
|
Parameters
|
|
68
65
|
----------
|
|
69
66
|
project : str
|
|
70
|
-
|
|
67
|
+
Project name.
|
|
71
68
|
entity_type : str
|
|
72
|
-
|
|
69
|
+
Entity type.
|
|
73
70
|
entity_kind : str
|
|
74
|
-
|
|
71
|
+
Entity kind.
|
|
75
72
|
entity_name : str
|
|
76
|
-
|
|
77
|
-
entity_id : str
|
|
78
|
-
|
|
73
|
+
Entity name.
|
|
74
|
+
entity_id : str
|
|
75
|
+
Entity ID.
|
|
79
76
|
|
|
80
77
|
Returns
|
|
81
78
|
-------
|
|
82
79
|
str
|
|
83
|
-
|
|
80
|
+
Key.
|
|
84
81
|
"""
|
|
82
|
+
if entity_id is None:
|
|
83
|
+
return f"store://{project}/{entity_type}/{entity_kind}/{entity_name}"
|
|
84
|
+
return f"store://{project}/{entity_type}/{entity_kind}/{entity_name}:{entity_id}"
|
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from digitalhub.stores.client.enums import ApiCategories, BackendOperations
|
|
9
10
|
|
|
10
11
|
DEFAULT_START_PAGE = 0
|
|
11
12
|
DEFAULT_SIZE = 25
|
|
12
13
|
DEFAULT_SORT = "metadata.updated,DESC"
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
class
|
|
16
|
+
class ClientParametersBuilder:
|
|
16
17
|
"""
|
|
17
18
|
Parameter builder for DHCore client API calls.
|
|
18
19
|
|
|
@@ -22,15 +23,6 @@ class ClientDHCoreParametersBuilder(ClientParametersBuilder):
|
|
|
22
23
|
within projects). Supports query parameter formatting, search filter
|
|
23
24
|
construction for Solr-based searches, cascade deletion options,
|
|
24
25
|
versioning parameters, and entity sharing parameters.
|
|
25
|
-
|
|
26
|
-
Methods
|
|
27
|
-
-------
|
|
28
|
-
build_parameters(category, operation, **kwargs)
|
|
29
|
-
Main entry point for parameter building based on API category.
|
|
30
|
-
build_parameters_base(operation, **kwargs)
|
|
31
|
-
Builds parameters for base-level API operations.
|
|
32
|
-
build_parameters_context(operation, **kwargs)
|
|
33
|
-
Builds parameters for context-level API operations.
|
|
34
26
|
"""
|
|
35
27
|
|
|
36
28
|
def build_parameters(self, category: str, operation: str, **kwargs) -> dict:
|
|
@@ -236,6 +228,53 @@ class ClientDHCoreParametersBuilder(ClientParametersBuilder):
|
|
|
236
228
|
|
|
237
229
|
return kwargs
|
|
238
230
|
|
|
231
|
+
@staticmethod
|
|
232
|
+
def _ensure_params(**kwargs) -> dict:
|
|
233
|
+
"""
|
|
234
|
+
Initialize parameter dictionary with query parameters structure.
|
|
235
|
+
|
|
236
|
+
Ensures parameter dictionary has 'params' key for HTTP query parameters,
|
|
237
|
+
guaranteeing consistent structure for all parameter building methods.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
**kwargs : dict
|
|
242
|
+
Keyword arguments to format. May be empty or contain various
|
|
243
|
+
parameters for API operations.
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
-------
|
|
247
|
+
dict
|
|
248
|
+
Parameters dictionary with guaranteed 'params' key containing
|
|
249
|
+
empty dict if not already present.
|
|
250
|
+
"""
|
|
251
|
+
if "params" not in kwargs:
|
|
252
|
+
kwargs["params"] = {}
|
|
253
|
+
return kwargs
|
|
254
|
+
|
|
255
|
+
@staticmethod
|
|
256
|
+
def _add_param(key: str, value: Any | None, **kwargs) -> dict:
|
|
257
|
+
"""
|
|
258
|
+
Add a single query parameter to kwargs.
|
|
259
|
+
|
|
260
|
+
Parameters
|
|
261
|
+
----------
|
|
262
|
+
key : str
|
|
263
|
+
Parameter key.
|
|
264
|
+
value : Any
|
|
265
|
+
Parameter value.
|
|
266
|
+
**kwargs : dict
|
|
267
|
+
Keyword arguments to format. May be empty or contain various
|
|
268
|
+
parameters for API operations.
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
dict
|
|
273
|
+
Parameters dictionary with added key-value pair in 'params'.
|
|
274
|
+
"""
|
|
275
|
+
kwargs["params"][key] = value
|
|
276
|
+
return kwargs
|
|
277
|
+
|
|
239
278
|
@staticmethod
|
|
240
279
|
def read_page_number(**kwargs) -> int:
|
|
241
280
|
"""
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import typing
|
|
8
|
+
from warnings import warn
|
|
9
|
+
|
|
10
|
+
from requests.exceptions import JSONDecodeError
|
|
11
|
+
|
|
12
|
+
from digitalhub.stores.client.error_parser import ErrorParser
|
|
13
|
+
from digitalhub.utils.exceptions import BackendError, ClientError
|
|
14
|
+
|
|
15
|
+
if typing.TYPE_CHECKING:
|
|
16
|
+
from requests import Response
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# API levels that are supported
|
|
20
|
+
MAX_API_LEVEL = 20
|
|
21
|
+
MIN_API_LEVEL = 14
|
|
22
|
+
LIB_VERSION = 14
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ResponseProcessor:
|
|
26
|
+
"""
|
|
27
|
+
Processes and validates HTTP responses from DHCore backend.
|
|
28
|
+
|
|
29
|
+
Handles API version validation, error parsing, and response body parsing
|
|
30
|
+
to dictionary. Supports API versions {MIN_API_LEVEL} to {MAX_API_LEVEL}.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self) -> None:
|
|
34
|
+
self._error_parser = ErrorParser()
|
|
35
|
+
|
|
36
|
+
def process(self, response: Response) -> dict:
|
|
37
|
+
"""
|
|
38
|
+
Process HTTP response with validation and parsing.
|
|
39
|
+
|
|
40
|
+
Performs API version compatibility check, error parsing for failed
|
|
41
|
+
responses, and JSON deserialization.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
response : Response
|
|
46
|
+
HTTP response object from backend.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
dict
|
|
51
|
+
Parsed response body as dictionary.
|
|
52
|
+
"""
|
|
53
|
+
self._check_api_version(response)
|
|
54
|
+
self._error_parser.parse(response)
|
|
55
|
+
return self._parse_json(response)
|
|
56
|
+
|
|
57
|
+
def _check_api_version(self, response: Response) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Validate DHCore API version compatibility.
|
|
60
|
+
|
|
61
|
+
Checks backend API version against supported range and warns if backend
|
|
62
|
+
version is newer than library. Supported: {MIN_API_LEVEL} to {MAX_API_LEVEL}.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
response : Response
|
|
67
|
+
HTTP response containing X-Api-Level header.
|
|
68
|
+
"""
|
|
69
|
+
if "X-Api-Level" not in response.headers:
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
core_api_level = int(response.headers["X-Api-Level"])
|
|
73
|
+
if not (MIN_API_LEVEL <= core_api_level <= MAX_API_LEVEL):
|
|
74
|
+
raise ClientError("Backend API level not supported.")
|
|
75
|
+
|
|
76
|
+
if LIB_VERSION < core_api_level:
|
|
77
|
+
warn("Backend API level is higher than library version. You should consider updating the library.")
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def _parse_json(response: Response) -> dict:
|
|
81
|
+
"""
|
|
82
|
+
Parse HTTP response body to dictionary.
|
|
83
|
+
|
|
84
|
+
Converts JSON response to Python dictionary, treating empty responses
|
|
85
|
+
as valid and returning empty dict.
|
|
86
|
+
|
|
87
|
+
Parameters
|
|
88
|
+
----------
|
|
89
|
+
response : Response
|
|
90
|
+
HTTP response object to parse.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
dict
|
|
95
|
+
Parsed response body as dictionary, or empty dict if body is empty.
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
return response.json()
|
|
99
|
+
except JSONDecodeError:
|
|
100
|
+
if response.text == "":
|
|
101
|
+
return {}
|
|
102
|
+
raise BackendError("Backend response could not be parsed.")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from digitalhub.stores.client.builder import get_client
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def refresh_token() -> None:
|
|
11
|
+
"""
|
|
12
|
+
Refresh the current OAuth2 access token.
|
|
13
|
+
|
|
14
|
+
Uses the refresh token stored in client configuration to obtain a new
|
|
15
|
+
access token. Requires OAuth2 authentication configuration.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Raises
|
|
19
|
+
------
|
|
20
|
+
ClientError
|
|
21
|
+
If client not properly configured or token refresh fails.
|
|
22
|
+
"""
|
|
23
|
+
get_client().refresh_token()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_credentials_and_config() -> dict:
|
|
27
|
+
"""
|
|
28
|
+
Get current client credentials and configuration.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
dict
|
|
33
|
+
Current client credentials and configuration details.
|
|
34
|
+
"""
|
|
35
|
+
return get_client().get_credentials_and_config()
|
|
@@ -4,23 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
from digitalhub.stores.
|
|
7
|
+
from digitalhub.stores.configurator.configurator import configurator
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def set_current_profile(
|
|
10
|
+
def set_current_profile(profile: str) -> None:
|
|
11
11
|
"""
|
|
12
12
|
Set the current credentials profile.
|
|
13
13
|
|
|
14
14
|
Parameters
|
|
15
15
|
----------
|
|
16
|
-
|
|
16
|
+
profile : str
|
|
17
17
|
Name of the credentials profile to set.
|
|
18
|
-
|
|
19
|
-
Returns
|
|
20
|
-
-------
|
|
21
|
-
None
|
|
22
18
|
"""
|
|
23
|
-
|
|
19
|
+
configurator.set_current_profile(profile)
|
|
24
20
|
|
|
25
21
|
|
|
26
22
|
def get_current_profile() -> str:
|
|
@@ -32,4 +28,4 @@ def get_current_profile() -> str:
|
|
|
32
28
|
str
|
|
33
29
|
Name of the current credentials profile.
|
|
34
30
|
"""
|
|
35
|
-
return
|
|
31
|
+
return configurator.get_current_profile()
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from digitalhub.stores.configurator.handler import ConfigurationHandler
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Configurator:
|
|
11
|
+
"""
|
|
12
|
+
Configurator class for configuration and credentials management.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self._handler = ConfigurationHandler()
|
|
17
|
+
self._reload_from_env = False
|
|
18
|
+
|
|
19
|
+
##############################
|
|
20
|
+
# Configuration
|
|
21
|
+
##############################
|
|
22
|
+
|
|
23
|
+
def get_configuration(self) -> dict:
|
|
24
|
+
"""
|
|
25
|
+
Retrieve the current configuration.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
dict
|
|
30
|
+
Dictionary of configuration variables.
|
|
31
|
+
"""
|
|
32
|
+
return self._handler.get_configuration()
|
|
33
|
+
|
|
34
|
+
##############################
|
|
35
|
+
# Credentials
|
|
36
|
+
##############################
|
|
37
|
+
|
|
38
|
+
def get_credentials(self) -> dict:
|
|
39
|
+
"""
|
|
40
|
+
Retrieve the current credentials.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
dict
|
|
45
|
+
Dictionary of credentials.
|
|
46
|
+
"""
|
|
47
|
+
return self._handler.get_credentials()
|
|
48
|
+
|
|
49
|
+
def eval_retry(self) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
Evaluate credentials reload based on retry logic.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
bool
|
|
56
|
+
True if a retry action was performed, otherwise False.
|
|
57
|
+
"""
|
|
58
|
+
current_creds = self.get_credentials()
|
|
59
|
+
reread_creds = self._handler.load_credentials()
|
|
60
|
+
|
|
61
|
+
# Compare cached and file credentials.
|
|
62
|
+
# If different, reload in cache.
|
|
63
|
+
if current_creds != reread_creds:
|
|
64
|
+
self.reload_credentials()
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
# Check if we need to reload from env only
|
|
68
|
+
if not self._reload_from_env:
|
|
69
|
+
self._handler.reload_credentials_from_env()
|
|
70
|
+
self._reload_from_env = True
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
def reload_credentials(self) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Reload credentials from environment and file.
|
|
78
|
+
"""
|
|
79
|
+
self._handler.reload_credentials()
|
|
80
|
+
|
|
81
|
+
###############################
|
|
82
|
+
# Profile methods
|
|
83
|
+
###############################
|
|
84
|
+
|
|
85
|
+
def set_current_profile(self, profile: str) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Set the current profile.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
profile : str
|
|
92
|
+
Name of the profile to set.
|
|
93
|
+
"""
|
|
94
|
+
self._handler.set_current_profile(profile)
|
|
95
|
+
|
|
96
|
+
################################
|
|
97
|
+
# Other methods
|
|
98
|
+
################################
|
|
99
|
+
|
|
100
|
+
def write_file(self, variables: dict) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Write the current configuration and credentials to file.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
variables : dict
|
|
107
|
+
Dictionary of variables to write.
|
|
108
|
+
"""
|
|
109
|
+
self._handler.write_file(variables)
|
|
110
|
+
|
|
111
|
+
def get_config_creds(self) -> dict:
|
|
112
|
+
"""
|
|
113
|
+
Get merged configuration and credentials.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
dict
|
|
118
|
+
Merged configuration and credentials dictionary.
|
|
119
|
+
"""
|
|
120
|
+
return {**self.get_configuration(), **self.get_credentials()}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
configurator = Configurator()
|
|
@@ -32,26 +32,20 @@ class SetCreds(Enum):
|
|
|
32
32
|
DH_PROFILE = "DH_NAME"
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class
|
|
35
|
+
class ConfigurationVars(Enum):
|
|
36
36
|
"""
|
|
37
|
-
|
|
37
|
+
List of supported configuration variables.
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
# S3
|
|
41
41
|
S3_ENDPOINT_URL = "AWS_ENDPOINT_URL"
|
|
42
|
-
S3_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
|
|
43
|
-
S3_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
|
|
44
|
-
S3_SESSION_TOKEN = "AWS_SESSION_TOKEN"
|
|
45
42
|
S3_REGION = "AWS_REGION"
|
|
46
43
|
S3_SIGNATURE_VERSION = "S3_SIGNATURE_VERSION"
|
|
47
|
-
S3_CREDENTIALS_EXPIRATION = "AWS_CREDENTIALS_EXPIRATION"
|
|
48
44
|
S3_PATH_STYLE = "S3_PATH_STYLE"
|
|
49
45
|
|
|
50
46
|
# SQL
|
|
51
47
|
DB_HOST = "DB_HOST"
|
|
52
48
|
DB_PORT = "DB_PORT"
|
|
53
|
-
DB_USERNAME = "DB_USERNAME"
|
|
54
|
-
DB_PASSWORD = "DB_PASSWORD"
|
|
55
49
|
DB_DATABASE = "DB_DATABASE"
|
|
56
50
|
DB_PLATFORM = "DB_PLATFORM"
|
|
57
51
|
DB_PG_SCHEMA = "DB_SCHEMA"
|
|
@@ -59,10 +53,32 @@ class CredsEnvVar(Enum):
|
|
|
59
53
|
# DHCORE
|
|
60
54
|
DHCORE_ENDPOINT = "DHCORE_ENDPOINT"
|
|
61
55
|
DHCORE_ISSUER = "DHCORE_ISSUER"
|
|
56
|
+
DHCORE_WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|
|
57
|
+
DHCORE_CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
58
|
+
DEFAULT_FILES_STORE = "DHCORE_DEFAULT_FILES_STORE"
|
|
59
|
+
|
|
60
|
+
# OAUTH2
|
|
61
|
+
OAUTH2_TOKEN_ENDPOINT = "OAUTH2_TOKEN_ENDPOINT"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CredentialsVars(Enum):
|
|
65
|
+
"""
|
|
66
|
+
List of supported credential variables.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
# S3
|
|
70
|
+
S3_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
|
|
71
|
+
S3_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
|
|
72
|
+
S3_SESSION_TOKEN = "AWS_SESSION_TOKEN"
|
|
73
|
+
S3_CREDENTIALS_EXPIRATION = "AWS_CREDENTIALS_EXPIRATION"
|
|
74
|
+
|
|
75
|
+
# SQL
|
|
76
|
+
DB_USERNAME = "DB_USERNAME"
|
|
77
|
+
DB_PASSWORD = "DB_PASSWORD"
|
|
78
|
+
|
|
79
|
+
# DHCORE
|
|
62
80
|
DHCORE_USER = "DHCORE_USER"
|
|
63
81
|
DHCORE_PASSWORD = "DHCORE_PASSWORD"
|
|
64
|
-
DHCORE_CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
65
82
|
DHCORE_ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
|
|
66
83
|
DHCORE_REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
|
|
67
84
|
DHCORE_PERSONAL_ACCESS_TOKEN = "DHCORE_PERSONAL_ACCESS_TOKEN"
|
|
68
|
-
DHCORE_WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|