etos-test-runner 3.7.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.
- etos_test_runner/__init__.py +43 -0
- etos_test_runner/etr.py +209 -0
- etos_test_runner/lib/__init__.py +16 -0
- etos_test_runner/lib/checkout.sh +16 -0
- etos_test_runner/lib/custom_dataset.py +37 -0
- etos_test_runner/lib/decrypt.py +47 -0
- etos_test_runner/lib/environ.sh +16 -0
- etos_test_runner/lib/events.py +62 -0
- etos_test_runner/lib/executor.py +450 -0
- etos_test_runner/lib/executor.sh +37 -0
- etos_test_runner/lib/iut.py +104 -0
- etos_test_runner/lib/iut_monitoring.py +130 -0
- etos_test_runner/lib/log_area.py +369 -0
- etos_test_runner/lib/testrunner.py +300 -0
- etos_test_runner/lib/verdict.py +87 -0
- etos_test_runner/lib/workspace.py +188 -0
- etos_test_runner/plugins/__init__.py +24 -0
- etos_test_runner/plugins/plugin.py +112 -0
- etos_test_runner-3.7.0.dist-info/AUTHORS.rst +7 -0
- etos_test_runner-3.7.0.dist-info/LICENSE.txt +201 -0
- etos_test_runner-3.7.0.dist-info/METADATA +58 -0
- etos_test_runner-3.7.0.dist-info/RECORD +25 -0
- etos_test_runner-3.7.0.dist-info/WHEEL +5 -0
- etos_test_runner-3.7.0.dist-info/top_level.txt +2 -0
- etr_send_event/__init__.py +132 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright 2020 Axis Communications AB.
|
|
2
|
+
#
|
|
3
|
+
# For a full list of individual contributors, please see the commit history.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
"""ETOS test runner module."""
|
|
17
|
+
import os
|
|
18
|
+
import logging
|
|
19
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
20
|
+
from etos_lib.logging.logger import setup_logging
|
|
21
|
+
from etos_test_runner.lib.decrypt import decrypt
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
VERSION = version("etos_test_runner")
|
|
25
|
+
except PackageNotFoundError:
|
|
26
|
+
VERSION = "Unknown"
|
|
27
|
+
|
|
28
|
+
if os.getenv("ETOS_ENCRYPTION_KEY"):
|
|
29
|
+
os.environ["ETOS_RABBITMQ_PASSWORD"] = decrypt(
|
|
30
|
+
os.environ["ETOS_RABBITMQ_PASSWORD"], os.getenv("ETOS_ENCRYPTION_KEY")
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
DEV = os.getenv("DEV", "false").lower() == "true"
|
|
34
|
+
ENVIRONMENT = "development" if DEV else "production"
|
|
35
|
+
setup_logging("ETOS Test Runner", VERSION, ENVIRONMENT)
|
|
36
|
+
|
|
37
|
+
# JSONTas would print all passwords as they are decrypted,
|
|
38
|
+
# which is not safe, so we disable propagation on the loggers.
|
|
39
|
+
# Propagation needs to be set to 0 instead of disabling the
|
|
40
|
+
# logger or setting the loglevel higher because of how the
|
|
41
|
+
# etos library sets up logging.
|
|
42
|
+
logging.getLogger("JSONTas").propagate = 0
|
|
43
|
+
logging.getLogger("Dataset").propagate = 0
|
etos_test_runner/etr.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# Copyright Axis Communications AB.
|
|
3
|
+
#
|
|
4
|
+
# For a full list of individual contributors, please see the commit history.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
# -*- coding: utf-8 -*-
|
|
18
|
+
"""ETOS test runner module."""
|
|
19
|
+
import sys
|
|
20
|
+
import logging
|
|
21
|
+
import os
|
|
22
|
+
import signal
|
|
23
|
+
import importlib
|
|
24
|
+
import pkgutil
|
|
25
|
+
from typing import Optional, Union
|
|
26
|
+
from pprint import pprint
|
|
27
|
+
from collections import OrderedDict
|
|
28
|
+
|
|
29
|
+
from etos_lib import ETOS
|
|
30
|
+
from etos_lib.logging.logger import FORMAT_CONFIG
|
|
31
|
+
from jsontas.jsontas import JsonTas
|
|
32
|
+
|
|
33
|
+
from etos_test_runner.lib.testrunner import TestRunner
|
|
34
|
+
from etos_test_runner.lib.iut import Iut
|
|
35
|
+
from etos_test_runner.lib.custom_dataset import CustomDataset
|
|
36
|
+
from etos_test_runner.lib.decrypt import Decrypt, decrypt
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Remove spam from pika.
|
|
40
|
+
logging.getLogger("pika").setLevel(logging.WARNING)
|
|
41
|
+
|
|
42
|
+
_LOGGER = logging.getLogger(__name__)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ETR:
|
|
46
|
+
"""ETOS Test Runner."""
|
|
47
|
+
|
|
48
|
+
context = None
|
|
49
|
+
|
|
50
|
+
def __init__(self) -> None:
|
|
51
|
+
"""Initialize ETOS library and start eiffel publisher."""
|
|
52
|
+
self.etos = ETOS("ETOS Test Runner", os.getenv("HOSTNAME"), "ETOS Test Runner")
|
|
53
|
+
if os.getenv("ETOS_ENCRYPTION_KEY"):
|
|
54
|
+
os.environ["RABBITMQ_PASSWORD"] = decrypt(
|
|
55
|
+
os.environ["RABBITMQ_PASSWORD"], os.getenv("ETOS_ENCRYPTION_KEY")
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
self.etos.config.rabbitmq_publisher_from_environment()
|
|
59
|
+
self.etos.config.set("etos_rabbitmq_password", os.environ.get("ETOS_RABBITMQ_PASSWORD"))
|
|
60
|
+
# ETR will print the entire environment just before executing.
|
|
61
|
+
# Hide the password.
|
|
62
|
+
os.environ["RABBITMQ_PASSWORD"] = "*********"
|
|
63
|
+
os.environ["ETOS_RABBITMQ_PASSWORD"] = "*********"
|
|
64
|
+
|
|
65
|
+
self.etos.start_publisher()
|
|
66
|
+
self.environment_id = os.getenv("ENVIRONMENT_ID")
|
|
67
|
+
|
|
68
|
+
signal.signal(signal.SIGTERM, self.graceful_shutdown)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def graceful_shutdown(*_) -> None:
|
|
72
|
+
"""Catch sigterm."""
|
|
73
|
+
raise Exception("ETR has been terminated.") # pylint:disable=broad-exception-raised
|
|
74
|
+
|
|
75
|
+
def download_and_load(self, sub_suite_url: str) -> None:
|
|
76
|
+
"""Download and load test json.
|
|
77
|
+
|
|
78
|
+
:param sub_suite_url: URL to where the sub suite information exists.
|
|
79
|
+
"""
|
|
80
|
+
response = self.etos.http.get(sub_suite_url)
|
|
81
|
+
json_config = response.json(object_pairs_hook=OrderedDict)
|
|
82
|
+
dataset = CustomDataset()
|
|
83
|
+
dataset.add("decrypt", Decrypt)
|
|
84
|
+
config = JsonTas(dataset).run(json_config)
|
|
85
|
+
|
|
86
|
+
# ETR will print the entire environment just before executing.
|
|
87
|
+
# Hide the encryption key.
|
|
88
|
+
if os.getenv("ETOS_ENCRYPTION_KEY"):
|
|
89
|
+
os.environ["ETOS_ENCRYPTION_KEY"] = "*********"
|
|
90
|
+
|
|
91
|
+
self.etos.config.set("test_config", config)
|
|
92
|
+
self.etos.config.set("context", config.get("context"))
|
|
93
|
+
self.etos.config.set("artifact", config.get("artifact"))
|
|
94
|
+
self.etos.config.set("main_suite_id", config.get("test_suite_started_id"))
|
|
95
|
+
self.etos.config.set("suite_id", config.get("suite_id"))
|
|
96
|
+
|
|
97
|
+
def _run_tests(self) -> Union[int, dict]:
|
|
98
|
+
"""Run tests in ETOS test runner.
|
|
99
|
+
|
|
100
|
+
:return: Results of test runner execution.
|
|
101
|
+
"""
|
|
102
|
+
iut = Iut(self.etos.config.get("test_config").get("iut"))
|
|
103
|
+
test_runner = TestRunner(iut, self.etos)
|
|
104
|
+
return test_runner.execute()
|
|
105
|
+
|
|
106
|
+
def load_plugins(self) -> None:
|
|
107
|
+
"""Load plugins from environment using the name etr_."""
|
|
108
|
+
disable_plugins = os.getenv("DISABLE_PLUGINS")
|
|
109
|
+
disabled_plugins = []
|
|
110
|
+
if disable_plugins:
|
|
111
|
+
disabled_plugins = disable_plugins.split(",")
|
|
112
|
+
|
|
113
|
+
discovered_plugins = {
|
|
114
|
+
name: importlib.import_module(name)
|
|
115
|
+
for _, name, _ in pkgutil.iter_modules()
|
|
116
|
+
if name.startswith("etr_") and name not in disabled_plugins
|
|
117
|
+
}
|
|
118
|
+
plugins = []
|
|
119
|
+
for name, module in discovered_plugins.items():
|
|
120
|
+
_LOGGER.info("Loading plugin: %r", name)
|
|
121
|
+
if not hasattr(module, "ETRPlugin"):
|
|
122
|
+
raise AttributeError(f"{name} does not have an ETRPlugin class!")
|
|
123
|
+
plugins.append(module.ETRPlugin(self.etos))
|
|
124
|
+
self.etos.config.set("plugins", plugins)
|
|
125
|
+
|
|
126
|
+
def get_sub_suite_url(self, environment_id: str) -> Optional[str]:
|
|
127
|
+
"""Get sub suite from ETOS environment defined event.
|
|
128
|
+
|
|
129
|
+
:param environment_id: ID of th environment defined event.
|
|
130
|
+
:return: URL for sub suite.
|
|
131
|
+
"""
|
|
132
|
+
query = (
|
|
133
|
+
"""
|
|
134
|
+
{
|
|
135
|
+
environmentDefined(search: "{'meta.id': '%s'}") {
|
|
136
|
+
edges {
|
|
137
|
+
node {
|
|
138
|
+
data {
|
|
139
|
+
uri
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
"""
|
|
146
|
+
% environment_id
|
|
147
|
+
)
|
|
148
|
+
# Timeout can be configured using ETOS_DEFAULT_WAIT_TIMEOUT environment variable
|
|
149
|
+
# Default timeout is 60s.
|
|
150
|
+
wait_generator = self.etos.utils.wait(self.etos.graphql.execute, query=query)
|
|
151
|
+
for response in wait_generator:
|
|
152
|
+
if response:
|
|
153
|
+
try:
|
|
154
|
+
_, environment_defined = next(
|
|
155
|
+
self.etos.graphql.search_for_nodes(response, "environmentDefined")
|
|
156
|
+
)
|
|
157
|
+
except StopIteration:
|
|
158
|
+
continue
|
|
159
|
+
return environment_defined["data"]["uri"]
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
def run_etr(self) -> Union[int, dict]:
|
|
163
|
+
"""Send activity events and run ETR.
|
|
164
|
+
|
|
165
|
+
:return: Result of testrunner execution.
|
|
166
|
+
"""
|
|
167
|
+
_LOGGER.info("Starting ETR.")
|
|
168
|
+
sub_suite_url = self.get_sub_suite_url(self.environment_id)
|
|
169
|
+
if sub_suite_url is None:
|
|
170
|
+
raise TimeoutError(
|
|
171
|
+
f"Could not get sub suite environment event with id {self.environment_id!r}"
|
|
172
|
+
)
|
|
173
|
+
self.download_and_load(sub_suite_url)
|
|
174
|
+
FORMAT_CONFIG.identifier = self.etos.config.get("suite_id")
|
|
175
|
+
self.load_plugins()
|
|
176
|
+
try:
|
|
177
|
+
activity_name = self.etos.config.get("test_config").get("name")
|
|
178
|
+
triggered = self.etos.events.send_activity_triggered(activity_name)
|
|
179
|
+
self.etos.events.send_activity_started(triggered)
|
|
180
|
+
result = self._run_tests()
|
|
181
|
+
except Exception as exc: # pylint:disable=broad-except
|
|
182
|
+
self.etos.events.send_activity_finished(
|
|
183
|
+
triggered, {"conclusion": "FAILED", "description": str(exc)}
|
|
184
|
+
)
|
|
185
|
+
raise
|
|
186
|
+
self.etos.events.send_activity_finished(triggered, {"conclusion": "SUCCESSFUL"})
|
|
187
|
+
_LOGGER.info("ETR finished.")
|
|
188
|
+
return result
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def main() -> None:
|
|
192
|
+
"""Start ETR."""
|
|
193
|
+
etr = ETR()
|
|
194
|
+
result = etr.run_etr()
|
|
195
|
+
if isinstance(result, dict):
|
|
196
|
+
pprint(result)
|
|
197
|
+
_LOGGER.info("Done. Exiting")
|
|
198
|
+
_LOGGER.info(result)
|
|
199
|
+
sys.exit(result)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def run():
|
|
203
|
+
"""Entry point to ETR."""
|
|
204
|
+
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
|
205
|
+
main()
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
if __name__ == "__main__":
|
|
209
|
+
run()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright 2020 Axis Communications AB.
|
|
2
|
+
#
|
|
3
|
+
# For a full list of individual contributors, please see the commit history.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
"""ETOS test runner common helpers."""
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Copyright 2020 Axis Communications AB.
|
|
3
|
+
#
|
|
4
|
+
# For a full list of individual contributors, please see the commit history.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright Axis Communications AB.
|
|
2
|
+
#
|
|
3
|
+
# For a full list of individual contributors, please see the commit history.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
"""Custom dataset module."""
|
|
17
|
+
from jsontas.dataset import Dataset
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CustomDataset(Dataset):
|
|
21
|
+
"""Custom dataset for ETR to decrypt secrets.
|
|
22
|
+
|
|
23
|
+
This custom dataset removes all default JsonTas datastructures
|
|
24
|
+
as we are going to run JsonTas on the sub suite information
|
|
25
|
+
retrieved from the environment provider.
|
|
26
|
+
This sub suite information is quite large and if we keep the
|
|
27
|
+
default datastructures the ETR would be susceptible to remote
|
|
28
|
+
code execution. This custom dataset shall only be used when
|
|
29
|
+
decrypting secrets.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self):
|
|
33
|
+
"""Initialize an empty dataset."""
|
|
34
|
+
super().__init__()
|
|
35
|
+
# pylint:disable=unused-private-member
|
|
36
|
+
# It is used by the parent class.
|
|
37
|
+
self.__dataset = {}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright Axis Communications AB.
|
|
2
|
+
#
|
|
3
|
+
# For a full list of individual contributors, please see the commit history.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
"""JSONTas decrypt string data structure module."""
|
|
17
|
+
import os
|
|
18
|
+
from cryptography.fernet import Fernet
|
|
19
|
+
from jsontas.data_structures.datastructure import DataStructure
|
|
20
|
+
|
|
21
|
+
# pylint:disable=too-few-public-methods
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def decrypt(value, key):
|
|
25
|
+
"""Decrypt a string.
|
|
26
|
+
|
|
27
|
+
:param value: Data to decrypt.
|
|
28
|
+
:type value: str
|
|
29
|
+
:param key: Encryption key to decrypt data with.
|
|
30
|
+
:type key: str
|
|
31
|
+
:return: Decrypted data.
|
|
32
|
+
:rtype: str
|
|
33
|
+
"""
|
|
34
|
+
return Fernet(key).decrypt(value).decode()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Decrypt(DataStructure):
|
|
38
|
+
"""Decrypt an encrypted string."""
|
|
39
|
+
|
|
40
|
+
def execute(self):
|
|
41
|
+
"""Execute datastructure.
|
|
42
|
+
|
|
43
|
+
:return: Name of key. None, to tel JSONTas to not override key name, and decrypted value.
|
|
44
|
+
"""
|
|
45
|
+
key = os.getenv("ETOS_ENCRYPTION_KEY")
|
|
46
|
+
assert key is not None, "ETOS_ENCRYPTION_KEY environment variable must be set"
|
|
47
|
+
return None, decrypt(self.data.get("value"), key)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Copyright 2020 Axis Communications AB.
|
|
3
|
+
#
|
|
4
|
+
# For a full list of individual contributors, please see the commit history.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Copyright Axis Communications AB.
|
|
2
|
+
#
|
|
3
|
+
# For a full list of individual contributors, please see the commit history.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
# -*- coding: utf-8 -*-
|
|
17
|
+
"""ETOS internal message bus module."""
|
|
18
|
+
import os
|
|
19
|
+
from etos_lib import ETOS
|
|
20
|
+
from etos_lib.logging.log_publisher import RabbitMQLogPublisher
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class EventPublisher:
|
|
24
|
+
"""EventPublisher helps in sending events to the internal ETOS message bus."""
|
|
25
|
+
|
|
26
|
+
disabled = False
|
|
27
|
+
|
|
28
|
+
def __init__(self, etos: ETOS):
|
|
29
|
+
"""Set up, but do not start, the RabbitMQ publisher."""
|
|
30
|
+
if os.getenv("DISABLE_EVENT_PUBLISHING", "false").lower() == "true":
|
|
31
|
+
self.disabled = True
|
|
32
|
+
publisher = etos.config.get("event_publisher")
|
|
33
|
+
if self.disabled is False and publisher is None:
|
|
34
|
+
config = etos.config.etos_rabbitmq_publisher_data()
|
|
35
|
+
# This password should already be decrypted when setting up the logging.
|
|
36
|
+
config["password"] = etos.config.get("etos_rabbitmq_password")
|
|
37
|
+
publisher = RabbitMQLogPublisher(**config, routing_key=None)
|
|
38
|
+
etos.config.set("event_publisher", publisher)
|
|
39
|
+
self.publisher = publisher
|
|
40
|
+
self.identifier = etos.config.get("suite_id")
|
|
41
|
+
|
|
42
|
+
def __del__(self):
|
|
43
|
+
"""Close the RabbitMQ publisher."""
|
|
44
|
+
self.close()
|
|
45
|
+
|
|
46
|
+
def close(self):
|
|
47
|
+
"""Close the RabbitMQ publisher if it is started."""
|
|
48
|
+
if self.publisher is not None and self.publisher.is_alive():
|
|
49
|
+
self.publisher.wait_for_unpublished_events()
|
|
50
|
+
self.publisher.close()
|
|
51
|
+
self.publisher.wait_close()
|
|
52
|
+
|
|
53
|
+
def publish(self, event: dict):
|
|
54
|
+
"""Publish an event to the ETOS internal message bus."""
|
|
55
|
+
if self.disabled:
|
|
56
|
+
return
|
|
57
|
+
if self.publisher is None:
|
|
58
|
+
return
|
|
59
|
+
if not self.publisher.running:
|
|
60
|
+
self.publisher.start()
|
|
61
|
+
routing_key = f"{self.identifier}.event.{event.get('event')}"
|
|
62
|
+
self.publisher.send_event(event, routing_key=routing_key)
|