From 7d84d9cca37428f6817da2bbc60c73d21672acbb Mon Sep 17 00:00:00 2001 From: Bill Wei Date: Mon, 26 Feb 2024 06:26:47 -0500 Subject: [PATCH] feat: add raise_exception option to insert_hosts_to_meta filter (#197) --- .../event_filter/insert_hosts_to_meta.py | 27 ++++++++++++++++++- .../eda/plugins/event_source/webhook.py | 7 +++++ .../event_filter/test_insert_hosts_to_meta.py | 14 ++++++++++ tox.ini | 2 +- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/extensions/eda/plugins/event_filter/insert_hosts_to_meta.py b/extensions/eda/plugins/event_filter/insert_hosts_to_meta.py index fa33f8d7..b90a3301 100644 --- a/extensions/eda/plugins/event_filter/insert_hosts_to_meta.py +++ b/extensions/eda/plugins/event_filter/insert_hosts_to_meta.py @@ -14,6 +14,14 @@ string but contains multiple hosts, use this parameter to delimits the hosts. Treat the vale as a single host if the parameter is not present. + raise_error: Whether raise PathNotExistError if host_path does not + exist in the event. Default to false. + It is recommended to turn it on during the rulebook + development time. You can then turn it off for production. + log_error: Whether log an error message if host_path does not + exist in the event. Default to true. + You can turn if off if it is expected to have events not + having the host_path to avoid noises in the log. Example: ------- @@ -22,21 +30,33 @@ host_path: "app.target" path_separator: "." host_separator: ";" + raise_error: true + log_error: true """ from __future__ import annotations +import logging from typing import Any import dpath +LOGGER = logging.getLogger(__name__) + + +class PathNotExistError(Exception): + """Cannot find the path in the event.""" + def main( event: dict[str, Any], host_path: str | None = None, host_separator: str | None = None, path_separator: str = ".", + *, + raise_error: bool = False, + log_error: bool = True, ) -> dict[str, Any]: """Extract hosts from event data and insert into meta dict.""" if not host_path: @@ -44,8 +64,13 @@ def main( try: hosts = dpath.get(event, host_path, path_separator) - except KeyError: + except KeyError as error: # does not contain host + msg = f"Event {event} does not contain {host_path}" + if log_error: + LOGGER.error(msg) # noqa: TRY400 + if raise_error: + raise PathNotExistError(msg) from error return event if isinstance(hosts, str): diff --git a/extensions/eda/plugins/event_source/webhook.py b/extensions/eda/plugins/event_source/webhook.py index 7a6f72cd..d8daa832 100644 --- a/extensions/eda/plugins/event_source/webhook.py +++ b/extensions/eda/plugins/event_source/webhook.py @@ -3,6 +3,13 @@ An ansible-rulebook event source module for receiving events via a webhook. The message must be a valid JSON object. +The body received from the webhook post is placed under the key payload in +the data pushed to the event queue. Do not expect the host(s) in the path +"payload.meta.limit" will be automatically used to limit an ansible action +running on these hosts. Use insert_hosts_to_meta filter instead. See +https://ansible.readthedocs.io/projects/rulebook/en/latest/host_limit.html +for more details. + Arguments: --------- host: The hostname to listen to. Defaults to 0.0.0.0 (all interfaces) diff --git a/tests/unit/event_filter/test_insert_hosts_to_meta.py b/tests/unit/event_filter/test_insert_hosts_to_meta.py index 71949fb3..449086ad 100644 --- a/tests/unit/event_filter/test_insert_hosts_to_meta.py +++ b/tests/unit/event_filter/test_insert_hosts_to_meta.py @@ -1,5 +1,6 @@ import pytest +from extensions.eda.plugins.event_filter.insert_hosts_to_meta import PathNotExistError from extensions.eda.plugins.event_filter.insert_hosts_to_meta import main as hosts_main EVENT_DATA_1 = [ @@ -66,3 +67,16 @@ def test_find_hosts(data, args, expected_hosts): def test_fail_find_hosts(data, args): with pytest.raises(TypeError): hosts_main(data, **args) + + +def test_host_path_not_exist(): + event = {"app": {"target": 5000}} + host_path = "app.bad" + assert hosts_main(event, host_path=host_path) == event + + +def test_host_path_not_exist_exception(): + event = {"app": {"target": 5000}} + host_path = "app.bad" + with pytest.raises(PathNotExistError): + hosts_main(event, host_path=host_path, raise_error=True) diff --git a/tox.ini b/tox.ini index 4b70bbeb..25636ebf 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ basepython = python3.9, python3.10 [testenv:ruff] deps = -r{toxinidir}/lint_requirements.txt -commands = ruff check --select ALL --ignore INP001,RUF100,FA102 -q extensions/eda/plugins +commands = ruff check --select ALL --ignore INP001,RUF100,FA102,PLR0913 -q extensions/eda/plugins [testenv:darglint] deps = darglint