digitalhub 0.11.0b7__py3-none-any.whl → 0.13.0__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.
Potentially problematic release.
This version of digitalhub might be problematic. Click here for more details.
- digitalhub/__init__.py +4 -1
- digitalhub/context/api.py +9 -5
- digitalhub/context/builder.py +7 -5
- digitalhub/context/context.py +13 -1
- digitalhub/entities/__init__.py +3 -0
- digitalhub/entities/_base/__init__.py +3 -0
- digitalhub/entities/_base/_base/__init__.py +3 -0
- digitalhub/entities/_base/_base/entity.py +4 -0
- digitalhub/entities/_base/context/__init__.py +3 -0
- digitalhub/entities/_base/context/entity.py +4 -0
- digitalhub/entities/_base/entity/__init__.py +3 -0
- digitalhub/entities/_base/entity/_constructors/__init__.py +3 -0
- digitalhub/entities/_base/entity/_constructors/metadata.py +4 -0
- digitalhub/entities/_base/entity/_constructors/name.py +4 -0
- digitalhub/entities/_base/entity/_constructors/spec.py +4 -0
- digitalhub/entities/_base/entity/_constructors/status.py +4 -0
- digitalhub/entities/_base/entity/_constructors/uuid.py +4 -0
- digitalhub/entities/_base/entity/builder.py +4 -0
- digitalhub/entities/_base/entity/entity.py +4 -0
- digitalhub/entities/_base/entity/metadata.py +4 -0
- digitalhub/entities/_base/entity/spec.py +4 -0
- digitalhub/entities/_base/entity/status.py +4 -0
- digitalhub/entities/_base/executable/__init__.py +3 -0
- digitalhub/entities/_base/executable/entity.py +109 -57
- digitalhub/entities/_base/material/__init__.py +3 -0
- digitalhub/entities/_base/material/entity.py +15 -18
- digitalhub/entities/_base/material/spec.py +4 -0
- digitalhub/entities/_base/material/status.py +4 -0
- digitalhub/entities/_base/material/utils.py +5 -1
- digitalhub/entities/_base/runtime_entity/__init__.py +3 -0
- digitalhub/entities/_base/runtime_entity/builder.py +4 -0
- digitalhub/entities/_base/unversioned/__init__.py +3 -0
- digitalhub/entities/_base/unversioned/builder.py +4 -0
- digitalhub/entities/_base/unversioned/entity.py +4 -0
- digitalhub/entities/_base/versioned/__init__.py +3 -0
- digitalhub/entities/_base/versioned/builder.py +4 -0
- digitalhub/entities/_base/versioned/entity.py +4 -0
- digitalhub/entities/_commons/__init__.py +3 -0
- digitalhub/entities/_commons/enums.py +4 -0
- digitalhub/entities/_commons/metrics.py +68 -30
- digitalhub/entities/_commons/utils.py +40 -9
- digitalhub/entities/_processors/__init__.py +3 -0
- digitalhub/entities/_processors/base.py +154 -79
- digitalhub/entities/_processors/context.py +370 -215
- digitalhub/entities/_processors/utils.py +78 -30
- digitalhub/entities/artifact/__init__.py +3 -0
- digitalhub/entities/artifact/_base/__init__.py +3 -0
- digitalhub/entities/artifact/_base/builder.py +4 -0
- digitalhub/entities/artifact/_base/entity.py +4 -0
- digitalhub/entities/artifact/_base/spec.py +4 -0
- digitalhub/entities/artifact/_base/status.py +4 -0
- digitalhub/entities/artifact/artifact/__init__.py +3 -0
- digitalhub/entities/artifact/artifact/builder.py +4 -0
- digitalhub/entities/artifact/artifact/entity.py +4 -0
- digitalhub/entities/artifact/artifact/spec.py +4 -0
- digitalhub/entities/artifact/artifact/status.py +4 -0
- digitalhub/entities/artifact/crud.py +8 -0
- digitalhub/entities/artifact/utils.py +32 -13
- digitalhub/entities/builders.py +4 -0
- digitalhub/entities/dataitem/__init__.py +3 -0
- digitalhub/entities/dataitem/_base/__init__.py +3 -0
- digitalhub/entities/dataitem/_base/builder.py +4 -0
- digitalhub/entities/dataitem/_base/entity.py +4 -0
- digitalhub/entities/dataitem/_base/spec.py +4 -0
- digitalhub/entities/dataitem/_base/status.py +4 -0
- digitalhub/entities/dataitem/crud.py +18 -2
- digitalhub/entities/dataitem/dataitem/__init__.py +3 -0
- digitalhub/entities/dataitem/dataitem/builder.py +4 -0
- digitalhub/entities/dataitem/dataitem/entity.py +4 -0
- digitalhub/entities/dataitem/dataitem/spec.py +4 -0
- digitalhub/entities/dataitem/dataitem/status.py +4 -0
- digitalhub/entities/dataitem/iceberg/__init__.py +3 -0
- digitalhub/entities/dataitem/iceberg/builder.py +4 -0
- digitalhub/entities/dataitem/iceberg/entity.py +4 -0
- digitalhub/entities/dataitem/iceberg/spec.py +4 -0
- digitalhub/entities/dataitem/iceberg/status.py +4 -0
- digitalhub/entities/dataitem/table/__init__.py +3 -0
- digitalhub/entities/dataitem/table/builder.py +4 -0
- digitalhub/entities/dataitem/table/entity.py +7 -3
- digitalhub/entities/dataitem/table/models.py +4 -0
- digitalhub/entities/dataitem/table/spec.py +4 -0
- digitalhub/entities/dataitem/table/status.py +4 -0
- digitalhub/entities/dataitem/table/utils.py +4 -0
- digitalhub/entities/dataitem/utils.py +88 -35
- digitalhub/entities/function/__init__.py +3 -0
- digitalhub/entities/function/_base/__init__.py +3 -0
- digitalhub/entities/function/_base/builder.py +4 -0
- digitalhub/entities/function/_base/entity.py +4 -0
- digitalhub/entities/function/_base/spec.py +4 -0
- digitalhub/entities/function/_base/status.py +4 -0
- digitalhub/entities/function/crud.py +4 -0
- digitalhub/entities/model/__init__.py +3 -0
- digitalhub/entities/model/_base/__init__.py +3 -0
- digitalhub/entities/model/_base/builder.py +4 -0
- digitalhub/entities/model/_base/entity.py +4 -0
- digitalhub/entities/model/_base/spec.py +4 -0
- digitalhub/entities/model/_base/status.py +4 -0
- digitalhub/entities/model/crud.py +8 -0
- digitalhub/entities/model/huggingface/__init__.py +3 -0
- digitalhub/entities/model/huggingface/builder.py +4 -0
- digitalhub/entities/model/huggingface/entity.py +4 -0
- digitalhub/entities/model/huggingface/spec.py +4 -0
- digitalhub/entities/model/huggingface/status.py +4 -0
- digitalhub/entities/model/mlflow/__init__.py +3 -0
- digitalhub/entities/model/mlflow/builder.py +4 -0
- digitalhub/entities/model/mlflow/entity.py +4 -0
- digitalhub/entities/model/mlflow/models.py +4 -0
- digitalhub/entities/model/mlflow/spec.py +4 -0
- digitalhub/entities/model/mlflow/status.py +4 -0
- digitalhub/entities/model/mlflow/utils.py +4 -0
- digitalhub/entities/model/model/__init__.py +3 -0
- digitalhub/entities/model/model/builder.py +4 -0
- digitalhub/entities/model/model/entity.py +4 -0
- digitalhub/entities/model/model/spec.py +4 -0
- digitalhub/entities/model/model/status.py +4 -0
- digitalhub/entities/model/sklearn/__init__.py +3 -0
- digitalhub/entities/model/sklearn/builder.py +4 -0
- digitalhub/entities/model/sklearn/entity.py +4 -0
- digitalhub/entities/model/sklearn/spec.py +4 -0
- digitalhub/entities/model/sklearn/status.py +4 -0
- digitalhub/entities/model/utils.py +32 -13
- digitalhub/entities/project/__init__.py +3 -0
- digitalhub/entities/project/_base/__init__.py +3 -0
- digitalhub/entities/project/_base/builder.py +4 -0
- digitalhub/entities/project/_base/entity.py +4 -2
- digitalhub/entities/project/_base/models.py +4 -0
- digitalhub/entities/project/_base/spec.py +4 -0
- digitalhub/entities/project/_base/status.py +4 -0
- digitalhub/entities/project/crud.py +4 -0
- digitalhub/entities/project/utils.py +4 -0
- digitalhub/entities/run/__init__.py +3 -0
- digitalhub/entities/run/_base/__init__.py +3 -0
- digitalhub/entities/run/_base/builder.py +4 -0
- digitalhub/entities/run/_base/entity.py +6 -2
- digitalhub/entities/run/_base/spec.py +4 -0
- digitalhub/entities/run/_base/status.py +4 -0
- digitalhub/entities/run/crud.py +4 -0
- digitalhub/entities/secret/__init__.py +3 -0
- digitalhub/entities/secret/_base/__init__.py +3 -0
- digitalhub/entities/secret/_base/builder.py +4 -0
- digitalhub/entities/secret/_base/entity.py +4 -0
- digitalhub/entities/secret/_base/spec.py +4 -0
- digitalhub/entities/secret/_base/status.py +4 -0
- digitalhub/entities/secret/crud.py +4 -0
- digitalhub/entities/task/__init__.py +3 -0
- digitalhub/entities/task/_base/__init__.py +3 -0
- digitalhub/entities/task/_base/builder.py +4 -0
- digitalhub/entities/task/_base/entity.py +4 -0
- digitalhub/entities/task/_base/models.py +16 -3
- digitalhub/entities/task/_base/spec.py +4 -0
- digitalhub/entities/task/_base/status.py +4 -0
- digitalhub/entities/task/_base/utils.py +4 -0
- digitalhub/entities/task/crud.py +4 -0
- digitalhub/entities/trigger/__init__.py +3 -0
- digitalhub/entities/trigger/_base/__init__.py +3 -0
- digitalhub/entities/trigger/_base/builder.py +4 -0
- digitalhub/entities/trigger/_base/entity.py +15 -0
- digitalhub/entities/trigger/_base/spec.py +4 -0
- digitalhub/entities/trigger/_base/status.py +4 -0
- digitalhub/entities/trigger/crud.py +4 -0
- digitalhub/entities/trigger/lifecycle/__init__.py +3 -0
- digitalhub/entities/trigger/lifecycle/builder.py +4 -0
- digitalhub/entities/trigger/lifecycle/entity.py +4 -0
- digitalhub/entities/trigger/lifecycle/spec.py +4 -0
- digitalhub/entities/trigger/lifecycle/status.py +4 -0
- digitalhub/entities/trigger/scheduler/__init__.py +3 -0
- digitalhub/entities/trigger/scheduler/builder.py +4 -0
- digitalhub/entities/trigger/scheduler/entity.py +4 -0
- digitalhub/entities/trigger/scheduler/spec.py +4 -0
- digitalhub/entities/trigger/scheduler/status.py +4 -0
- digitalhub/entities/workflow/__init__.py +3 -0
- digitalhub/entities/workflow/_base/__init__.py +3 -0
- digitalhub/entities/workflow/_base/builder.py +4 -0
- digitalhub/entities/workflow/_base/entity.py +4 -0
- digitalhub/entities/workflow/_base/spec.py +4 -0
- digitalhub/entities/workflow/_base/status.py +4 -0
- digitalhub/entities/workflow/crud.py +4 -0
- digitalhub/factory/__init__.py +3 -0
- digitalhub/factory/factory.py +29 -3
- digitalhub/factory/utils.py +15 -3
- digitalhub/runtimes/__init__.py +3 -0
- digitalhub/runtimes/_base.py +5 -1
- digitalhub/runtimes/builder.py +22 -1
- digitalhub/runtimes/enums.py +4 -0
- digitalhub/stores/__init__.py +3 -0
- digitalhub/stores/client/__init__.py +15 -0
- digitalhub/stores/client/_base/__init__.py +3 -0
- digitalhub/stores/client/_base/api_builder.py +18 -0
- digitalhub/stores/client/_base/client.py +97 -0
- digitalhub/stores/client/_base/key_builder.py +32 -0
- digitalhub/stores/client/_base/params_builder.py +18 -0
- digitalhub/stores/client/api.py +14 -5
- digitalhub/stores/client/builder.py +7 -1
- digitalhub/stores/client/dhcore/__init__.py +3 -0
- digitalhub/stores/client/dhcore/api_builder.py +21 -0
- digitalhub/stores/client/dhcore/client.py +329 -70
- digitalhub/stores/client/dhcore/configurator.py +489 -193
- digitalhub/stores/client/dhcore/enums.py +7 -0
- digitalhub/stores/client/dhcore/error_parser.py +39 -1
- digitalhub/stores/client/dhcore/key_builder.py +4 -0
- digitalhub/stores/client/dhcore/models.py +4 -0
- digitalhub/stores/client/dhcore/params_builder.py +117 -17
- digitalhub/stores/client/dhcore/utils.py +44 -22
- digitalhub/stores/client/local/__init__.py +3 -0
- digitalhub/stores/client/local/api_builder.py +21 -0
- digitalhub/stores/client/local/client.py +10 -8
- digitalhub/stores/client/local/enums.py +4 -0
- digitalhub/stores/client/local/key_builder.py +4 -0
- digitalhub/stores/client/local/params_builder.py +4 -0
- digitalhub/stores/credentials/__init__.py +3 -0
- digitalhub/stores/credentials/api.py +35 -0
- digitalhub/stores/credentials/configurator.py +210 -0
- digitalhub/stores/credentials/enums.py +68 -0
- digitalhub/stores/credentials/handler.py +176 -0
- digitalhub/stores/credentials/ini_module.py +164 -0
- digitalhub/stores/credentials/store.py +81 -0
- digitalhub/stores/data/__init__.py +3 -0
- digitalhub/stores/data/_base/__init__.py +3 -0
- digitalhub/stores/data/_base/store.py +31 -9
- digitalhub/stores/data/api.py +53 -9
- digitalhub/stores/data/builder.py +94 -41
- digitalhub/stores/data/enums.py +4 -0
- digitalhub/stores/data/local/__init__.py +3 -0
- digitalhub/stores/data/local/store.py +8 -7
- digitalhub/stores/data/remote/__init__.py +3 -0
- digitalhub/stores/data/remote/store.py +8 -7
- digitalhub/stores/data/s3/__init__.py +3 -0
- digitalhub/stores/data/s3/configurator.py +69 -80
- digitalhub/stores/data/s3/store.py +73 -81
- digitalhub/stores/data/s3/utils.py +14 -10
- digitalhub/stores/data/sql/__init__.py +3 -0
- digitalhub/stores/data/sql/configurator.py +80 -73
- digitalhub/stores/data/sql/store.py +195 -102
- digitalhub/stores/readers/__init__.py +3 -0
- digitalhub/stores/readers/data/__init__.py +3 -0
- digitalhub/stores/readers/data/_base/__init__.py +3 -0
- digitalhub/stores/readers/data/_base/builder.py +4 -0
- digitalhub/stores/readers/data/_base/reader.py +4 -0
- digitalhub/stores/readers/data/api.py +4 -0
- digitalhub/stores/readers/data/factory.py +4 -0
- digitalhub/stores/readers/data/pandas/__init__.py +3 -0
- digitalhub/stores/readers/data/pandas/builder.py +4 -0
- digitalhub/stores/readers/data/pandas/reader.py +4 -0
- digitalhub/stores/readers/query/__init__.py +3 -0
- digitalhub/utils/__init__.py +3 -0
- digitalhub/utils/enums.py +4 -0
- digitalhub/utils/exceptions.py +10 -0
- digitalhub/utils/file_utils.py +57 -30
- digitalhub/utils/generic_utils.py +45 -33
- digitalhub/utils/git_utils.py +28 -14
- digitalhub/utils/io_utils.py +23 -18
- digitalhub/utils/logger.py +4 -0
- digitalhub/utils/types.py +4 -0
- digitalhub/utils/uri_utils.py +35 -31
- digitalhub-0.13.0.dist-info/METADATA +301 -0
- digitalhub-0.13.0.dist-info/RECORD +259 -0
- digitalhub-0.13.0.dist-info/licenses/AUTHORS +5 -0
- digitalhub-0.13.0.dist-info/licenses/LICENSE +201 -0
- digitalhub/entities/_commons/types.py +0 -5
- digitalhub/stores/configurator/__init__.py +0 -0
- digitalhub/stores/configurator/api.py +0 -31
- digitalhub/stores/configurator/configurator.py +0 -198
- digitalhub/stores/configurator/credentials_store.py +0 -65
- digitalhub/stores/configurator/enums.py +0 -21
- digitalhub/stores/configurator/ini_module.py +0 -128
- digitalhub/stores/data/s3/enums.py +0 -16
- digitalhub/stores/data/sql/enums.py +0 -16
- digitalhub/stores/data/utils.py +0 -34
- digitalhub-0.11.0b7.dist-info/METADATA +0 -259
- digitalhub-0.11.0b7.dist-info/RECORD +0 -261
- digitalhub-0.11.0b7.dist-info/licenses/LICENSE.txt +0 -216
- {digitalhub-0.11.0b7.dist-info → digitalhub-0.13.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
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 abc import abstractmethod
|
|
8
|
+
|
|
9
|
+
from digitalhub.stores.credentials.enums import CredsOrigin
|
|
10
|
+
from digitalhub.stores.credentials.handler import creds_handler
|
|
11
|
+
from digitalhub.utils.exceptions import ConfigError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Configurator:
|
|
15
|
+
"""
|
|
16
|
+
Base configurator for credentials management.
|
|
17
|
+
|
|
18
|
+
Attributes
|
|
19
|
+
----------
|
|
20
|
+
keys : list of str
|
|
21
|
+
List of credential keys to manage.
|
|
22
|
+
required_keys : list of str
|
|
23
|
+
List of required credential keys.
|
|
24
|
+
_env : str
|
|
25
|
+
Environment origin identifier.
|
|
26
|
+
_file : str
|
|
27
|
+
File origin identifier.
|
|
28
|
+
_creds_handler : object
|
|
29
|
+
Credentials handler instance.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# Must be set in implementing class
|
|
33
|
+
keys: list[str] = []
|
|
34
|
+
required_keys: list[str] = []
|
|
35
|
+
|
|
36
|
+
# Origin of the credentials
|
|
37
|
+
_env = CredsOrigin.ENV.value
|
|
38
|
+
_file = CredsOrigin.FILE.value
|
|
39
|
+
|
|
40
|
+
# Credentials handler
|
|
41
|
+
_creds_handler = creds_handler
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
self._current_profile = self._creds_handler.get_current_profile()
|
|
45
|
+
self.load_configs()
|
|
46
|
+
self._changed_origin = False
|
|
47
|
+
self._origin = self.set_origin()
|
|
48
|
+
|
|
49
|
+
##############################
|
|
50
|
+
# Configuration
|
|
51
|
+
##############################
|
|
52
|
+
|
|
53
|
+
def load_configs(self) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Load the configuration from both environment and file sources.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
None
|
|
60
|
+
"""
|
|
61
|
+
self.load_env_vars()
|
|
62
|
+
self.load_file_vars()
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def load_env_vars(self) -> None:
|
|
66
|
+
...
|
|
67
|
+
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def load_file_vars(self) -> None:
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
def check_config(self) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Check if the current profile has changed and reload
|
|
75
|
+
the file credentials if needed.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
None
|
|
80
|
+
"""
|
|
81
|
+
if (current := self._creds_handler.get_current_profile()) != self._current_profile:
|
|
82
|
+
self.load_file_vars()
|
|
83
|
+
self._current_profile = current
|
|
84
|
+
|
|
85
|
+
def set_origin(self) -> str:
|
|
86
|
+
"""
|
|
87
|
+
Determine the default origin for credentials (env or file).
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
str
|
|
92
|
+
The selected origin ('env' or 'file').
|
|
93
|
+
|
|
94
|
+
Raises
|
|
95
|
+
------
|
|
96
|
+
ConfigError
|
|
97
|
+
If required credentials are missing in both sources.
|
|
98
|
+
"""
|
|
99
|
+
origin = self._env
|
|
100
|
+
|
|
101
|
+
env_creds = self._creds_handler.get_credentials(self._env)
|
|
102
|
+
missing_env = self._check_credentials(env_creds)
|
|
103
|
+
|
|
104
|
+
file_creds = self._creds_handler.get_credentials(self._file)
|
|
105
|
+
missing_file = self._check_credentials(file_creds)
|
|
106
|
+
|
|
107
|
+
msg = ""
|
|
108
|
+
if missing_env:
|
|
109
|
+
msg = f"Missing required vars in env: {', '.join(missing_env)}"
|
|
110
|
+
origin = self._file
|
|
111
|
+
self._changed_origin = True
|
|
112
|
+
elif missing_file:
|
|
113
|
+
msg += f"Missing required vars in .dhcore.ini file: {', '.join(missing_file)}"
|
|
114
|
+
|
|
115
|
+
if missing_env and missing_file:
|
|
116
|
+
raise ConfigError(msg)
|
|
117
|
+
|
|
118
|
+
return origin
|
|
119
|
+
|
|
120
|
+
def eval_change_origin(self) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Attempt to change the origin of credentials.
|
|
123
|
+
Raise error if already evaluated.
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
None
|
|
128
|
+
"""
|
|
129
|
+
try:
|
|
130
|
+
self.change_origin()
|
|
131
|
+
except ConfigError:
|
|
132
|
+
raise ConfigError("Credentials origin already evaluated. Please check your credentials.")
|
|
133
|
+
|
|
134
|
+
def change_origin(self) -> None:
|
|
135
|
+
"""
|
|
136
|
+
Change the origin of credentials from env to file or vice versa.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
None
|
|
141
|
+
"""
|
|
142
|
+
if self._changed_origin:
|
|
143
|
+
raise ConfigError("Origin has already been changed.")
|
|
144
|
+
if self._origin == self._env:
|
|
145
|
+
self.change_to_file()
|
|
146
|
+
self.change_to_env()
|
|
147
|
+
|
|
148
|
+
def change_to_file(self) -> None:
|
|
149
|
+
"""
|
|
150
|
+
Set the credentials origin to file.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
None
|
|
155
|
+
"""
|
|
156
|
+
if self._origin == self._env:
|
|
157
|
+
self._changed_origin = True
|
|
158
|
+
self._origin = CredsOrigin.FILE.value
|
|
159
|
+
|
|
160
|
+
def change_to_env(self) -> None:
|
|
161
|
+
"""
|
|
162
|
+
Set the credentials origin to environment.
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
None
|
|
167
|
+
"""
|
|
168
|
+
if self._origin == self._file:
|
|
169
|
+
self._changed_origin = True
|
|
170
|
+
self._origin = CredsOrigin.ENV.value
|
|
171
|
+
|
|
172
|
+
##############################
|
|
173
|
+
# Credentials
|
|
174
|
+
##############################
|
|
175
|
+
|
|
176
|
+
def get_credentials(self, origin: str) -> dict:
|
|
177
|
+
"""
|
|
178
|
+
Retrieve credentials for the specified origin.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
origin : str
|
|
183
|
+
The origin to retrieve credentials from ('env' or 'file').
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
dict
|
|
188
|
+
Dictionary of credentials.
|
|
189
|
+
"""
|
|
190
|
+
return self._creds_handler.get_credentials(origin)
|
|
191
|
+
|
|
192
|
+
def _check_credentials(self, creds: dict) -> list[str]:
|
|
193
|
+
"""
|
|
194
|
+
Check for missing required credentials in a dictionary.
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
creds : dict
|
|
199
|
+
Dictionary of credentials to check.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
list of str
|
|
204
|
+
List of missing required credential keys.
|
|
205
|
+
"""
|
|
206
|
+
missing_keys = []
|
|
207
|
+
for k, v in creds.items():
|
|
208
|
+
if v is None and k in self.required_keys:
|
|
209
|
+
missing_keys.append(k)
|
|
210
|
+
return missing_keys
|
|
@@ -0,0 +1,68 @@
|
|
|
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 enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CredsOrigin(Enum):
|
|
11
|
+
"""
|
|
12
|
+
Credential origins for configuration.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
ENV : str
|
|
17
|
+
Credentials from environment variables.
|
|
18
|
+
FILE : str
|
|
19
|
+
Credentials from configuration file.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
ENV = "env"
|
|
23
|
+
FILE = "file"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SetCreds(Enum):
|
|
27
|
+
"""
|
|
28
|
+
Supported credential environments.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
DEFAULT = "__default"
|
|
32
|
+
DH_PROFILE = "DH_NAME"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CredsEnvVar(Enum):
|
|
36
|
+
"""
|
|
37
|
+
Supported credential environment variables.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# S3
|
|
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
|
+
S3_REGION = "AWS_REGION"
|
|
46
|
+
S3_SIGNATURE_VERSION = "S3_SIGNATURE_VERSION"
|
|
47
|
+
S3_CREDENTIALS_EXPIRATION = "AWS_CREDENTIALS_EXPIRATION"
|
|
48
|
+
S3_PATH_STYLE = "S3_PATH_STYLE"
|
|
49
|
+
|
|
50
|
+
# SQL
|
|
51
|
+
DB_HOST = "DB_HOST"
|
|
52
|
+
DB_PORT = "DB_PORT"
|
|
53
|
+
DB_USERNAME = "DB_USERNAME"
|
|
54
|
+
DB_PASSWORD = "DB_PASSWORD"
|
|
55
|
+
DB_DATABASE = "DB_DATABASE"
|
|
56
|
+
DB_PLATFORM = "DB_PLATFORM"
|
|
57
|
+
DB_PG_SCHEMA = "DB_SCHEMA"
|
|
58
|
+
|
|
59
|
+
# DHCORE
|
|
60
|
+
DHCORE_ENDPOINT = "DHCORE_ENDPOINT"
|
|
61
|
+
DHCORE_ISSUER = "DHCORE_ISSUER"
|
|
62
|
+
DHCORE_USER = "DHCORE_USER"
|
|
63
|
+
DHCORE_PASSWORD = "DHCORE_PASSWORD"
|
|
64
|
+
DHCORE_CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
65
|
+
DHCORE_ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
|
|
66
|
+
DHCORE_REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
|
|
67
|
+
DHCORE_PERSONAL_ACCESS_TOKEN = "DHCORE_PERSONAL_ACCESS_TOKEN"
|
|
68
|
+
DHCORE_WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|
|
@@ -0,0 +1,176 @@
|
|
|
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 os
|
|
8
|
+
|
|
9
|
+
from digitalhub.stores.credentials.enums import SetCreds
|
|
10
|
+
from digitalhub.stores.credentials.ini_module import (
|
|
11
|
+
load_file,
|
|
12
|
+
load_key,
|
|
13
|
+
load_profile,
|
|
14
|
+
set_current_profile,
|
|
15
|
+
write_config,
|
|
16
|
+
)
|
|
17
|
+
from digitalhub.stores.credentials.store import CredentialsStore
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CredentialHandler:
|
|
21
|
+
"""
|
|
22
|
+
Handler for configuring clients and managing credentials.
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
_creds_store : CredentialsStore
|
|
27
|
+
Store for credentials.
|
|
28
|
+
_profile : str
|
|
29
|
+
Current credentials profile name.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self) -> None:
|
|
33
|
+
self._creds_store = CredentialsStore()
|
|
34
|
+
self._profile = self._read_current_profile()
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _read_current_profile() -> str:
|
|
38
|
+
"""
|
|
39
|
+
Read the current credentials profile name.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
str
|
|
44
|
+
Name of the credentials profile.
|
|
45
|
+
"""
|
|
46
|
+
profile = os.getenv(SetCreds.DH_PROFILE.value)
|
|
47
|
+
if profile is not None:
|
|
48
|
+
return profile
|
|
49
|
+
file = load_file()
|
|
50
|
+
profile = load_profile(file)
|
|
51
|
+
if profile is not None:
|
|
52
|
+
return profile
|
|
53
|
+
return SetCreds.DEFAULT.value
|
|
54
|
+
|
|
55
|
+
##############################
|
|
56
|
+
# Public methods
|
|
57
|
+
##############################
|
|
58
|
+
|
|
59
|
+
def set_current_profile(self, creds_set: str) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Set the current credentials profile name.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
creds_set : str
|
|
66
|
+
Name of the credentials profile to set.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
None
|
|
71
|
+
"""
|
|
72
|
+
self._profile = creds_set
|
|
73
|
+
set_current_profile(creds_set)
|
|
74
|
+
|
|
75
|
+
def get_current_profile(self) -> str:
|
|
76
|
+
"""
|
|
77
|
+
Get the current credentials profile name.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
str
|
|
82
|
+
Name of the current credentials profile.
|
|
83
|
+
"""
|
|
84
|
+
return self._profile
|
|
85
|
+
|
|
86
|
+
def load_from_env(self, vars: list[str]) -> dict:
|
|
87
|
+
"""
|
|
88
|
+
Load variables from environment.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
vars : list of str
|
|
93
|
+
List of environment variable names to load.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
dict
|
|
98
|
+
Dictionary of environment variable values.
|
|
99
|
+
"""
|
|
100
|
+
return {var: os.getenv(var) for var in vars}
|
|
101
|
+
|
|
102
|
+
def load_from_file(self, vars: list[str]) -> dict:
|
|
103
|
+
"""
|
|
104
|
+
Load variables from credentials config file.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
vars : list of str
|
|
109
|
+
List of variable names to load from file.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
dict
|
|
114
|
+
Dictionary of variable values from file.
|
|
115
|
+
"""
|
|
116
|
+
file = load_file()
|
|
117
|
+
profile = load_profile(file)
|
|
118
|
+
if profile is not None:
|
|
119
|
+
self._profile = profile
|
|
120
|
+
return {var: load_key(file, self._profile, var) for var in vars}
|
|
121
|
+
|
|
122
|
+
def write_env(self, creds: dict) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Write credentials to the .dhcore file for the current profile.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
creds : dict
|
|
129
|
+
Credentials to write.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
None
|
|
134
|
+
"""
|
|
135
|
+
write_config(creds, self._profile)
|
|
136
|
+
|
|
137
|
+
##############################
|
|
138
|
+
# Credentials store methods
|
|
139
|
+
##############################
|
|
140
|
+
|
|
141
|
+
def set_credentials(self, origin: str, creds: dict) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Set credentials for the current profile and origin.
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
origin : str
|
|
148
|
+
The origin of the credentials ('env' or 'file').
|
|
149
|
+
creds : dict
|
|
150
|
+
Credentials to set.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
None
|
|
155
|
+
"""
|
|
156
|
+
self._creds_store.set_credentials(self._profile, origin, creds)
|
|
157
|
+
|
|
158
|
+
def get_credentials(self, origin: str) -> dict:
|
|
159
|
+
"""
|
|
160
|
+
Get credentials for the current profile from the specified origin.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
origin : str
|
|
165
|
+
The origin to get credentials from ('env' or 'file').
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
dict
|
|
170
|
+
Dictionary of credentials.
|
|
171
|
+
"""
|
|
172
|
+
return self._creds_store.get_credentials(self._profile, origin)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# Define global credential handler
|
|
176
|
+
creds_handler = CredentialHandler()
|
|
@@ -0,0 +1,164 @@
|
|
|
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 configparser import ConfigParser
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from digitalhub.utils.exceptions import ClientError
|
|
11
|
+
|
|
12
|
+
# File where to write credementials
|
|
13
|
+
ENV_FILE = Path.home() / ".dhcore.ini"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_file() -> ConfigParser:
|
|
17
|
+
"""
|
|
18
|
+
Load the credentials configuration from the .dhcore.ini file.
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
ConfigParser
|
|
23
|
+
Parsed configuration file object.
|
|
24
|
+
|
|
25
|
+
Raises
|
|
26
|
+
------
|
|
27
|
+
ClientError
|
|
28
|
+
If the file cannot be read.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
file = ConfigParser()
|
|
32
|
+
file.read(ENV_FILE)
|
|
33
|
+
return file
|
|
34
|
+
except Exception as e:
|
|
35
|
+
raise ClientError(f"Failed to read env file: {e}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def load_profile(file: ConfigParser) -> str | None:
|
|
39
|
+
"""
|
|
40
|
+
Load the current credentials profile name from the .dhcore.ini file.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
file : ConfigParser
|
|
45
|
+
Parsed configuration file object.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
str or None
|
|
50
|
+
Name of the credentials profile, or None if not found.
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
return file["DEFAULT"]["current_environment"]
|
|
54
|
+
except KeyError:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def load_key(file: ConfigParser, profile: str, key: str) -> str | None:
|
|
59
|
+
"""
|
|
60
|
+
Load a specific key value from the credentials profile in the
|
|
61
|
+
.dhcore.ini file.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
file : ConfigParser
|
|
66
|
+
Parsed configuration file object.
|
|
67
|
+
profile : str
|
|
68
|
+
Name of the credentials profile.
|
|
69
|
+
key : str
|
|
70
|
+
Name of the key to retrieve.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
str or None
|
|
75
|
+
Value of the key, or None if not found.
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
return file[profile][key]
|
|
79
|
+
except KeyError:
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def write_config(creds: dict, environment: str) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Write credentials to the .dhcore.ini file for the specified environment.
|
|
86
|
+
Overwrites any existing values for that environment.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
creds : dict
|
|
91
|
+
Dictionary of credentials to write.
|
|
92
|
+
environment : str
|
|
93
|
+
Name of the credentials profile/environment.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
None
|
|
98
|
+
|
|
99
|
+
Raises
|
|
100
|
+
------
|
|
101
|
+
ClientError
|
|
102
|
+
If the file cannot be written.
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
cfg = load_file()
|
|
106
|
+
|
|
107
|
+
sections = cfg.sections()
|
|
108
|
+
if environment not in sections:
|
|
109
|
+
cfg.add_section(environment)
|
|
110
|
+
|
|
111
|
+
cfg["DEFAULT"]["current_environment"] = environment
|
|
112
|
+
for k, v in creds.items():
|
|
113
|
+
cfg[environment][k] = str(v)
|
|
114
|
+
|
|
115
|
+
ENV_FILE.touch(exist_ok=True)
|
|
116
|
+
with open(ENV_FILE, "w") as inifile:
|
|
117
|
+
cfg.write(inifile)
|
|
118
|
+
|
|
119
|
+
except Exception as e:
|
|
120
|
+
raise ClientError(f"Failed to write env file: {e}")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def set_current_profile(environment: str) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Set the current credentials profile in the .dhcore.ini file.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
environment : str
|
|
130
|
+
Name of the credentials profile to set as current.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
None
|
|
135
|
+
|
|
136
|
+
Raises
|
|
137
|
+
------
|
|
138
|
+
ClientError
|
|
139
|
+
If the file cannot be written.
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
cfg = load_file()
|
|
143
|
+
cfg["DEFAULT"]["current_environment"] = environment
|
|
144
|
+
with open(ENV_FILE, "w") as inifile:
|
|
145
|
+
cfg.write(inifile)
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
raise ClientError(f"Failed to write env file: {e}")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def read_env_from_file() -> str | None:
|
|
152
|
+
"""
|
|
153
|
+
Read the current credentials profile name from the .dhcore.ini file.
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
-------
|
|
157
|
+
str or None
|
|
158
|
+
Name of the current credentials profile, or None if not found.
|
|
159
|
+
"""
|
|
160
|
+
try:
|
|
161
|
+
cfg = load_file()
|
|
162
|
+
return cfg["DEFAULT"]["current_environment"]
|
|
163
|
+
except Exception:
|
|
164
|
+
return None
|
|
@@ -0,0 +1,81 @@
|
|
|
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 typing import Any
|
|
8
|
+
|
|
9
|
+
from digitalhub.stores.credentials.enums import CredsOrigin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CredentialsStore:
|
|
13
|
+
"""
|
|
14
|
+
Store and retrieve credentials for different profiles and origins.
|
|
15
|
+
|
|
16
|
+
Attributes
|
|
17
|
+
----------
|
|
18
|
+
_file_creds : dict of str to dict
|
|
19
|
+
Credentials stored by profile from file origin.
|
|
20
|
+
_env_creds : dict of str to Any
|
|
21
|
+
Credentials stored from environment origin.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
self._file_creds: dict[str, dict[str, Any]] = {}
|
|
26
|
+
self._env_creds: dict[str, Any] = {}
|
|
27
|
+
|
|
28
|
+
def set_credentials(
|
|
29
|
+
self,
|
|
30
|
+
profile: str,
|
|
31
|
+
origin: str,
|
|
32
|
+
credentials: dict[str, Any],
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Set all credentials for a given profile and origin.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
profile : str
|
|
40
|
+
Name of the credentials profile.
|
|
41
|
+
origin : str
|
|
42
|
+
Origin of the credentials ('env' or 'file').
|
|
43
|
+
credentials : dict of str to Any
|
|
44
|
+
Dictionary of credentials to set.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
None
|
|
49
|
+
"""
|
|
50
|
+
if origin == CredsOrigin.ENV.value:
|
|
51
|
+
for key, value in credentials.items():
|
|
52
|
+
self._env_creds[key] = value
|
|
53
|
+
return
|
|
54
|
+
if profile not in self._file_creds:
|
|
55
|
+
self._file_creds[profile] = {}
|
|
56
|
+
for key, value in credentials.items():
|
|
57
|
+
self._file_creds[profile][key] = value
|
|
58
|
+
|
|
59
|
+
def get_credentials(
|
|
60
|
+
self,
|
|
61
|
+
profile: str,
|
|
62
|
+
origin: str,
|
|
63
|
+
) -> dict[str, Any]:
|
|
64
|
+
"""
|
|
65
|
+
Get all credentials for a given profile and origin.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
profile : str
|
|
70
|
+
Name of the credentials profile.
|
|
71
|
+
origin : str
|
|
72
|
+
Origin of the credentials ('env' or 'file').
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
dict of str to Any
|
|
77
|
+
Dictionary of credentials for the profile and origin.
|
|
78
|
+
"""
|
|
79
|
+
if origin == CredsOrigin.ENV.value:
|
|
80
|
+
return self._env_creds
|
|
81
|
+
return self._file_creds[profile]
|