Skip to content

Commit

Permalink
[AAP-9301] Added msg/var support in debug action (#377)
Browse files Browse the repository at this point in the history
https://issues.redhat.com/browse/AAP-9301

The debug action supports msg and var attributes to display
single/multiple messages or variables akin to ansible debug builtin. The
msg supports an array of messages.
This removes the need for a separate echo command. The echo is
equivalent to
```
action:
   debug:
     msg: .....
```
  • Loading branch information
mkanoor authored Feb 22, 2023
1 parent 0f882d3 commit 36ce184
Show file tree
Hide file tree
Showing 31 changed files with 275 additions and 203 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Support multiple actions for a rule
- Support for search/match/regex
- Support for graceful shutdown, timeout to allow actions to complete
- Removed the echo command in favor of debug with msg

### Fixed

Expand Down
59 changes: 22 additions & 37 deletions ansible_rulebook/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from typing import Callable, Dict, List, Optional, Union

import ansible_runner
import dpath
import janus
import yaml
from drools import ruleset as lang
Expand Down Expand Up @@ -75,13 +76,27 @@ async def none(


async def debug(event_log, **kwargs):
print(get_horizontal_rule("="))
print("kwargs:")
pprint(kwargs)
print(get_horizontal_rule("="))
print("facts:")
pprint(lang.get_facts(kwargs["source_ruleset_name"]))
print(get_horizontal_rule("="))
if "msg" in kwargs:
messages = kwargs.get("msg")
if not isinstance(messages, list):
messages = [messages]
for msg in messages:
print(msg)
elif "var" in kwargs:
key = kwargs.get("var")
try:
print(dpath.get(kwargs.get("variables"), key, separator="."))
except KeyError:
logger.error("Key %s not found in variable pool", key)
return
else:
print(get_horizontal_rule("="))
print("kwargs:")
pprint(kwargs)
print(get_horizontal_rule("="))
print("facts:")
pprint(lang.get_facts(kwargs["source_ruleset_name"]))
print(get_horizontal_rule("="))
sys.stdout.flush()
await event_log.put(
dict(
Expand Down Expand Up @@ -131,35 +146,6 @@ async def print_event(
)


async def echo(
event_log,
inventory: Dict,
hosts: List,
variables: Dict,
project_data_file: str,
source_ruleset_name: str,
source_rule_name: str,
ruleset: str,
name: Optional[str] = None,
message: Optional[str] = None,
):

print(str(datetime.now()) + " : " + message)
sys.stdout.flush()
await event_log.put(
dict(
type="Action",
action="echo",
activation_id=settings.identifier,
ruleset=source_ruleset_name,
rule=source_rule_name,
playbook_name=name,
run_at=str(datetime.utcnow()),
matching_events=_get_events(variables),
)
)


async def set_fact(
event_log,
inventory: Dict,
Expand Down Expand Up @@ -816,7 +802,6 @@ async def shutdown(
run_module=run_module,
run_job_template=run_job_template,
shutdown=shutdown,
echo=echo,
)


Expand Down
58 changes: 33 additions & 25 deletions ansible_rulebook/schema/ruleset_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@
{"$ref": "#/$defs/print-event-action"},
{"$ref": "#/$defs/debug-action"},
{"$ref": "#/$defs/none-action"},
{"$ref": "#/$defs/shutdown-action"},
{"$ref": "#/$defs/echo-action"}
{"$ref": "#/$defs/shutdown-action"}
]
}
},
Expand All @@ -125,8 +124,7 @@
{"$ref": "#/$defs/print-event-action"},
{"$ref": "#/$defs/debug-action"},
{"$ref": "#/$defs/none-action"},
{"$ref": "#/$defs/shutdown-action"},
{"$ref": "#/$defs/echo-action"}
{"$ref": "#/$defs/shutdown-action"}
]
}
},
Expand Down Expand Up @@ -340,36 +338,46 @@
],
"additionalProperties": false
},
"debug-msg": {
"type": "object",
"properties": {
"msg": {
"anyOf": [
{"type": "string"},
{"type": "array",
"items": {"type": "string"}
}
]
}
},
"additionalProperties": false

},
"debug-var": {
"type": "object",
"properties": {
"var": { "type": "string" }
},
"additionalProperties": false
},

"debug-action": {
"type": "object",
"properties": {
"debug": {
"type": ["object","null"]
}
"anyOf": [
{"$ref": "#/$defs/debug-msg"},
{"$ref": "#/$defs/debug-var"},
{"type": "null" }
]
}
},
"additionalProperties": false,
"required": [
"debug"
]
},
"echo-action": {
"type": "object",
"properties": {
"echo": {
"type": ["object"],
"properties": {
"message": {"type": "string" }
},
"additionalProperties": false
},
"required": [
"message"
]
},
"required": [
"echo"
],
"additionalProperties": false
},

