An integration layer allowing Ansible Rulebook to use Drools as rule engine for rules evaluation. Drools can be invoked from Ansible either via a REST API or natively through jpy.
Assuming the following local setup:
.
├── ansible-rulebook
├── drools-ansible-rulebook-integration
└── drools_jpy
For the Python projects, creating a common, shared virtual environment instance is strongly advised, in order to be shared between drools_jpy
and ansible-rulebook
.
You can opt for ansible-rulebook to "borrow" the venv from drools_jpy.
Another strategy is to use a venv strategically placed (personally used ~/venv/bin/activate
).
To create the venv:
python3 -m venv {destination directory}
e.g.:
python3 -m venv ~/venv
Ref: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments
Assuming the Python requirements were already installed for the projects:
- https://ansible.readthedocs.io/projects/rulebook/en/stable/development_environment.html
- https://github.com/ansible/drools_jpy#setup-and-testing
The following steps illustrate how to perform end-to-end testing.
Build locally with Maven, then copy the runtime JAR to drools_jpy:
(from drools-ansible-rulebook-integration
)
mvn clean install
cp drools-ansible-rulebook-integration-runtime/target/drools-ansible-rulebook-integration-runtime-1.0.6-SNAPSHOT.jar ../drools_jpy/src/drools/jars/
Use the shared venv, run the test with very-verbose and non-caputuring output, following by building (in venv site):
(from drools_jpy
)
source ~/venv/bin/activate
pytest -vv -s
python3 -m pip install .
Use the same shared venv (so to find the specific version of drools_jpy), run the tests:
(from ansible-rulebook
)
pip install -e .
pip install -r requirements_dev.txt
pytest -m "e2e" -n auto
pytest -m "not e2e and not long_run" -vv -n auto
You can always run all the tests with:
pytest
An example of the strategy in practice: #64
You will need:
- Java 11+ installed
- Environment variable JAVA_HOME set accordingly
- Maven 3.8.1+ installed
When using native image compilation, you will also need:
- GraalVM 22.1.0 installed
- Environment variable GRAALVM_HOME set accordingly
- Note that GraalVM native image compilation typically requires other packages (glibc-devel, zlib-devel and gcc) to be installed too. You also need 'native-image' installed in GraalVM (using 'gu install native-image'). Please refer to GraalVM installation documentation for more details.
mvn clean install
cd drools-ansible-rulebook-integration-core-rest
mvn clean compile quarkus:dev
mvn clean install
cd drools-ansible-rulebook-integration-core-rest
java -jar target/quarkus-app/quarkus-run.jar
Note that this requires GRAALVM_HOME to point to a valid GraalVM installation
mvn clean install
cd drools-ansible-rulebook-integration-core-rest
mvn clean package -Pnative
To run the generated native executable, generated in target/
, execute
./target/drools-ansible-rulebook-integration-core-rest-1.0.6-SNAPSHOT-runner
Note: This does not yet work on Windows, GraalVM and Quarkus should be rolling out support for Windows soon.
You can take a look at the OpenAPI definition - automatically generated and included in this service - to determine all available operations exposed by this service. For easy readability you can visualize the OpenAPI definition file using a UI tool like for example available Swagger UI.
In addition, various clients to interact with this service can be easily generated using this OpenAPI definition.
When running in either Quarkus Development or Native mode, we also leverage the Quarkus OpenAPI extension that exposes Swagger UI that you can use to look at available REST endpoints and send test requests.
Creates a rules executor with the set of rules defined in the json payload as in the following example:
curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{
"rules": [
{"Rule": {
"name": "R1",
"condition": "sensu.data.i == 1",
"action": {
"assert_fact": {
"ruleset": "Test rules4",
"fact": {
"j": 1
}
}
}
}},
{"Rule": {
"name": "R2",
"condition": "sensu.data.i == 2",
"action": {
"run_playbook": [
{
"name": "hello_playbook.yml"
}
]
}
}},
{"Rule": {
"name": "R3",
"condition":{
"any":[
{
"all":[
"sensu.data.i == 3",
"j == 2"
]
},
{
"all":[
"sensu.data.i == 4",
"j == 3"
]
}
]
},
"action": {
"retract_fact": {
"ruleset": "Test rules4",
"fact": {
"j": 3
}
}
}
}},
{"Rule": {
"name": "R4",
"condition": "j == 1",
"action": {
"post_event": {
"ruleset": "Test rules4",
"fact": {
"j": 4
}
}
}
}}
]
}' http://localhost:8080/create-rules-executor
As response it will return a simple number which is the identifier of the generated rules executor. Use this number in the URL of subsequent calls to that executor.
Note that the condition activating the rule can be a simple one, made only by one single constraint, or a nested combination of AND
and OR
like in R3
. There all
means that all conditions must be met in order to activate the rule, so it's equivalent to a AND
, while any
means that any of them is sufficient, equivalent to a OR
.
Processes the event passed in the json payload, also executing the consequences of the rules (actions) that it activates.
curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{ "sensu": { "data": { "i":1 } } }' http://localhost:8080/rules-executors/1/execute
This call, other than having the side-effect of actually executing the activated rules, returns a value representing the number of executed rules.
Processes the event passed in the json payload, without executing the consequences of the rules (actions), but only returning the list of rules activated by the event.
curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{ "sensu": { "data": { "i":1 } } }' http://localhost:8080/rules-executors/1/process
Example response:
[
{
"ruleName":"R1",
"facts":{
"sensu":{
"data":{
"i":1
}
}
}
}
]
Note that if the engine is used only in this way, i.e. only to evaluate rules but not to fire them, the rules actions are useless and they can be safely omitted in the json payload defining the rule set.