nost-tools 2.0.0__py3-none-any.whl → 2.0.1__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 nost-tools might be problematic. Click here for more details.
- nost_tools/__init__.py +29 -29
- nost_tools/application.py +800 -793
- nost_tools/application_utils.py +262 -262
- nost_tools/configuration.py +304 -304
- nost_tools/entity.py +73 -73
- nost_tools/errors.py +14 -14
- nost_tools/logger_application.py +192 -192
- nost_tools/managed_application.py +261 -261
- nost_tools/manager.py +472 -472
- nost_tools/observer.py +181 -181
- nost_tools/publisher.py +141 -141
- nost_tools/schemas.py +432 -426
- nost_tools/simulator.py +531 -531
- {nost_tools-2.0.0.dist-info → nost_tools-2.0.1.dist-info}/METADATA +118 -119
- nost_tools-2.0.1.dist-info/RECORD +18 -0
- {nost_tools-2.0.0.dist-info → nost_tools-2.0.1.dist-info}/licenses/LICENSE +29 -29
- nost_tools-2.0.0.dist-info/RECORD +0 -18
- {nost_tools-2.0.0.dist-info → nost_tools-2.0.1.dist-info}/WHEEL +0 -0
- {nost_tools-2.0.0.dist-info → nost_tools-2.0.1.dist-info}/top_level.txt +0 -0
nost_tools/configuration.py
CHANGED
|
@@ -1,304 +1,304 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Configuration Settings.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import logging
|
|
6
|
-
import os
|
|
7
|
-
|
|
8
|
-
import yaml
|
|
9
|
-
from dotenv import find_dotenv, load_dotenv
|
|
10
|
-
from pydantic import ValidationError
|
|
11
|
-
|
|
12
|
-
from .errors import ConfigAssertionError, ConfigurationError, EnvironmentVariableError
|
|
13
|
-
from .schemas import (
|
|
14
|
-
ChannelConfig,
|
|
15
|
-
Config,
|
|
16
|
-
Credentials,
|
|
17
|
-
ExchangeConfig,
|
|
18
|
-
ExecConfig,
|
|
19
|
-
KeycloakConfig,
|
|
20
|
-
RabbitMQConfig,
|
|
21
|
-
RuntimeConfig,
|
|
22
|
-
ServersConfig,
|
|
23
|
-
SimulationConfig,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
logger = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
|
-
class ConnectionConfig:
|
|
29
|
-
"""Connection configuration.
|
|
30
|
-
|
|
31
|
-
The configuration settings to establish a connection to the broker, including authentication for the
|
|
32
|
-
user and identification of the server.
|
|
33
|
-
|
|
34
|
-
Attributes:
|
|
35
|
-
username (str): client username, provided by NOS-T operator
|
|
36
|
-
password (str): client password, provided by NOS-T operator
|
|
37
|
-
host (str): broker hostname
|
|
38
|
-
rabbitmq_port (int): RabbitMQ broker port number
|
|
39
|
-
keycloak_port (int): Keycloak IAM port number
|
|
40
|
-
keycloak_realm (str): Keycloak realm name
|
|
41
|
-
client_id (str): Keycloak client ID
|
|
42
|
-
client_secret_key (str): Keycloak client secret key
|
|
43
|
-
virtual_host (str): RabbitMQ virtual host
|
|
44
|
-
is_tls (bool): True, if the connection uses Transport Layer Security (TLS)
|
|
45
|
-
yaml_file (str): Path to the YAML configuration file
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
def __init__(
|
|
49
|
-
self,
|
|
50
|
-
username: str = None,
|
|
51
|
-
password: str = None,
|
|
52
|
-
rabbitmq_host: str = None,
|
|
53
|
-
rabbitmq_port: int = None,
|
|
54
|
-
keycloak_host: str = None,
|
|
55
|
-
keycloak_port: int = None,
|
|
56
|
-
keycloak_realm: str = None,
|
|
57
|
-
client_id: str = None,
|
|
58
|
-
client_secret_key: str = None,
|
|
59
|
-
virtual_host: str = None,
|
|
60
|
-
is_tls: bool = True,
|
|
61
|
-
yaml_file: str = None,
|
|
62
|
-
):
|
|
63
|
-
"""
|
|
64
|
-
Initializes a new connection configuration.
|
|
65
|
-
|
|
66
|
-
Args:
|
|
67
|
-
username (str): client username, provided by NOS-T operator
|
|
68
|
-
password (str): client password, provided by NOS-T operator
|
|
69
|
-
host (str): broker hostname
|
|
70
|
-
rabbitmq_port (int): RabbitMQ broker port number
|
|
71
|
-
keycloak_port (int): Keycloak IAM port number
|
|
72
|
-
keycloak_realm (str): Keycloak realm name
|
|
73
|
-
client_id (str): Keycloak client ID
|
|
74
|
-
client_secret_key (str): Keycloak client secret key
|
|
75
|
-
virtual_host (str): RabbitMQ virtual host
|
|
76
|
-
is_tls (bool): True, if the connection uses TLS
|
|
77
|
-
yaml_file (str): Path to the YAML configuration file
|
|
78
|
-
"""
|
|
79
|
-
self.username = username
|
|
80
|
-
self.password = password
|
|
81
|
-
self.rabbitmq_host = rabbitmq_host
|
|
82
|
-
self.keycloak_host = keycloak_host
|
|
83
|
-
self.rabbitmq_port = rabbitmq_port
|
|
84
|
-
self.keycloak_port = keycloak_port
|
|
85
|
-
self.keycloak_realm = keycloak_realm
|
|
86
|
-
self.client_id = client_id
|
|
87
|
-
self.client_secret_key = client_secret_key
|
|
88
|
-
self.virtual_host = virtual_host
|
|
89
|
-
self.is_tls = is_tls
|
|
90
|
-
|
|
91
|
-
self.yaml_config = None
|
|
92
|
-
self.predefined_exchanges_queues = False
|
|
93
|
-
self.yaml_file = yaml_file
|
|
94
|
-
self.unique_exchanges = {}
|
|
95
|
-
self.channel_configs = []
|
|
96
|
-
|
|
97
|
-
self.create_connection_config()
|
|
98
|
-
|
|
99
|
-
def get_exchanges(self):
|
|
100
|
-
"""
|
|
101
|
-
Get exchanges from the YAML configuration file.
|
|
102
|
-
"""
|
|
103
|
-
for app, app_channels in self.yaml_config.channels.items():
|
|
104
|
-
for channel, details in app_channels.items():
|
|
105
|
-
bindings = details.get("bindings", {}).get("amqp", {})
|
|
106
|
-
exchange = bindings.get("exchange", {})
|
|
107
|
-
exchange_name = exchange.get("name")
|
|
108
|
-
if exchange_name:
|
|
109
|
-
exchange_config = ExchangeConfig(
|
|
110
|
-
name=exchange_name,
|
|
111
|
-
type=exchange.get("type", "topic"),
|
|
112
|
-
durable=exchange.get("durable", True),
|
|
113
|
-
auto_delete=exchange.get("autoDelete", False),
|
|
114
|
-
vhost=exchange.get("vhost", "/"),
|
|
115
|
-
)
|
|
116
|
-
if exchange_name in self.unique_exchanges:
|
|
117
|
-
if (
|
|
118
|
-
self.unique_exchanges[exchange_name]
|
|
119
|
-
!= exchange_config.model_dump()
|
|
120
|
-
):
|
|
121
|
-
raise ValueError(
|
|
122
|
-
f"Conflicting configurations for exchange '{exchange_name}': {self.unique_exchanges[exchange_name]} vs {exchange_config.model_dump()}"
|
|
123
|
-
)
|
|
124
|
-
else:
|
|
125
|
-
self.unique_exchanges[exchange_name] = (
|
|
126
|
-
exchange_config.model_dump()
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
def get_channels(self):
|
|
130
|
-
"""
|
|
131
|
-
Get channels from the YAML configuration file.
|
|
132
|
-
"""
|
|
133
|
-
for app, app_channels in self.yaml_config.channels.items():
|
|
134
|
-
for channel, details in app_channels.items():
|
|
135
|
-
bindings = details.get("bindings", {}).get("amqp", {})
|
|
136
|
-
exchange = bindings.get("exchange", {})
|
|
137
|
-
exchange_name = exchange.get("name")
|
|
138
|
-
address = details.get("address")
|
|
139
|
-
if address and bindings:
|
|
140
|
-
channel_config = ChannelConfig(
|
|
141
|
-
app=app,
|
|
142
|
-
address=address,
|
|
143
|
-
exchange=exchange_name or "default_exchange",
|
|
144
|
-
durable=exchange.get("durable", True),
|
|
145
|
-
auto_delete=exchange.get("autoDelete", False),
|
|
146
|
-
vhost=exchange.get("vhost", "/"),
|
|
147
|
-
)
|
|
148
|
-
self.channel_configs.append(channel_config.model_dump())
|
|
149
|
-
|
|
150
|
-
def get_exchanges_channels(self):
|
|
151
|
-
"""
|
|
152
|
-
Get exchanges and channels from the YAML configuration file.
|
|
153
|
-
"""
|
|
154
|
-
|
|
155
|
-
self.get_exchanges(), self.get_channels()
|
|
156
|
-
if self.unique_exchanges and self.channel_configs:
|
|
157
|
-
self.predefined_exchanges_queues = True
|
|
158
|
-
self.simulation_config = SimulationConfig(
|
|
159
|
-
exchanges=self.unique_exchanges,
|
|
160
|
-
queues=self.channel_configs,
|
|
161
|
-
execution_parameters=self.yaml_config.execution,
|
|
162
|
-
predefined_exchanges_queues=self.predefined_exchanges_queues,
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
def load_environment_variables(self):
|
|
166
|
-
"""
|
|
167
|
-
Loads an environment (.env) file and returns the parsed data.
|
|
168
|
-
"""
|
|
169
|
-
dotenv_path = find_dotenv(usecwd=True)
|
|
170
|
-
if dotenv_path:
|
|
171
|
-
logger.info(f"Checking for credentials in the .env file: {dotenv_path}.")
|
|
172
|
-
load_dotenv(dotenv_path, override=True)
|
|
173
|
-
else:
|
|
174
|
-
logger.warning(
|
|
175
|
-
"Checking for credentials in the system environment variables."
|
|
176
|
-
)
|
|
177
|
-
if self.server_config.servers.rabbitmq.keycloak_authentication:
|
|
178
|
-
required_fields = [
|
|
179
|
-
"USERNAME",
|
|
180
|
-
"PASSWORD",
|
|
181
|
-
"CLIENT_ID",
|
|
182
|
-
"CLIENT_SECRET_KEY",
|
|
183
|
-
]
|
|
184
|
-
else:
|
|
185
|
-
required_fields = ["USERNAME", "PASSWORD"]
|
|
186
|
-
|
|
187
|
-
env_data = {field: os.getenv(field) for field in required_fields}
|
|
188
|
-
|
|
189
|
-
missing_fields = [field for field, value in env_data.items() if value is None]
|
|
190
|
-
if missing_fields:
|
|
191
|
-
raise EnvironmentVariableError(
|
|
192
|
-
f"Missing required fields in .env file: {', '.join(missing_fields)}"
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
try:
|
|
196
|
-
if self.server_config.servers.rabbitmq.keycloak_authentication:
|
|
197
|
-
self.credentials_config = Credentials(
|
|
198
|
-
username=env_data["USERNAME"],
|
|
199
|
-
password=env_data["PASSWORD"],
|
|
200
|
-
client_id=env_data["CLIENT_ID"],
|
|
201
|
-
client_secret_key=env_data["CLIENT_SECRET_KEY"],
|
|
202
|
-
)
|
|
203
|
-
else:
|
|
204
|
-
self.credentials_config = Credentials(
|
|
205
|
-
username=env_data["USERNAME"],
|
|
206
|
-
password=env_data["PASSWORD"],
|
|
207
|
-
)
|
|
208
|
-
except ValidationError as err:
|
|
209
|
-
raise EnvironmentVariableError(f"Invalid environment variables: {err}")
|
|
210
|
-
|
|
211
|
-
def load_yaml_config_file(self):
|
|
212
|
-
"""
|
|
213
|
-
Loads a YAML configuration file and returns the parsed data.
|
|
214
|
-
"""
|
|
215
|
-
if not os.path.exists(self.yaml_file):
|
|
216
|
-
raise ConfigurationError("Couldn't load config file (not found)")
|
|
217
|
-
|
|
218
|
-
with open(self.yaml_file, "r", encoding="utf-8") as f:
|
|
219
|
-
try:
|
|
220
|
-
yaml_data = yaml.safe_load(f) # Store the parsed YAML data
|
|
221
|
-
except yaml.YAMLError as err:
|
|
222
|
-
raise ConfigurationError(f"Invalid YAML configuration: {err}")
|
|
223
|
-
|
|
224
|
-
try:
|
|
225
|
-
self.yaml_config = Config(**yaml_data)
|
|
226
|
-
except ValidationError as err:
|
|
227
|
-
raise ConfigurationError(f"Invalid configuration: {err}")
|
|
228
|
-
|
|
229
|
-
def create_connection_config(self):
|
|
230
|
-
"""
|
|
231
|
-
Creates a connection configuration.
|
|
232
|
-
"""
|
|
233
|
-
if self.yaml_file:
|
|
234
|
-
try:
|
|
235
|
-
self.load_yaml_config_file()
|
|
236
|
-
except ConfigurationError as e:
|
|
237
|
-
raise ValueError(f"Configuration error: {e}")
|
|
238
|
-
|
|
239
|
-
try:
|
|
240
|
-
assert all(
|
|
241
|
-
item in self.yaml_config.execution.required_apps
|
|
242
|
-
for item in self.yaml_config.channels.keys()
|
|
243
|
-
), "Application names do not match the channels defined in the configuration file."
|
|
244
|
-
except ConfigAssertionError as e:
|
|
245
|
-
raise ValueError(f"Assertion error: {e}")
|
|
246
|
-
else:
|
|
247
|
-
try:
|
|
248
|
-
self.yaml_config = Config(
|
|
249
|
-
servers=ServersConfig(
|
|
250
|
-
rabbitmq=RabbitMQConfig(
|
|
251
|
-
host=self.rabbitmq_host,
|
|
252
|
-
port=self.rabbitmq_port,
|
|
253
|
-
virtual_host=self.virtual_host,
|
|
254
|
-
tls=self.is_tls,
|
|
255
|
-
),
|
|
256
|
-
keycloak=KeycloakConfig(
|
|
257
|
-
host=self.keycloak_host,
|
|
258
|
-
port=self.keycloak_port,
|
|
259
|
-
realm=self.keycloak_realm,
|
|
260
|
-
tls=self.is_tls,
|
|
261
|
-
),
|
|
262
|
-
),
|
|
263
|
-
channels={},
|
|
264
|
-
execution=ExecConfig(),
|
|
265
|
-
)
|
|
266
|
-
except:
|
|
267
|
-
self.yaml_config = Config(
|
|
268
|
-
servers=ServersConfig(
|
|
269
|
-
rabbitmq=RabbitMQConfig(), keycloak=KeycloakConfig()
|
|
270
|
-
),
|
|
271
|
-
channels={},
|
|
272
|
-
execution=ExecConfig(),
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
self.get_exchanges_channels()
|
|
276
|
-
|
|
277
|
-
server_config = self.yaml_config.copy()
|
|
278
|
-
if hasattr(server_config, "channels"):
|
|
279
|
-
del server_config.channels
|
|
280
|
-
if hasattr(server_config, "execution"):
|
|
281
|
-
del server_config.execution
|
|
282
|
-
self.server_config = server_config
|
|
283
|
-
|
|
284
|
-
if (
|
|
285
|
-
self.username is not None
|
|
286
|
-
and self.password is not None
|
|
287
|
-
and self.client_id is not None
|
|
288
|
-
and self.client_secret_key is not None
|
|
289
|
-
):
|
|
290
|
-
logger.info("Using provided credentials.")
|
|
291
|
-
self.credentials_config = Credentials(
|
|
292
|
-
username=self.username,
|
|
293
|
-
password=self.password,
|
|
294
|
-
client_id=self.client_id,
|
|
295
|
-
client_secret_key=self.client_secret_key,
|
|
296
|
-
)
|
|
297
|
-
else:
|
|
298
|
-
self.load_environment_variables()
|
|
299
|
-
|
|
300
|
-
self.rc = RuntimeConfig(
|
|
301
|
-
credentials=self.credentials_config,
|
|
302
|
-
server_configuration=server_config,
|
|
303
|
-
simulation_configuration=self.simulation_config,
|
|
304
|
-
)
|
|
1
|
+
"""
|
|
2
|
+
Configuration Settings.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
import yaml
|
|
9
|
+
from dotenv import find_dotenv, load_dotenv
|
|
10
|
+
from pydantic import ValidationError
|
|
11
|
+
|
|
12
|
+
from .errors import ConfigAssertionError, ConfigurationError, EnvironmentVariableError
|
|
13
|
+
from .schemas import (
|
|
14
|
+
ChannelConfig,
|
|
15
|
+
Config,
|
|
16
|
+
Credentials,
|
|
17
|
+
ExchangeConfig,
|
|
18
|
+
ExecConfig,
|
|
19
|
+
KeycloakConfig,
|
|
20
|
+
RabbitMQConfig,
|
|
21
|
+
RuntimeConfig,
|
|
22
|
+
ServersConfig,
|
|
23
|
+
SimulationConfig,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
class ConnectionConfig:
|
|
29
|
+
"""Connection configuration.
|
|
30
|
+
|
|
31
|
+
The configuration settings to establish a connection to the broker, including authentication for the
|
|
32
|
+
user and identification of the server.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
username (str): client username, provided by NOS-T operator
|
|
36
|
+
password (str): client password, provided by NOS-T operator
|
|
37
|
+
host (str): broker hostname
|
|
38
|
+
rabbitmq_port (int): RabbitMQ broker port number
|
|
39
|
+
keycloak_port (int): Keycloak IAM port number
|
|
40
|
+
keycloak_realm (str): Keycloak realm name
|
|
41
|
+
client_id (str): Keycloak client ID
|
|
42
|
+
client_secret_key (str): Keycloak client secret key
|
|
43
|
+
virtual_host (str): RabbitMQ virtual host
|
|
44
|
+
is_tls (bool): True, if the connection uses Transport Layer Security (TLS)
|
|
45
|
+
yaml_file (str): Path to the YAML configuration file
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
username: str = None,
|
|
51
|
+
password: str = None,
|
|
52
|
+
rabbitmq_host: str = None,
|
|
53
|
+
rabbitmq_port: int = None,
|
|
54
|
+
keycloak_host: str = None,
|
|
55
|
+
keycloak_port: int = None,
|
|
56
|
+
keycloak_realm: str = None,
|
|
57
|
+
client_id: str = None,
|
|
58
|
+
client_secret_key: str = None,
|
|
59
|
+
virtual_host: str = None,
|
|
60
|
+
is_tls: bool = True,
|
|
61
|
+
yaml_file: str = None,
|
|
62
|
+
):
|
|
63
|
+
"""
|
|
64
|
+
Initializes a new connection configuration.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
username (str): client username, provided by NOS-T operator
|
|
68
|
+
password (str): client password, provided by NOS-T operator
|
|
69
|
+
host (str): broker hostname
|
|
70
|
+
rabbitmq_port (int): RabbitMQ broker port number
|
|
71
|
+
keycloak_port (int): Keycloak IAM port number
|
|
72
|
+
keycloak_realm (str): Keycloak realm name
|
|
73
|
+
client_id (str): Keycloak client ID
|
|
74
|
+
client_secret_key (str): Keycloak client secret key
|
|
75
|
+
virtual_host (str): RabbitMQ virtual host
|
|
76
|
+
is_tls (bool): True, if the connection uses TLS
|
|
77
|
+
yaml_file (str): Path to the YAML configuration file
|
|
78
|
+
"""
|
|
79
|
+
self.username = username
|
|
80
|
+
self.password = password
|
|
81
|
+
self.rabbitmq_host = rabbitmq_host
|
|
82
|
+
self.keycloak_host = keycloak_host
|
|
83
|
+
self.rabbitmq_port = rabbitmq_port
|
|
84
|
+
self.keycloak_port = keycloak_port
|
|
85
|
+
self.keycloak_realm = keycloak_realm
|
|
86
|
+
self.client_id = client_id
|
|
87
|
+
self.client_secret_key = client_secret_key
|
|
88
|
+
self.virtual_host = virtual_host
|
|
89
|
+
self.is_tls = is_tls
|
|
90
|
+
|
|
91
|
+
self.yaml_config = None
|
|
92
|
+
self.predefined_exchanges_queues = False
|
|
93
|
+
self.yaml_file = yaml_file
|
|
94
|
+
self.unique_exchanges = {}
|
|
95
|
+
self.channel_configs = []
|
|
96
|
+
|
|
97
|
+
self.create_connection_config()
|
|
98
|
+
|
|
99
|
+
def get_exchanges(self):
|
|
100
|
+
"""
|
|
101
|
+
Get exchanges from the YAML configuration file.
|
|
102
|
+
"""
|
|
103
|
+
for app, app_channels in self.yaml_config.channels.items():
|
|
104
|
+
for channel, details in app_channels.items():
|
|
105
|
+
bindings = details.get("bindings", {}).get("amqp", {})
|
|
106
|
+
exchange = bindings.get("exchange", {})
|
|
107
|
+
exchange_name = exchange.get("name")
|
|
108
|
+
if exchange_name:
|
|
109
|
+
exchange_config = ExchangeConfig(
|
|
110
|
+
name=exchange_name,
|
|
111
|
+
type=exchange.get("type", "topic"),
|
|
112
|
+
durable=exchange.get("durable", True),
|
|
113
|
+
auto_delete=exchange.get("autoDelete", False),
|
|
114
|
+
vhost=exchange.get("vhost", "/"),
|
|
115
|
+
)
|
|
116
|
+
if exchange_name in self.unique_exchanges:
|
|
117
|
+
if (
|
|
118
|
+
self.unique_exchanges[exchange_name]
|
|
119
|
+
!= exchange_config.model_dump()
|
|
120
|
+
):
|
|
121
|
+
raise ValueError(
|
|
122
|
+
f"Conflicting configurations for exchange '{exchange_name}': {self.unique_exchanges[exchange_name]} vs {exchange_config.model_dump()}"
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
self.unique_exchanges[exchange_name] = (
|
|
126
|
+
exchange_config.model_dump()
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def get_channels(self):
|
|
130
|
+
"""
|
|
131
|
+
Get channels from the YAML configuration file.
|
|
132
|
+
"""
|
|
133
|
+
for app, app_channels in self.yaml_config.channels.items():
|
|
134
|
+
for channel, details in app_channels.items():
|
|
135
|
+
bindings = details.get("bindings", {}).get("amqp", {})
|
|
136
|
+
exchange = bindings.get("exchange", {})
|
|
137
|
+
exchange_name = exchange.get("name")
|
|
138
|
+
address = details.get("address")
|
|
139
|
+
if address and bindings:
|
|
140
|
+
channel_config = ChannelConfig(
|
|
141
|
+
app=app,
|
|
142
|
+
address=address,
|
|
143
|
+
exchange=exchange_name or "default_exchange",
|
|
144
|
+
durable=exchange.get("durable", True),
|
|
145
|
+
auto_delete=exchange.get("autoDelete", False),
|
|
146
|
+
vhost=exchange.get("vhost", "/"),
|
|
147
|
+
)
|
|
148
|
+
self.channel_configs.append(channel_config.model_dump())
|
|
149
|
+
|
|
150
|
+
def get_exchanges_channels(self):
|
|
151
|
+
"""
|
|
152
|
+
Get exchanges and channels from the YAML configuration file.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
self.get_exchanges(), self.get_channels()
|
|
156
|
+
if self.unique_exchanges and self.channel_configs:
|
|
157
|
+
self.predefined_exchanges_queues = True
|
|
158
|
+
self.simulation_config = SimulationConfig(
|
|
159
|
+
exchanges=self.unique_exchanges,
|
|
160
|
+
queues=self.channel_configs,
|
|
161
|
+
execution_parameters=self.yaml_config.execution,
|
|
162
|
+
predefined_exchanges_queues=self.predefined_exchanges_queues,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def load_environment_variables(self):
|
|
166
|
+
"""
|
|
167
|
+
Loads an environment (.env) file and returns the parsed data.
|
|
168
|
+
"""
|
|
169
|
+
dotenv_path = find_dotenv(usecwd=True)
|
|
170
|
+
if dotenv_path:
|
|
171
|
+
logger.info(f"Checking for credentials in the .env file: {dotenv_path}.")
|
|
172
|
+
load_dotenv(dotenv_path, override=True)
|
|
173
|
+
else:
|
|
174
|
+
logger.warning(
|
|
175
|
+
"Checking for credentials in the system environment variables."
|
|
176
|
+
)
|
|
177
|
+
if self.server_config.servers.rabbitmq.keycloak_authentication:
|
|
178
|
+
required_fields = [
|
|
179
|
+
"USERNAME",
|
|
180
|
+
"PASSWORD",
|
|
181
|
+
"CLIENT_ID",
|
|
182
|
+
"CLIENT_SECRET_KEY",
|
|
183
|
+
]
|
|
184
|
+
else:
|
|
185
|
+
required_fields = ["USERNAME", "PASSWORD"]
|
|
186
|
+
|
|
187
|
+
env_data = {field: os.getenv(field) for field in required_fields}
|
|
188
|
+
|
|
189
|
+
missing_fields = [field for field, value in env_data.items() if value is None]
|
|
190
|
+
if missing_fields:
|
|
191
|
+
raise EnvironmentVariableError(
|
|
192
|
+
f"Missing required fields in .env file: {', '.join(missing_fields)}"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
if self.server_config.servers.rabbitmq.keycloak_authentication:
|
|
197
|
+
self.credentials_config = Credentials(
|
|
198
|
+
username=env_data["USERNAME"],
|
|
199
|
+
password=env_data["PASSWORD"],
|
|
200
|
+
client_id=env_data["CLIENT_ID"],
|
|
201
|
+
client_secret_key=env_data["CLIENT_SECRET_KEY"],
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
self.credentials_config = Credentials(
|
|
205
|
+
username=env_data["USERNAME"],
|
|
206
|
+
password=env_data["PASSWORD"],
|
|
207
|
+
)
|
|
208
|
+
except ValidationError as err:
|
|
209
|
+
raise EnvironmentVariableError(f"Invalid environment variables: {err}")
|
|
210
|
+
|
|
211
|
+
def load_yaml_config_file(self):
|
|
212
|
+
"""
|
|
213
|
+
Loads a YAML configuration file and returns the parsed data.
|
|
214
|
+
"""
|
|
215
|
+
if not os.path.exists(self.yaml_file):
|
|
216
|
+
raise ConfigurationError("Couldn't load config file (not found)")
|
|
217
|
+
|
|
218
|
+
with open(self.yaml_file, "r", encoding="utf-8") as f:
|
|
219
|
+
try:
|
|
220
|
+
yaml_data = yaml.safe_load(f) # Store the parsed YAML data
|
|
221
|
+
except yaml.YAMLError as err:
|
|
222
|
+
raise ConfigurationError(f"Invalid YAML configuration: {err}")
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
self.yaml_config = Config(**yaml_data)
|
|
226
|
+
except ValidationError as err:
|
|
227
|
+
raise ConfigurationError(f"Invalid configuration: {err}")
|
|
228
|
+
|
|
229
|
+
def create_connection_config(self):
|
|
230
|
+
"""
|
|
231
|
+
Creates a connection configuration.
|
|
232
|
+
"""
|
|
233
|
+
if self.yaml_file:
|
|
234
|
+
try:
|
|
235
|
+
self.load_yaml_config_file()
|
|
236
|
+
except ConfigurationError as e:
|
|
237
|
+
raise ValueError(f"Configuration error: {e}")
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
assert all(
|
|
241
|
+
item in self.yaml_config.execution.required_apps
|
|
242
|
+
for item in self.yaml_config.channels.keys()
|
|
243
|
+
), "Application names do not match the channels defined in the configuration file."
|
|
244
|
+
except ConfigAssertionError as e:
|
|
245
|
+
raise ValueError(f"Assertion error: {e}")
|
|
246
|
+
else:
|
|
247
|
+
try:
|
|
248
|
+
self.yaml_config = Config(
|
|
249
|
+
servers=ServersConfig(
|
|
250
|
+
rabbitmq=RabbitMQConfig(
|
|
251
|
+
host=self.rabbitmq_host,
|
|
252
|
+
port=self.rabbitmq_port,
|
|
253
|
+
virtual_host=self.virtual_host,
|
|
254
|
+
tls=self.is_tls,
|
|
255
|
+
),
|
|
256
|
+
keycloak=KeycloakConfig(
|
|
257
|
+
host=self.keycloak_host,
|
|
258
|
+
port=self.keycloak_port,
|
|
259
|
+
realm=self.keycloak_realm,
|
|
260
|
+
tls=self.is_tls,
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
channels={},
|
|
264
|
+
execution=ExecConfig(),
|
|
265
|
+
)
|
|
266
|
+
except:
|
|
267
|
+
self.yaml_config = Config(
|
|
268
|
+
servers=ServersConfig(
|
|
269
|
+
rabbitmq=RabbitMQConfig(), keycloak=KeycloakConfig()
|
|
270
|
+
),
|
|
271
|
+
channels={},
|
|
272
|
+
execution=ExecConfig(),
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
self.get_exchanges_channels()
|
|
276
|
+
|
|
277
|
+
server_config = self.yaml_config.copy()
|
|
278
|
+
if hasattr(server_config, "channels"):
|
|
279
|
+
del server_config.channels
|
|
280
|
+
if hasattr(server_config, "execution"):
|
|
281
|
+
del server_config.execution
|
|
282
|
+
self.server_config = server_config
|
|
283
|
+
|
|
284
|
+
if (
|
|
285
|
+
self.username is not None
|
|
286
|
+
and self.password is not None
|
|
287
|
+
and self.client_id is not None
|
|
288
|
+
and self.client_secret_key is not None
|
|
289
|
+
):
|
|
290
|
+
logger.info("Using provided credentials.")
|
|
291
|
+
self.credentials_config = Credentials(
|
|
292
|
+
username=self.username,
|
|
293
|
+
password=self.password,
|
|
294
|
+
client_id=self.client_id,
|
|
295
|
+
client_secret_key=self.client_secret_key,
|
|
296
|
+
)
|
|
297
|
+
else:
|
|
298
|
+
self.load_environment_variables()
|
|
299
|
+
|
|
300
|
+
self.rc = RuntimeConfig(
|
|
301
|
+
credentials=self.credentials_config,
|
|
302
|
+
server_configuration=server_config,
|
|
303
|
+
simulation_configuration=self.simulation_config,
|
|
304
|
+
)
|