"none-action": {
"type": "object",
"properties": {
Expand Down
63 changes: 44 additions & 19 deletions docs/actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ The following actions are supported:
- `shutdown`_
- `debug`_
- `none`_
- `echo`_

run_playbook
************
Expand Down Expand Up @@ -364,31 +363,57 @@ When a rule's condition(s) are satisfied we get the results back as:
debug
*****
Write the event to stdout
It accepts an arbitrary dict that it's injected into the event to be printed

none
****
No action, useful when writing tests
No arguments needed

echo
****
.. list-table:: Write a user specified message to stdout
.. list-table:: debug ansible-rulebook
:widths: 25 150 10
:header-rows: 1

* - Name
- Description
- Required
* - message
- A terse message to display to stdout
- Yes
* - msg
- A simple string or an array of strings, which can have references to event or events
- No
* - var
- The variable to print, which can have references to event or events. Using {{ }} is optional.
- No

| The debug action tries to mimic the debug command in ansible.
| If no arguments are provided it prints the matching events along with other important properties
| **msg** and **var** are mutually exclusive, you can have only 1 of them in the debug
| msg can be a single string or an array of strings, with references to event or events.
| With var using the Jinja style braces is optional like shown in the example below
Example:

.. code-block:: yaml
.. code-block:: yaml
action:
echo:
message: Hello World
name: debug with single message
condition: event.i >= 5
action:
debug:
msg: Simple debug message
.. code-block:: yaml
name: debug with multiple messages
condition: event.i >= 5
action:
debug:
msg:
- "Message 1 {{ event }}"
- Second Message
.. code-block:: yaml
name: debug with var
condition: event.i >= 5
action:
debug:
var: event.i
none
****
No action, useful when writing tests
No arguments needed
16 changes: 8 additions & 8 deletions docs/conditions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,8 @@ Check if an item exists in a list based on a test
name: check if an item exist in list
condition: event.levels is select('>=', 10)
action:
echo:
message: The list has an item with the value greater than or equal to 10
debug:
msg: The list has an item with the value greater than or equal to 10
| In the above example "levels" is a list of integers e.g. [1,2,3,20], the test says
| check if any item exists in the list with a value >= 10. This test passes because
Expand All @@ -632,8 +632,8 @@ Check if an item does not exist in a list based on a test
name: check if an item does not exist in list
condition: event.levels is not select('>=', 10)
action:
echo:
message: The list does not have item with the value greater than or equal to 10
debug:
msg: The list does not have item with the value greater than or equal to 10
| In the above example "levels" is a list of integers e.g. [1,2,3], the test says
| check if *no* item exists with a value >= 10. This test passes because none of the items
Expand All @@ -654,8 +654,8 @@ Checking if an object exists in a list based on a test
name: check if an object exist in list
condition: event.objects is selectattr('age', '>=', 20)
action:
echo:
message: An object with age greater than 20 found
debug:
msg: An object with age greater than 20 found
| In the above example "objects" is a list of object's, with multiple properties. One of the
| properties is age, the test says check if any object exists in the list with an age >= 20.
Expand All @@ -668,8 +668,8 @@ Checking if an object does not exist in a list based on a test
name: check if an object does not exist in list
condition: event.objects is not selectattr('age', '>=', 20)
action:
echo:
message: No object with age greater than 20 found
debug:
msg: No object with age greater than 20 found
| In the above example "objects" is a list of object's, with multiple properties. One of the
| properties is age, the test says check if *no* object exists in the list with an age >= 20.
Expand Down
4 changes: 2 additions & 2 deletions docs/variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Let's take the following example rulebook:
- name: Say Hello
condition: event.i == vars.match_this_int
action:
echo:
message: "Hi, I'm {{ MY_NAME }}."
debug:
msg: "Hi, I'm {{ MY_NAME }}."
In this rulebook we use three different variables. One, **MY_NAME**, we will supply using an environment variable.
The other two will be supplied in a file called `vars.yml` which looks like this:
Expand Down
2 changes: 1 addition & 1 deletion tests/asts/rules_with_assignment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- Action:
action: debug
action_args:
events_event: '{{events.first}}'
var: events.first
condition:
AllCondition:
- AssignmentExpression:
Expand Down
2 changes: 1 addition & 1 deletion tests/asts/rules_with_assignment2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- Action:
action: debug
action_args:
events_event: '{{events.first}}'
var: events.first
condition:
AllCondition:
- AssignmentExpression:
Expand Down
6 changes: 0 additions & 6 deletions tests/e2e/files/rulebooks/actions/test_actions_sanity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
rulebook_scope: same_ruleset
- action: "check_retract_fact"
rulebook_scope: same_ruleset
- action: "echo"
rules:
- name: run_playbook
condition: event.action == "run_playbook"
Expand Down Expand Up @@ -111,11 +110,6 @@
module_args:
msg: "Retracted fact in same ruleset, this should not be printed"

- name: echo
condition: event.action == "echo"
action:
echo:
message: "Echo action executed"

- name: Second ruleset
hosts: all
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/files/rulebooks/actions/test_run_playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@
event.post_processing_state == "Complete" and
event.post_processing_host == "simba"
action:
echo:
message: "Post-processing complete on {{ event.post_processing_host }}"
debug:
msg: "Post-processing complete on {{ event.post_processing_host }}"
5 changes: 1 addition & 4 deletions tests/e2e/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ def test_actions_sanity():
* post_event
* set_fact
* retract_fact
* echo
Each rule has specific logic to be executed only one time
and each action produces a specific output to be verified.
"""
Expand Down Expand Up @@ -89,10 +88,8 @@ def test_actions_sanity():
not in result.stdout
), "retract_fact action failed"

assert "Echo action executed" in result.stdout

assert (
len(result.stdout.splitlines()) == 43
len(result.stdout.splitlines()) == 42
), "unexpected output from the rulebook"


Expand Down
4 changes: 2 additions & 2 deletions tests/examples/48_echo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
- name: r1
condition: event.i == 1
action:
echo:
message: Hurray it works
debug:
msg: Hurray it works
Loading

0 comments on commit 36ce184

Please sign in to comment.