├── .dockerignore
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
├── actions
│ ├── all-tests
│ │ └── action.yml
│ ├── common-tests
│ │ └── action.yml
│ ├── e2e-tests
│ │ └── action.yml
│ ├── image-test
│ │ └── action.yml
│ ├── run-flake
│ │ └── action.yml
│ ├── run-isort
│ │ └── action.yml
│ └── setup
│ │ └── action.yml
├── dependabot.yml
└── workflows
│ ├── build-image.yml
│ ├── ci.yml
│ ├── e2e-tests.yml.disabled
│ ├── release.yml
│ └── scheduled.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── ansible_rulebook
├── __init__.py
├── __main__.py
├── action
│ ├── __init__.py
│ ├── control.py
│ ├── debug.py
│ ├── helper.py
│ ├── metadata.py
│ ├── noop.py
│ ├── pg_notify.py
│ ├── post_event.py
│ ├── print_event.py
│ ├── retract_fact.py
│ ├── run_job_template.py
│ ├── run_module.py
│ ├── run_playbook.py
│ ├── run_workflow_template.py
│ ├── runner.py
│ ├── set_fact.py
│ └── shutdown.py
├── app.py
├── cli.py
├── collection.py
├── common.py
├── condition_parser.py
├── condition_types.py
├── conf.py
├── engine.py
├── event_filter
│ ├── __init__.py
│ └── insert_meta_info.py
├── exception.py
├── job_template_runner.py
├── json_generator.py
├── messages.py
├── rule_generator.py
├── rule_set_runner.py
├── rule_types.py
├── rules_parser.py
├── schema
│ └── ruleset_schema.json
├── terminal.py
├── token.py
├── util.py
├── validators.py
├── vault.py
└── websocket.py
├── commitlint.config.js
├── demos
└── sensu-kafka-demo
│ ├── ansible-rulebook
│ ├── Dockerfile
│ └── data
│ │ ├── inventory.yml
│ │ ├── recover-fake-app.yml
│ │ └── rules.yml
│ ├── diagram.jpg
│ ├── docker-compose.yml
│ ├── instructions.md
│ └── sensu-cli
│ ├── Dockerfile
│ └── assets
│ ├── check.yml
│ └── handler.yml
├── docs
├── Makefile
├── actions.rst
├── collections.rst
├── conditions.rst
├── conf.py
├── contributing.rst
├── decision_environment.rst
├── development_environment.rst
├── drools_seq.md
├── events_and_facts.rst
├── filters.rst
├── getting_started.rst
├── host_limit.rst
├── index.rst
├── installation.rst
├── introduction.rst
├── make.bat
├── multi_events.rst
├── readme.md
├── requirements.txt
├── rulebooks.rst
├── rules.rst
├── runner.rst
├── sources.rst
├── usage.rst
└── variables.rst
├── minimal-decision-environment.yml
├── performance_test
├── 100M_event_rules.yml
├── 100k_event_rules.yml
├── 10M_event_rules.yml
├── 10k_event_rules.yml
├── 1M_event_rules.yml
├── 1k_event_rules.yml
├── generate_inventory.py
├── hello_playbook1.yml
├── inventory1.yml
├── inventory10.yml
├── inventory100.yml
├── null_rules.yml
├── perf_test.py
├── rules.yml
├── run_perf.sh
└── sources
│ └── range.py
├── pyproject.toml
├── pytest.ini
├── requirements_dev.txt
├── requirements_lint.txt
├── requirements_test.txt
├── setup.cfg
├── sonar-project.properties
├── tests
├── __init__.py
├── asts
│ ├── 01_noop.yml
│ ├── 02_debug.yml
│ ├── 03_print_event.yml
│ ├── 04_set_fact.yml
│ ├── 05_post_event.yml
│ ├── 06_retract_fact.yml
│ ├── 07_and.yml
│ ├── 08_or.yml
│ ├── 09_gt.yml
│ ├── 10_lt.yml
│ ├── 11_le.yml
│ ├── 12_ge.yml
│ ├── 13_add.yml
│ ├── 14_sub.yml
│ ├── 15_multiple_events_all.yml
│ ├── 16_multiple_events_any.yml
│ ├── 17_multiple_sources_any.yml
│ ├── 18_multiple_sources_all.yml
│ ├── 19_is_defined.yml
│ ├── 20_is_not_defined.yml
│ ├── 21_run_playbook.yml
│ ├── 23_nested_data.yml
│ ├── 24_max_attributes.yml
│ ├── 25_max_attributes_nested.yml
│ ├── 26_print_events.yml
│ ├── 27_var_root.yml
│ ├── 28_right_side_condition_template.yml
│ ├── 29_run_module.yml
│ ├── 30_run_module_missing.yml
│ ├── 31_run_module_missing_args.yml
│ ├── 32_run_module_fail.yml
│ ├── 33_run_playbook_retry.yml
│ ├── 34_run_playbook_retries.yml
│ ├── 35_multiple_rulesets_1_fired.yml
│ ├── 36_multiple_rulesets_both_fired.yml
│ ├── 37_hosts_facts.yml
│ ├── 38_shutdown.yml
│ ├── rules.yml
│ ├── rules_with_assignment.yml
│ ├── rules_with_assignment2.yml
│ ├── rules_with_multiple_conditions.yml
│ ├── rules_with_multiple_conditions2.yml
│ ├── rules_with_multiple_conditions3.yml
│ ├── rules_with_time.yml
│ ├── rules_with_timestamp.yml
│ ├── rules_with_vars.yml
│ ├── rules_without_assignment.yml
│ ├── test_filters.yml
│ ├── test_host_rules.yml
│ ├── test_rules.yml
│ ├── test_rules_multiple_hosts.yml
│ ├── test_rules_multiple_hosts2.yml
│ ├── test_rules_multiple_hosts3.yml
│ ├── test_set_facts.yml
│ └── test_simple.yml
├── conftest.py
├── data
│ ├── awx_test_data.py
│ ├── bad_source.py
│ ├── not_asyncio.py
│ ├── rulebook.yml
│ ├── test.tar
│ ├── test_cert.pem
│ ├── test_env.yml
│ ├── test_key.pem
│ └── test_vars.yml
├── e2e
│ ├── README.md
│ ├── __init__.py
│ ├── config
│ │ └── default.yml
│ ├── conftest.py
│ ├── files
│ │ ├── extra_vars
│ │ │ ├── operator_variables.yml
│ │ │ ├── test_debug.yml
│ │ │ ├── test_variables_extra_vars.yml
│ │ │ └── vaulted_variables.yml
│ │ ├── inventories
│ │ │ ├── default_inventory.ini
│ │ │ ├── default_inventory.yml
│ │ │ └── inventory_as_dir
│ │ │ │ ├── group_vars
│ │ │ │ └── customgroup.yml
│ │ │ │ ├── host_vars
│ │ │ │ └── localhost.yml
│ │ │ │ └── hosts.yml
│ │ ├── passwords
│ │ │ ├── pass1.txt
│ │ │ ├── pass2.txt
│ │ │ └── pass3.txt
│ │ ├── playbooks
│ │ │ ├── long_running.yml
│ │ │ ├── print_event.yml
│ │ │ ├── print_group_vars.yml
│ │ │ ├── print_rule_name.yml
│ │ │ ├── run_playbook_test_playbook.yml
│ │ │ ├── run_playbook_test_playbook_with_set_stats.yml
│ │ │ └── run_playbook_test_playbook_without_cacheable.yml
│ │ └── rulebooks
│ │ │ ├── actions
│ │ │ ├── test_actions_sanity.yml
│ │ │ ├── test_run_playbook.yml
│ │ │ ├── test_run_playbook_with_set_stats.yml
│ │ │ ├── test_run_playbook_without_cacheable.yml
│ │ │ ├── test_shutdown_graceful.yml
│ │ │ └── test_shutdown_now.yml
│ │ │ ├── hello_events_with_var.yml
│ │ │ ├── malformed_rulebook.yml
│ │ │ ├── operators
│ │ │ ├── test_logical_operators.yml
│ │ │ ├── test_membership_operators.yml
│ │ │ ├── test_relational_operators.yml
│ │ │ ├── test_select_operator.yml
│ │ │ ├── test_selectattr_operator.yml
│ │ │ ├── test_string_match.yml
│ │ │ ├── test_string_search_regex.yml
│ │ │ └── test_string_search_search.yml
│ │ │ ├── test_debug_no_params.yml
│ │ │ ├── test_debug_var_and_message.yml
│ │ │ ├── test_disabled_rules.yml
│ │ │ ├── test_hot_reload.yml
│ │ │ ├── test_inventory_as_dir.yml
│ │ │ ├── test_match_multiple_rules.yml
│ │ │ ├── test_process_sigint.yml
│ │ │ ├── test_process_source_end.yml
│ │ │ ├── test_source_stacktrace.yml
│ │ │ ├── test_vaulted_rulebook.yml
│ │ │ ├── test_vaulted_rulebook_interpolate.yml
│ │ │ ├── test_vaulted_v2.yml
│ │ │ ├── variables
│ │ │ └── test_variables_sanity.yml
│ │ │ └── websockets
│ │ │ └── test_websocket_range.yml
│ ├── settings.py
│ ├── test_actions.py
│ ├── test_match_multiple_rules.py
│ ├── test_non_alpha_keys.py
│ ├── test_operators.py
│ ├── test_run_module_output.py
│ ├── test_runtime.py
│ ├── test_skip_audit_events.py
│ ├── test_source_stacktrace.py
│ ├── test_variables.py
│ ├── test_vault.py
│ ├── test_websocket.py
│ ├── utils.py
│ └── utils
│ │ └── awx
│ │ ├── ansible.cfg
│ │ ├── create-cluster.yml
│ │ ├── install-awx.yml
│ │ ├── kind-config.yml
│ │ ├── readme.md
│ │ ├── requirements.txt
│ │ └── roles
│ │ └── install-awx
│ │ ├── defaults
│ │ └── main.yaml
│ │ ├── tasks
│ │ └── main.yaml
│ │ └── templates
│ │ ├── admin-password-secret.yml.j2
│ │ ├── awx.yaml.j2
│ │ └── kustomization
│ │ └── kustomization.yaml.j2
├── event_filter
│ ├── dashes_to_underscores.py
│ ├── json_filter.py
│ ├── noop.py
│ └── test_insert_meta_info.py
├── examples
│ ├── 01_noop.yml
│ ├── 02_debug.yml
│ ├── 03_print_event.yml
│ ├── 04_set_fact.yml
│ ├── 05_post_event.yml
│ ├── 06_retract_fact.yml
│ ├── 07_and.yml
│ ├── 08_or.yml
│ ├── 09_gt.yml
│ ├── 10_lt.yml
│ ├── 11_le.yml
│ ├── 12_ge.yml
│ ├── 13_add.yml
│ ├── 14_sub.yml
│ ├── 15_multiple_events_all.yml
│ ├── 16_multiple_events_any.yml
│ ├── 17_multiple_sources_any.yml
│ ├── 18_multiple_sources_all.yml
│ ├── 19_is_defined.yml
│ ├── 20_is_not_defined.yml
│ ├── 21_run_playbook.yml
│ ├── 22_run_playbook.yml
│ ├── 23_nested_data.yml
│ ├── 24_max_attributes.yml
│ ├── 25_max_attributes_nested.yml
│ ├── 26_print_events.yml
│ ├── 27_var_root.yml
│ ├── 28_right_side_condition_template.yml
│ ├── 29_run_module.yml
│ ├── 30_run_module_missing.yml
│ ├── 31_run_module_missing_args.yml
│ ├── 32_run_module_fail.yml
│ ├── 33_run_playbook_retry.yml
│ ├── 34_run_playbook_retries.yml
│ ├── 35_multiple_rulesets_1_fired.yml
│ ├── 36_multiple_rulesets_both_fired.yml
│ ├── 37_hosts_facts.yml
│ ├── 38_shutdown.yml
│ ├── 39_is_defined.yml
│ ├── 40_in.yml
│ ├── 41_not_in.yml
│ ├── 42_contains.yml
│ ├── 43_not_contains.yml
│ ├── 44_in_and.yml
│ ├── 45_in_or.yml
│ ├── 46_job_template.yml
│ ├── 47_generic_plugin.yml
│ ├── 48_echo.yml
│ ├── 49_float.yml
│ ├── 50_negation.yml
│ ├── 51_vars_namespace.yml
│ ├── 52_once_within.yml
│ ├── 53_once_within_multiple_hosts.yml
│ ├── 54_time_window.yml
│ ├── 55_not_all.yml
│ ├── 56_once_after.yml
│ ├── 57_once_after_multi.yml
│ ├── 58_string_search.yml
│ ├── 59_multiple_actions.yml
│ ├── 60_json_filter.yml
│ ├── 61_select_1.yml
│ ├── 62_select_2.yml
│ ├── 63_selectattr_1.yml
│ ├── 64_selectattr_2.yml
│ ├── 65_selectattr_3.yml
│ ├── 66_sleepy_playbook.yml
│ ├── 67_shutdown_now.yml
│ ├── 68_disabled_rule.yml
│ ├── 69_enhanced_debug.yml
│ ├── 70_null.yml
│ ├── 72_set_fact_with_type.yml
│ ├── 73_mix_and_match_list.yml
│ ├── 74_self_referential.yml
│ ├── 75_all_conditions.yml
│ ├── 76_all_conditions.yml
│ ├── 77_default_events_ttl.yml
│ ├── 78_complete_retract_fact.yml
│ ├── 79_workflow_template.yml
│ ├── 80_match_multiple_rules.yml
│ ├── 81_match_single_rule.yml
│ ├── 82_non_alpha_keys.yml
│ ├── 83_boolean_true.yml
│ ├── 84_job_template_exclude_events.yml
│ ├── 85_workflow_template_exclude_events.yml
│ ├── 86_job_template_include_events.yml
│ ├── 87_workflow_template_include_events.yml
│ ├── 88_job_template_no_args.yml
│ ├── 89_source_error_with_msg.yml
│ ├── 90_source_error_without_msg.yml
│ ├── 91_mask_senstive_variables.yml
│ └── replays
│ │ ├── 23_nested_data
│ │ ├── 00.json
│ │ ├── 01.json
│ │ ├── 02.json
│ │ ├── 03.json
│ │ ├── 04.json
│ │ ├── 05.json
│ │ ├── 06.json
│ │ ├── 07.json
│ │ ├── 08.json
│ │ ├── 09.json
│ │ └── generate_data.py
│ │ ├── 24_max_attributes
│ │ ├── 00.json
│ │ └── generate_data.py
│ │ ├── 25_max_attributes_nested
│ │ ├── 00.json
│ │ └── generate_data.py
│ │ └── 39_is_defined
│ │ ├── 00.json
│ │ ├── 01.json
│ │ ├── 02.json
│ │ ├── 03.json
│ │ ├── 04.json
│ │ ├── 05.json
│ │ ├── 06.json
│ │ ├── 07.json
│ │ ├── 08.json
│ │ ├── 09.json
│ │ └── generate_data.py
├── generate_asts.py
├── pass1.txt
├── playbooks
│ ├── check_facts_playbook.yml
│ ├── compare_value.yml
│ ├── fail_and_succeed.yml
│ ├── hello.yml
│ ├── hello_events.yml
│ ├── hello_world_set_fact.yml
│ ├── inventory.yml
│ ├── inventory1.yml
│ ├── sleeper.yml
│ ├── validate_args_playbook.yml
│ └── vars.yml
├── rules
│ ├── rule_names_with_substitution.yml
│ ├── rules.yml
│ ├── rules_with_assignment.yml
│ ├── rules_with_assignment2.yml
│ ├── rules_with_multiple_conditions.yml
│ ├── rules_with_multiple_conditions2.yml
│ ├── rules_with_multiple_conditions3.yml
│ ├── rules_with_time.yml
│ ├── rules_with_timestamp.yml
│ ├── rules_with_vars.yml
│ ├── rules_without_assignment.yml
│ ├── test_blank_rule_name.yml
│ ├── test_blank_ruleset_name.yml
│ ├── test_combine_hosts.yml
│ ├── test_combine_hosts_module.yml
│ ├── test_duplicate_rule_names.yml
│ ├── test_duplicate_ruleset_names.yml
│ ├── test_empty_rule_names.yml
│ ├── test_filters.yml
│ ├── test_host_rules.yml
│ ├── test_kafka.yml
│ ├── test_missing_rule_names.yml
│ ├── test_missing_ruleset_name.yml
│ ├── test_multiple_sources.yml
│ ├── test_rules.yml
│ ├── test_rules_expanded_conditions.yml
│ ├── test_rules_multiple_hosts.yml
│ ├── test_rules_multiple_hosts2.yml
│ ├── test_rules_multiple_hosts3.yml
│ ├── test_rules_playbooks.yml
│ ├── test_set_facts.yml
│ ├── test_simple.yml
│ ├── test_states.yml
│ └── webserver_down.yml
├── run_examples.sh
├── sources
│ ├── __init__.py
│ ├── fail_after.py
│ ├── file.py
│ ├── generic.py
│ ├── hosts.py
│ ├── infrange.py
│ ├── log_scraper.py
│ ├── nested.py
│ ├── ping.py
│ ├── process_check.py
│ ├── range.py
│ ├── range2.py
│ ├── replay.py
│ ├── replays
│ │ ├── 01.json
│ │ ├── 02.json
│ │ ├── 03.json
│ │ ├── 04.json
│ │ └── 05.json
│ ├── source_with_exception.py
│ ├── template.py
│ ├── tick.py
│ ├── timestamp.py
│ └── url_check.py
├── test_ansible_events.py
├── test_app.py
├── test_ast.py
├── test_collection.py
├── test_controller.py
├── test_engine.py
├── test_examples.py
├── test_rules.py
├── test_simple.yml
├── test_token.py
├── test_vault.py
├── test_websocket.py
└── unit
│ ├── action
│ ├── __init__.py
│ ├── conftest.py
│ ├── playbooks
│ │ ├── fail.yml
│ │ └── rule_name.yml
│ ├── test_controller.py
│ ├── test_debug.py
│ ├── test_noop.py
│ ├── test_pg_notify.py
│ ├── test_post_event.py
│ ├── test_print_event.py
│ ├── test_retract_fact.py
│ ├── test_run_job_template.py
│ ├── test_run_module.py
│ ├── test_run_playbook.py
│ ├── test_run_workflow_template.py
│ ├── test_set_fact.py
│ └── test_shutdown.py
│ ├── test_cli.py
│ ├── test_terminal.py
│ └── test_util.py
├── tools
└── convert_to_ast.py
└── tox.ini
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | venv
3 | .venv/
4 | **/*.pyc
5 | **/__pycache__
6 | .tox
7 | .vscode/
8 | .idea/
9 | .ansible/
10 | *.egg-info/
11 | .pytest_cache/
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 4
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | charset = utf-8
11 | end_of_line = lf
12 |
13 | [*.{yml,yaml}]
14 | indent_size = 2
15 |
16 | [*.bat]
17 | indent_style = tab
18 | end_of_line = crlf
19 |
20 | [LICENSE]
21 | insert_final_newline = false
22 |
23 | [Makefile]
24 | indent_style = tab
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: For debugging help or technical support
4 | url: https://ansible-rulebook.readthedocs.io/en/latest/contributing.html
5 | about: For general debugging or technical support please see the linked section of our docs.
6 |
7 | - name: 📝 Ansible Code of Conduct
8 | url: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_template_chooser
9 | about: EDA-Controlles uses the Ansible Code of Conduct; ❤ Be nice to other members of the community. ☮ Behave.
10 |
11 | - name: 💼 For Enterprise
12 | url: https://www.ansible.com/use-cases/event-driven-automation
13 | about: Red Hat offers support for the Ansible Automation Platform
14 |
--------------------------------------------------------------------------------
/.github/actions/common-tests/action.yml:
--------------------------------------------------------------------------------
1 | name: common-tests
2 | description: run common tests for ansible-rulebook (unit and integration)
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: Setup jUnit reporter
8 | shell: bash
9 | run: |
10 | echo "GIT_SHA=$(git rev-parse "$GITHUB_SHA")" >> "$GITHUB_ENV"
11 |
12 | - name: Run common tests
13 | shell: bash
14 | run: pytest -vv -s -m "not e2e and not long_run" -vv -n auto --cov=./ --cov-report=xml --junit-xml=common-test-results.xml
15 |
16 | - name: Upload jUnit test results (APDE CI)
17 | shell: bash
18 | if: env.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL != '' && github.ref == 'refs/heads/main'
19 | run: >-
20 | http --check-status --ignore-stdin
21 | --auth "${{ env.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_USER }}:${{ env.PDE_ORG_RESULTS_UPLOAD_PASSWORD }}"
22 | -f POST "${{ env.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL }}/api/results/upload/"
23 | xunit_xml@common-test-results.xml
24 | component_name=eda
25 | git_commit_sha=${{ env.GIT_SHA }}
26 | git_repository_url="https://github.com/${{ github.repository }}"
27 |
--------------------------------------------------------------------------------
/.github/actions/e2e-tests/action.yml:
--------------------------------------------------------------------------------
1 | name: e2e-tests
2 | description: run e2e tests for ansible-rulebook
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: Setup jUnit reporter
8 | shell: bash
9 | run: |
10 | echo "GIT_SHA=$(git rev-parse "$GITHUB_SHA")" >> "$GITHUB_ENV"
11 |
12 | - name: Run e2e tests
13 | shell: bash
14 | run: pytest -m "e2e" -n auto --cov=./ --cov-report=xml --cov-append --junit-xml=e2e-test-results.xml
15 |
16 | - name: Upload jUnit test results (APDE CI)
17 | shell: bash
18 | if: env.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL != '' && github.ref == 'refs/heads/main'
19 | run: >-
20 | http --check-status --ignore-stdin
21 | --auth "${{ env.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_USER }}:${{ env.PDE_ORG_RESULTS_UPLOAD_PASSWORD }}"
22 | -f POST "${{ env.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL }}/api/results/upload/"
23 | xunit_xml@e2e-test-results.xml
24 | component_name=eda
25 | git_commit_sha=${{ env.GIT_SHA }}
26 | git_repository_url="https://github.com/${{ github.repository }}"
27 |
--------------------------------------------------------------------------------
/.github/actions/image-test/action.yml:
--------------------------------------------------------------------------------
1 | name: build-and-test-image
2 | description: Build and test the container image
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: Set up Python
8 | uses: actions/setup-python@v5
9 | with:
10 | python-version: 3.11
11 |
12 | - name: Get package version
13 | shell: bash
14 | run: |
15 | python -m pip install setuptools_scm
16 | echo "SETUPTOOLS_SCM_PRETEND_VERSION=$(python -m setuptools_scm)" >> $GITHUB_ENV
17 |
18 | - name: Set up Docker Buildx
19 | uses: docker/setup-buildx-action@v2
20 |
21 | - name: Build container image
22 | uses: docker/build-push-action@v4
23 | with:
24 | context: .
25 | platforms: linux/amd64
26 | tags: localhost/ansible-rulebook:test
27 | load: true
28 | build-args: |
29 | SETUPTOOLS_SCM_PRETEND_VERSION=${{ env.SETUPTOOLS_SCM_PRETEND_VERSION }}
30 |
31 | - name: Run tests
32 | shell: bash
33 | run: >
34 | docker run --rm localhost/ansible-rulebook:test bash -c '
35 | pip install -r requirements_test.txt &&
36 | pytest -m "e2e" -n auto'
37 |
--------------------------------------------------------------------------------
/.github/actions/run-flake/action.yml:
--------------------------------------------------------------------------------
1 | name: run-flake
2 | description: run flake8
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: Set up Python
8 | uses: actions/setup-python@v5
9 | with:
10 | python-version: "3.10"
11 |
12 | - name: Install dependencies
13 | shell: bash
14 | run: python -m pip install -r requirements_lint.txt
15 |
16 | - name: Lint with flake8
17 | shell: bash
18 | run: flake8 . --count --show-source --statistics
19 |
--------------------------------------------------------------------------------
/.github/actions/run-isort/action.yml:
--------------------------------------------------------------------------------
1 | name: run-isort
2 | description: run isort
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: Set up Python
8 | uses: actions/setup-python@v5
9 | with:
10 | python-version: "3.10"
11 |
12 | - name: Install dependencies
13 | shell: bash
14 | run: python -m pip install isort
15 |
16 | - name: Lint with isort
17 | shell: bash
18 | run: isort . --check --diff
19 |
--------------------------------------------------------------------------------
/.github/actions/setup/action.yml:
--------------------------------------------------------------------------------
1 | name: setup
2 | description: Common steps to install ansible-rulebook for CI workflows
3 |
4 | inputs:
5 | python-version:
6 | description: python version to use
7 | required: true
8 |
9 | runs:
10 | using: composite
11 | steps:
12 | - name: Install Java
13 | uses: actions/setup-java@v3
14 | with:
15 | distribution: "zulu"
16 | java-version: "17"
17 |
18 | - name: Set up Python ${{ inputs.python-version }}
19 | uses: actions/setup-python@v5
20 | with:
21 | python-version: ${{ inputs.python-version }}
22 |
23 | - name: Install package
24 | shell: bash
25 | run: python -m pip install .[production]
26 |
27 | - name: Install test dependencies
28 | shell: bash
29 | run: python -m pip install -r requirements_test.txt
30 |
31 | - name: Install `ansible.eda` collection
32 | shell: bash
33 | run: ansible-galaxy collection install git+https://github.com/ansible/event-driven-ansible
34 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: weekly
8 |
--------------------------------------------------------------------------------
/.github/workflows/e2e-tests.yml.disabled:
--------------------------------------------------------------------------------
1 | # at this stage, ci.yml run all-tests, which performs: common-tests, long_run tests, e2e-tests
2 | name: e2e tests
3 |
4 | on:
5 | push:
6 | branches:
7 | - "main"
8 | pull_request:
9 | branches:
10 | - "main"
11 | workflow_dispatch:
12 |
13 | jobs:
14 | e2e-tests:
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | python-version:
20 | - "3.9"
21 | - "3.10"
22 | - "3.11"
23 |
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v3
27 |
28 | - name: Setup
29 | uses: ./.github/actions/setup
30 | with:
31 | python-version: ${{ matrix.python-version }}
32 |
33 | - name: e2e tests
34 | uses: ./.github/actions/e2e-tests
35 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release Workflow
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | build-and-publish:
9 | runs-on: ubuntu-latest
10 | # Restrict this action only to protected tags
11 | if: github.repository == 'ansible/ansible-rulebook' && startsWith(github.event.release.tag_name, 'v')
12 | permissions:
13 | contents: write
14 | steps:
15 | - name: Check out repository
16 | uses: actions/checkout@v4
17 |
18 | - name: Set up Python
19 | uses: actions/setup-python@v5
20 | with:
21 | python-version: "3.11"
22 |
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install -U build setuptools setuptools_scm
26 |
27 | - name: Build package
28 | run: make dist
29 |
30 | - name: Upload artifacts to GitHub Release
31 | env:
32 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 | RELEASE_TAG: ${{ github.event.release.tag_name }}
34 | RELEASE_ID: ${{ github.event.release.id }}
35 | run: |
36 | gh release upload "$RELEASE_TAG" dist/*
37 |
38 | - name: Publish to PyPI
39 | uses: pypa/gh-action-pypi-publish@release/v1
40 | with:
41 | password: ${{ secrets.PYPI_API_TOKEN }}
42 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | exclude: "^docs/"
3 | repos:
4 | - repo: https://github.com/psf/black
5 | rev: 22.6.0
6 | hooks:
7 | - id: black
8 | - repo: https://github.com/pycqa/isort
9 | rev: 5.12.0
10 | hooks:
11 | - id: isort
12 | - repo: https://github.com/pycqa/flake8
13 | rev: 4.0.1
14 | hooks:
15 | - id: flake8
16 | additional_dependencies:
17 | - flake8-bugbear
18 | - repo: local
19 | hooks:
20 | - id: ajv
21 | name: ajv
22 | description: Validate JSON schema
23 | language: node
24 | types: [json]
25 | files: ^ansible_rulebook/schema/ruleset_schema.json$
26 | additional_dependencies:
27 | - ajv-cli
28 | entry: ajv compile -s
29 | - repo: https://github.com/pre-commit/pre-commit-hooks
30 | rev: v4.4.0
31 | hooks:
32 | - id: pretty-format-json
33 | language_version: python3
34 | args: ['--autofix', '--no-sort-keys', '--indent', '4']
35 | - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
36 | rev: v9.5.0
37 | hooks:
38 | - id: commitlint
39 | additional_dependencies: ['@commitlint/config-conventional']
40 | stages: [commit-msg]
41 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include AUTHORS.rst
2 | include CONTRIBUTING.rst
3 | include HISTORY.rst
4 | include LICENSE
5 | include README.rst
6 |
7 | recursive-include tests *
8 | recursive-exclude * __pycache__
9 | recursive-exclude * *.py[co]
10 |
11 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
12 |
13 | recursive-include ansible_rulebook/schema *.json
14 |
--------------------------------------------------------------------------------
/ansible_rulebook/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Top-level package for Ansible Events."""
16 |
17 | import yaml
18 |
19 |
20 | def construct_vault_encrypted_unicode(loader, node):
21 | return loader.construct_scalar(node)
22 |
23 |
24 | yaml.SafeLoader.add_constructor("!vault", construct_vault_encrypted_unicode)
25 |
--------------------------------------------------------------------------------
/ansible_rulebook/__main__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from ansible_rulebook.cli import main
16 |
17 | main()
18 |
--------------------------------------------------------------------------------
/ansible_rulebook/action/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ansible/ansible-rulebook/da1bed4a19a08e37eb45394248941156692a304f/ansible_rulebook/action/__init__.py
--------------------------------------------------------------------------------
/ansible_rulebook/action/noop.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import logging
16 |
17 | from .control import Control
18 | from .helper import Helper
19 | from .metadata import Metadata
20 |
21 | logger = logging.getLogger(__name__)
22 |
23 |
24 | class Noop:
25 | """The No Op action usually used for debugging, doesn't do anything and
26 | just sends the action status
27 | """
28 |
29 | def __init__(
30 | self,
31 | metadata: Metadata,
32 | control: Control,
33 | **action_args,
34 | ):
35 | self.helper = Helper(metadata, control, "noop")
36 | self.action_args = action_args
37 |
38 | async def __call__(self):
39 | await self.helper.send_default_status()
40 |
--------------------------------------------------------------------------------
/ansible_rulebook/event_filter/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ansible/ansible-rulebook/da1bed4a19a08e37eb45394248941156692a304f/ansible_rulebook/event_filter/__init__.py
--------------------------------------------------------------------------------
/ansible_rulebook/messages.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from dataclasses import dataclass
16 |
17 | DEFAULT_SHUTDOWN_DELAY = 60.0
18 |
19 |
20 | @dataclass(frozen=True)
21 | class Shutdown:
22 | message: str = "Not specified"
23 | delay: float = DEFAULT_SHUTDOWN_DELAY
24 | kind: str = "graceful"
25 | source_plugin: str = ""
26 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | // custom rules for commitlint
2 |
3 | module.exports = {
4 | extends: ['@commitlint/config-conventional'],
5 | rules: {
6 | 'body-max-line-length': [2, 'always', Infinity],
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/ansible-rulebook/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM quay.io/aizquier/ansible-rulebook:latest
2 |
3 | COPY ./data/* /data/
4 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/ansible-rulebook/data/inventory.yml:
--------------------------------------------------------------------------------
1 | all:
2 | hosts:
3 | localhost:
4 | ansible_connection: local
5 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/ansible-rulebook/data/recover-fake-app.yml:
--------------------------------------------------------------------------------
1 | - hosts: localhost
2 | gather_facts: false
3 | vars:
4 | app_host: fake-app
5 | app_port: 5080
6 | tasks:
7 | - name: Fix fake app
8 | ansible.builtin.uri:
9 | url: "http://{{ app_host }}:{{ app_port }}/up"
10 | register: response
11 | failed_when: response.status != 200
12 |
13 | - name: check the app is running again
14 | ansible.builtin.uri:
15 | url: "http://{{ app_host }}:{{ app_port }}/health"
16 | register: response
17 | failed_when: response.status != 200
18 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/ansible-rulebook/data/rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: sensu-kafka demo rules
3 | hosts: localhost
4 | sources:
5 | - name: kafka
6 | ansible.eda.kafka:
7 | topic: sensu-events
8 | host: broker
9 | port: 9092
10 | rules:
11 | - name: recover fake-app outage
12 | condition: event.check.metadata.name == "check-fake-app" and event.check.status == 2
13 | action:
14 | run_playbook:
15 | name: recover-fake-app.yml
16 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/diagram.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ansible/ansible-rulebook/da1bed4a19a08e37eb45394248941156692a304f/demos/sensu-kafka-demo/diagram.jpg
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/sensu-cli/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mirror.gcr.io/sensu/sensu:latest
2 |
3 | COPY assets/* /sensu-assets/
4 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/sensu-cli/assets/check.yml:
--------------------------------------------------------------------------------
1 | ---
2 | type: CheckConfig
3 | api_version: core/v2
4 | metadata:
5 | name: check-fake-app
6 | namespace: default
7 | spec:
8 | command: http-check --url http://fake-app:5080/health
9 | subscriptions:
10 | - webserver
11 | handlers:
12 | - sensu-kafka-handler
13 | interval: 5
14 | runtime_assets:
15 | - sensu/http-checks
16 | publish: true
17 |
--------------------------------------------------------------------------------
/demos/sensu-kafka-demo/sensu-cli/assets/handler.yml:
--------------------------------------------------------------------------------
1 | ---
2 | type: Handler
3 | api_version: core/v2
4 | metadata:
5 | name: sensu-kafka-handler
6 | namespace: default
7 | spec:
8 | command: sensu-kafka-handler --host broker:9092 --topic sensu-events
9 | type: pipe
10 | runtime_assets:
11 | - sensu/sensu-kafka-handler
12 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = python -msphinx
7 | SPHINXPROJ = ansible_rulebook
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/drools_seq.md:
--------------------------------------------------------------------------------
1 | ```mermaid
2 | sequenceDiagram
3 | Rulebook->>+Drools: Create Async Socket
4 | Rulebook->>+Rulebook:Create Asyncio Task
to wait for async responses
5 | Rulebook->>+Ruleset: Create Ruleset
6 | Ruleset->>+SourceQueue: Create Source Queue
7 | Ruleset->>+Sources: Start Sources with a Source Queue
8 | Ruleset->>+ActionPlanQueue: CreatePlan Queue
9 | Loop Add all rules to Ruleset
10 | Ruleset->>+Rule: Create a Rule
11 | end
12 | Ruleset->>+Drools: Create Ruleset Session
13 | Loop Till Shutdown Event
14 | Sources->>+SourceQueue: Send Events
15 | Ruleset->>+SourceQueue: Read Events
16 | Ruleset->>+Drools: Process Event
17 | Drools->>+Rule: Synchronous response
18 | Rule->>+ActionPlanQueue: Queue Actions
for dispatch
19 | Rulebook-->>+Rulebook: Handle Async Response
20 | Drools--X+Rulebook: Send Async response
with ruleset session and rule
21 | Rulebook--X+Rule: Send Async Response
22 | Rule->>+ActionPlanQueue: Queue Actions
for dispatch
23 | ActionPlanQueue-->>+Ruleset: post event/set fact
24 | Ruleset-->>+Drools: Process Event/Fact
25 | end
26 | ```
27 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to Ansible Rulebook documentation
2 | =========================================
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 | :caption: Contents:
7 |
8 | introduction
9 | getting_started
10 | installation
11 | development_environment
12 | contributing
13 | usage
14 | rulebooks
15 | rules
16 | conditions
17 | events_and_facts
18 | variables
19 | host_limit
20 | multi_events
21 | actions
22 | sources
23 | filters
24 | runner
25 | collections
26 | decision_environment
27 |
28 | Indices and tables
29 | ==================
30 | * :ref:`modindex`
31 | * :ref:`search`
32 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=python -msphinx
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | set SPHINXPROJ=ansible_rulebook
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed,
20 | echo.then set the SPHINXBUILD environment variable to point to the full
21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the
22 | echo.Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | # Some tips for documentation development
2 |
3 | - Ensure your dependencies
4 |
5 | ```
6 | pip install -r requirements_dev.txt
7 | ```
8 |
9 | - Simulate a hot-reload web server
10 |
11 | ```
12 | # install when-changed
13 | pip install git+https://github.com/joh/when-changed
14 |
15 | # rebuild with every change
16 | cd docs
17 | when-changed . -c "make clean && make html"
18 |
19 | # spin up a basic http server
20 | cd _build/html
21 | python -m http.server 3000
22 |
23 | # or install sphinx-autobuild
24 | pip install sphinx-autobuild
25 |
26 | # monitor it and auto-rebuild with every change
27 | sphinx-autobuild docs _build/html --port 3000
28 | ```
29 |
30 | - nice RST extension for vscode:
31 |
32 |
33 | ## Some useful links
34 |
35 | -
36 | -
37 | -
38 | -
39 | -
40 | -
41 | -
42 | -
43 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | # Docs
2 | sphinx
3 | sphinx-ansible-theme == 0.10.1
4 | pyyaml
5 |
--------------------------------------------------------------------------------
/docs/runner.rst:
--------------------------------------------------------------------------------
1 | ======
2 | Runner
3 | ======
4 |
5 |
6 |
7 | Work in progress
8 |
--------------------------------------------------------------------------------
/minimal-decision-environment.yml:
--------------------------------------------------------------------------------
1 | version: 3
2 |
3 | images:
4 | base_image:
5 | name: 'registry.access.redhat.com/ubi9/python-311:latest'
6 |
7 | dependencies:
8 | galaxy:
9 | collections:
10 | - ansible.eda
11 | python:
12 | - azure-servicebus
13 | - aiobotocore
14 | - aiohttp
15 | - aiokafka
16 | - gssapi
17 | - watchdog
18 | - systemd-python
19 | - dpath
20 | - ansible-rulebook
21 | ansible_core:
22 | package_pip: ansible-core~=2.16.0
23 | ansible_runner:
24 | package_pip: ansible-runner
25 | system:
26 | - java-17-openjdk-devel [platform:rpm]
27 |
--------------------------------------------------------------------------------
/performance_test/100M_event_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "100M event rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 100000000
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/100k_event_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "10k event rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 100000
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/10M_event_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "10M event rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 10000000
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/10k_event_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "10k event rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 10000
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/1M_event_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "1M event rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 1000000
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/1k_event_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "1k event rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 1000
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/hello_playbook1.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: A playbook
3 | hosts: all
4 | gather_facts: false
5 | tasks:
6 | - name:
7 | debug:
8 | msg: 'Hello event {{ansible_eda.event}}'
9 | ...
10 |
--------------------------------------------------------------------------------
/performance_test/inventory1.yml:
--------------------------------------------------------------------------------
1 | all:
2 | hosts:
3 | localhost0:
4 | ansible_host: localhost
5 |
6 |
--------------------------------------------------------------------------------
/performance_test/inventory10.yml:
--------------------------------------------------------------------------------
1 | all:
2 | hosts:
3 | localhost0:
4 | ansible_host: localhost
5 | localhost1:
6 | ansible_host: localhost
7 | localhost2:
8 | ansible_host: localhost
9 | localhost3:
10 | ansible_host: localhost
11 | localhost4:
12 | ansible_host: localhost
13 | localhost5:
14 | ansible_host: localhost
15 | localhost6:
16 | ansible_host: localhost
17 | localhost7:
18 | ansible_host: localhost
19 | localhost8:
20 | ansible_host: localhost
21 | localhost9:
22 | ansible_host: localhost
23 |
24 |
--------------------------------------------------------------------------------
/performance_test/null_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "Null rules"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/performance_test/rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Host Rules Perf
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | fact:
14 | j: 1
15 | - name: r2
16 | condition: event.i == 2
17 | action:
18 | run_playbook:
19 | name: ./hello_playbook1.yml
20 | - name: r3
21 | condition: event.i == 3
22 | action:
23 | retract_fact:
24 | fact:
25 | j: 3
26 | - name: r4
27 | condition: event.i == 4
28 | action:
29 | post_event:
30 | event:
31 | j: 4
32 | - name: r5
33 | condition: event.j is defined
34 | action:
35 | none:
36 |
--------------------------------------------------------------------------------
/performance_test/run_perf.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ulimit -Sn 10000
3 | #Argtest
4 | #
5 |
6 | now=$(date +"%Y%m%d%H%M%S")
7 |
8 | ./perf_test.py "perf${now}.csv" x x x x --only-header
9 | for t in rules.yml null_rules.yml 1k_event_rules.yml 10k_event_rules.yml 100k_event_rules.yml 1M_event_rules.yml 10M_event_rules.yml 100M_event_rules.yml
10 | do
11 | for n in 1 10 100
12 | do
13 | ./perf_test.py "perf${now}.csv" "ansible-rulebook -i inventory${n}.yml -S sources --rulebook ${t}" ansible-rulebook ${t} ${n} --no-header
14 | done
15 | done
16 |
--------------------------------------------------------------------------------
/performance_test/sources/range.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import asyncio
16 | from typing import Any, Dict
17 |
18 |
19 | async def main(queue: asyncio.Queue, args: Dict[str, Any]):
20 | delay = args.get("delay", 0)
21 |
22 | for i in range(int(args["limit"])):
23 | await queue.put(dict(i=i))
24 | await asyncio.sleep(delay)
25 |
26 |
27 | if __name__ == "__main__":
28 |
29 | class MockQueue:
30 | async def put(self, event):
31 | print(event)
32 |
33 | asyncio.run(main(MockQueue(), dict(limit=5)))
34 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools>=64", "setuptools_scm"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [tool.setuptools_scm]
6 | version_scheme = "release-branch-semver"
7 |
8 |
9 | [tool.black]
10 | line-length = 79
11 | target-version = ["py39", "py310"]
12 | extend-exclude = "docs"
13 |
14 | [tool.isort]
15 | profile = "black"
16 | combine_as_imports = true
17 | line_length = 79
18 | extend_skip = ["docs"]
19 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | asyncio_mode = strict
3 | log_file_level = INFO
4 | log_cli = true
5 | log_format = %(asctime)s %(levelname)s %(message)s
6 | log_date_format = %Y-%m-%d %H:%M:%S
7 | markers =
8 | e2e: mark for end to end tests
9 | temporal: mark for time based tests
10 | long_run: mark for long running tests
11 | vcr: required by tests that use pytest-vcr
12 |
--------------------------------------------------------------------------------
/requirements_dev.txt:
--------------------------------------------------------------------------------
1 | -r requirements_test.txt
2 | -r requirements_lint.txt
3 | -r docs/requirements.txt
4 |
5 | setuptools_scm
6 |
7 | # Packaging / distribution
8 | twine
9 | build
10 |
11 | # Testing
12 | tox
13 | coverage
14 |
15 | # For building DEs
16 | ansible-builder
17 |
18 | pre-commit
19 |
--------------------------------------------------------------------------------
/requirements_lint.txt:
--------------------------------------------------------------------------------
1 | flake8==5.0.4
2 | flake8-bugbear
3 | isort
4 | black==22.12.0
5 |
--------------------------------------------------------------------------------
/requirements_test.txt:
--------------------------------------------------------------------------------
1 | watchdog
2 | docopt
3 | psutil
4 | requests
5 | ansible
6 | ansible-core~=2.16.0; python_version >= "3.11"
7 | ansible-core~=2.15.0; python_version < "3.11"
8 | ansible-runner
9 | jmespath
10 |
11 | pytest
12 | pytest-asyncio
13 | pytest-timeout
14 | pytest-xdist
15 | pytest-cov
16 | pytest-check
17 | marshmallow==3.26.1
18 | pytest-jira
19 | dynaconf==3.1.11
20 | freezegun
21 | oauthlib>=3.2.0
22 | kubernetes
23 | urllib3<2
24 | aioresponses
25 | httpie
26 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | # Complete documentation with many more options at:
2 | # https://docs.sonarqube.org/latest/analysis/analysis-parameters/
3 |
4 | ## The unique project identifier. This is mandatory.
5 | # Do not duplicate or reuse!
6 | # Available characters: [a-zA-Z0-9_:\.\-]
7 | # Must have least one non-digit.
8 | # Recommended format: :
9 | sonar.projectKey=ansible_ansible-rulebook
10 |
11 | sonar.organization=ansible
12 |
13 | # Customize what paths to scan. Default is .
14 | sonar.sources=.
15 |
16 | # Verbose name of project displayed in WUI. Default is set to the projectKey. This field is optional.
17 | sonar.projectName=ansible-rulebook
18 |
19 | sonar.issue.ignore.multicriteria=e1
20 | # Ignore "should be a variable"
21 | #sonar.issue.ignore.multicriteria.e1.ruleKey=python:S1192
22 | sonar.issue.ignore.multicriteria.e1.resourceKey=**/action/*
23 |
24 | # Only scan with python3
25 | sonar.python.version=3.9,3.10,3.11,3.12
26 |
27 | # Ignore code dupe for premature code reuse recommened in PR
28 | # https://github.com/ansible/ansible-rulebook/pull/537#issuecomment-1598883529
29 | sonar.cpd.exclusions=**/action/*
30 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Unit test package for ansible_rulebook."""
16 |
--------------------------------------------------------------------------------
/tests/asts/01_noop.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 01 No operation
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: none
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/02_debug.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 02 Debug
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/03_print_event.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 03 Print event
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: print_event
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/04_set_fact.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 04 Assert Fact
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: set_fact
10 | action_args:
11 | fact:
12 | msg: hello world
13 | condition:
14 | AllCondition:
15 | - EqualsExpression:
16 | lhs:
17 | Event: i
18 | rhs:
19 | Integer: 1
20 | enabled: true
21 | name: r1
22 | - Rule:
23 | action:
24 | Action:
25 | action: print_event
26 | action_args: {}
27 | condition:
28 | AllCondition:
29 | - EqualsExpression:
30 | lhs:
31 | Event: msg
32 | rhs:
33 | String: hello world
34 | enabled: true
35 | name: r2
36 | sources:
37 | - EventSource:
38 | name: range
39 | source_args:
40 | limit: 5
41 | source_filters: []
42 | source_name: range
43 |
--------------------------------------------------------------------------------
/tests/asts/05_post_event.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 05 Post event
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: post_event
10 | action_args:
11 | event:
12 | msg: hello world
13 | condition:
14 | AllCondition:
15 | - EqualsExpression:
16 | lhs:
17 | Event: i
18 | rhs:
19 | Integer: 1
20 | enabled: true
21 | name: r1
22 | - Rule:
23 | action:
24 | Action:
25 | action: print_event
26 | action_args: {}
27 | condition:
28 | AllCondition:
29 | - EqualsExpression:
30 | lhs:
31 | Event: msg
32 | rhs:
33 | String: hello world
34 | enabled: true
35 | name: r2
36 | sources:
37 | - EventSource:
38 | name: range
39 | source_args:
40 | limit: 5
41 | source_filters: []
42 | source_name: range
43 |
--------------------------------------------------------------------------------
/tests/asts/07_and.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 07 And
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - AndExpression:
14 | lhs:
15 | EqualsExpression:
16 | lhs:
17 | Event: nested.i
18 | rhs:
19 | Integer: 1
20 | rhs:
21 | EqualsExpression:
22 | lhs:
23 | Event: nested.j
24 | rhs:
25 | Integer: 1
26 | enabled: true
27 | name: r1
28 | sources:
29 | - EventSource:
30 | name: nested
31 | source_args:
32 | i_limit: 5
33 | j_limit: 5
34 | source_filters: []
35 | source_name: nested
36 |
--------------------------------------------------------------------------------
/tests/asts/08_or.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 08 Or
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - OrExpression:
14 | lhs:
15 | EqualsExpression:
16 | lhs:
17 | Event: nested.i
18 | rhs:
19 | Integer: 1
20 | rhs:
21 | EqualsExpression:
22 | lhs:
23 | Event: nested.j
24 | rhs:
25 | Integer: 1
26 | enabled: true
27 | name: r1
28 | sources:
29 | - EventSource:
30 | name: nested
31 | source_args:
32 | i_limit: 5
33 | j_limit: 5
34 | source_filters: []
35 | source_name: nested
36 |
--------------------------------------------------------------------------------
/tests/asts/09_gt.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 09 Greater Than
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - GreaterThanExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 2
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/10_lt.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 10 Less Than
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - LessThanExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 2
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/11_le.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 11 Less Than Or Equal To
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - LessThanOrEqualToExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 2
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/12_ge.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 09 Greater Than or Equal To
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - GreaterThanOrEqualToExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 2
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/13_add.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 09 Add
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: nested.i
16 | rhs:
17 | AdditionExpression:
18 | lhs:
19 | Event: nested.j
20 | rhs:
21 | Integer: 1
22 | enabled: true
23 | name: r1
24 | sources:
25 | - EventSource:
26 | name: nested
27 | source_args:
28 | i_limit: 5
29 | j_limit: 5
30 | source_filters: []
31 | source_name: nested
32 |
--------------------------------------------------------------------------------
/tests/asts/14_sub.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 14 Subtract
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: nested.i
16 | rhs:
17 | SubtractionExpression:
18 | lhs:
19 | Event: nested.j
20 | rhs:
21 | Integer: 1
22 | enabled: true
23 | name: r1
24 | sources:
25 | - EventSource:
26 | name: nested
27 | source_args:
28 | i_limit: 5
29 | j_limit: 5
30 | source_filters: []
31 | source_name: nested
32 |
--------------------------------------------------------------------------------
/tests/asts/15_multiple_events_all.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 15 multiple events all
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: nested.i
16 | rhs:
17 | Integer: 1
18 | - EqualsExpression:
19 | lhs:
20 | Event: nested.j
21 | rhs:
22 | Integer: 1
23 | enabled: true
24 | name: r1
25 | sources:
26 | - EventSource:
27 | name: nested
28 | source_args:
29 | i_limit: 5
30 | j_limit: 5
31 | source_filters: []
32 | source_name: nested
33 |
--------------------------------------------------------------------------------
/tests/asts/16_multiple_events_any.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 16 multiple events any
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AnyCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: nested.i
16 | rhs:
17 | Integer: 1
18 | - EqualsExpression:
19 | lhs:
20 | Event: nested.j
21 | rhs:
22 | Integer: 1
23 | enabled: true
24 | name: r1
25 | sources:
26 | - EventSource:
27 | name: nested
28 | source_args:
29 | i_limit: 5
30 | j_limit: 5
31 | source_filters: []
32 | source_name: nested
33 |
--------------------------------------------------------------------------------
/tests/asts/17_multiple_sources_any.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 17 multiple sources
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AnyCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | - EqualsExpression:
19 | lhs:
20 | Event: range2.i
21 | rhs:
22 | Integer: 1
23 | enabled: true
24 | name: r1
25 | sources:
26 | - EventSource:
27 | name: range
28 | source_args:
29 | limit: 5
30 | source_filters: []
31 | source_name: range
32 | - EventSource:
33 | name: range2
34 | source_args:
35 | limit: 5
36 | source_filters: []
37 | source_name: range2
38 |
--------------------------------------------------------------------------------
/tests/asts/18_multiple_sources_all.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 18 multiple sources all
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | - EqualsExpression:
19 | lhs:
20 | Event: range2.i
21 | rhs:
22 | Integer: 1
23 | enabled: true
24 | name: r1
25 | sources:
26 | - EventSource:
27 | name: range
28 | source_args:
29 | limit: 5
30 | source_filters: []
31 | source_name: range
32 | - EventSource:
33 | name: range2
34 | source_args:
35 | limit: 5
36 | source_filters: []
37 | source_name: range2
38 |
--------------------------------------------------------------------------------
/tests/asts/19_is_defined.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 19 is defined
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: set_fact
10 | action_args:
11 | fact:
12 | msg: hello
13 | condition:
14 | AllCondition:
15 | - EqualsExpression:
16 | lhs:
17 | Event: i
18 | rhs:
19 | Integer: 1
20 | enabled: true
21 | name: r1
22 | - Rule:
23 | action:
24 | Action:
25 | action: debug
26 | action_args: {}
27 | condition:
28 | AllCondition:
29 | - IsDefinedExpression:
30 | Event: msg
31 | enabled: true
32 | name: r2
33 | - Rule:
34 | action:
35 | Action:
36 | action: print_event
37 | action_args:
38 | pretty: true
39 | condition:
40 | AllCondition:
41 | - IsDefinedExpression:
42 | Event: payload
43 | enabled: true
44 | name: r3
45 | sources:
46 | - EventSource:
47 | name: range
48 | source_args:
49 | limit: 5
50 | source_filters: []
51 | source_name: range
52 |
--------------------------------------------------------------------------------
/tests/asts/20_is_not_defined.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 20 is not defined
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: set_fact
10 | action_args:
11 | fact:
12 | msg: hello
13 | condition:
14 | AllCondition:
15 | - EqualsExpression:
16 | lhs:
17 | Event: i
18 | rhs:
19 | Integer: 1
20 | enabled: true
21 | name: r1
22 | - Rule:
23 | action:
24 | Action:
25 | action: retract_fact
26 | action_args:
27 | fact:
28 | msg: hello
29 | condition:
30 | AllCondition:
31 | - IsDefinedExpression:
32 | Event: msg
33 | enabled: true
34 | name: r2
35 | - Rule:
36 | action:
37 | Action:
38 | action: debug
39 | action_args: {}
40 | condition:
41 | AllCondition:
42 | - IsNotDefinedExpression:
43 | Event: msg
44 | enabled: true
45 | name: r3
46 | sources:
47 | - EventSource:
48 | name: range
49 | source_args:
50 | limit: 5
51 | source_filters: []
52 | source_name: range
53 |
--------------------------------------------------------------------------------
/tests/asts/21_run_playbook.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 21 run playbook
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_playbook
10 | action_args:
11 | name: playbooks/hello.yml
12 | condition:
13 | AllCondition:
14 | - EqualsExpression:
15 | lhs:
16 | Event: i
17 | rhs:
18 | Integer: 1
19 | enabled: true
20 | name: r1
21 | sources:
22 | - EventSource:
23 | name: range
24 | source_args:
25 | limit: 5
26 | source_filters: []
27 | source_name: range
28 |
--------------------------------------------------------------------------------
/tests/asts/23_nested_data.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 23 run playbook
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: root.nested.i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: replay
23 | source_args:
24 | directory: examples/replays/23_nested_data
25 | source_filters: []
26 | source_name: replay
27 |
--------------------------------------------------------------------------------
/tests/asts/24_max_attributes.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 24 max attributes
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: attr_1
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: replay
23 | source_args:
24 | directory: examples/replays/24_max_attributes
25 | source_filters: []
26 | source_name: replay
27 |
--------------------------------------------------------------------------------
/tests/asts/25_max_attributes_nested.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 25 max attributes nested
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: branch_0.branch_0.branch_0.leaf_1
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: replay
23 | source_args:
24 | directory: examples/replays/25_max_attributes_nested
25 | source_filters: []
26 | source_name: replay
27 |
--------------------------------------------------------------------------------
/tests/asts/26_print_events.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 26 Print events
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: print_event
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | - EqualsExpression:
19 | lhs:
20 | Event: i
21 | rhs:
22 | Integer: 2
23 | enabled: true
24 | name: r1
25 | sources:
26 | - EventSource:
27 | name: range
28 | source_args:
29 | limit: 5
30 | source_filters: []
31 | source_name: range
32 |
--------------------------------------------------------------------------------
/tests/asts/27_var_root.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 27 multiple events all with var_root
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: print_event
10 | action_args:
11 | var_root:
12 | kafka.message: kafka
13 | webhook.payload: webhook
14 | condition:
15 | AllCondition:
16 | - AssignmentExpression:
17 | lhs:
18 | Events: webhook
19 | rhs:
20 | EqualsExpression:
21 | lhs:
22 | Event: webhook.payload.url
23 | rhs:
24 | String: http://www.example.com
25 | - AssignmentExpression:
26 | lhs:
27 | Events: kafka
28 | rhs:
29 | EqualsExpression:
30 | lhs:
31 | Event: kafka.message.channel
32 | rhs:
33 | String: red
34 | enabled: true
35 | name: r1
36 | sources:
37 | - EventSource:
38 | name: non_existent
39 | source_args: {}
40 | source_filters: []
41 | source_name: non_existent
42 |
--------------------------------------------------------------------------------
/tests/asts/28_right_side_condition_template.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 28 test jinja templating on the right side of the condition
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - AssignmentExpression:
14 | lhs:
15 | Facts: first
16 | rhs:
17 | IsDefinedExpression:
18 | Fact: custom.expected_index
19 | - EqualsExpression:
20 | lhs:
21 | Event: i
22 | rhs:
23 | Facts: first.custom.expected_index
24 | enabled: true
25 | name: r1
26 | sources:
27 | - EventSource:
28 | name: range
29 | source_args:
30 | limit: 5
31 | source_filters: []
32 | source_name: range
33 |
--------------------------------------------------------------------------------
/tests/asts/29_run_module.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 29 run module
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_module
10 | action_args:
11 | module_args:
12 | name: Fred Flintstone
13 | name: ansible.eda.upcase
14 | condition:
15 | AllCondition:
16 | - EqualsExpression:
17 | lhs:
18 | Event: i
19 | rhs:
20 | Integer: 1
21 | enabled: true
22 | name: r1
23 | sources:
24 | - EventSource:
25 | name: range
26 | source_args:
27 | limit: 5
28 | source_filters: []
29 | source_name: range
30 |
--------------------------------------------------------------------------------
/tests/asts/30_run_module_missing.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 30 run module missing
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_module
10 | action_args:
11 | module_args:
12 | name: fred
13 | name: ansible.eda.upcase2
14 | condition:
15 | AllCondition:
16 | - EqualsExpression:
17 | lhs:
18 | Event: i
19 | rhs:
20 | Integer: 1
21 | enabled: true
22 | name: r1
23 | sources:
24 | - EventSource:
25 | name: range
26 | source_args:
27 | limit: 5
28 | source_filters: []
29 | source_name: range
30 |
--------------------------------------------------------------------------------
/tests/asts/31_run_module_missing_args.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 31 run module missing args
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_module
10 | action_args:
11 | module_args:
12 | un_name: fred
13 | name: ansible.eda.upcase
14 | condition:
15 | AllCondition:
16 | - EqualsExpression:
17 | lhs:
18 | Event: i
19 | rhs:
20 | Integer: 1
21 | enabled: true
22 | name: r1
23 | sources:
24 | - EventSource:
25 | name: range
26 | source_args:
27 | limit: 5
28 | source_filters: []
29 | source_name: range
30 |
--------------------------------------------------------------------------------
/tests/asts/32_run_module_fail.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 32 run module fail
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_module
10 | action_args:
11 | module_args:
12 | name: fail
13 | name: ansible.eda.upcase
14 | retry: true
15 | condition:
16 | AllCondition:
17 | - EqualsExpression:
18 | lhs:
19 | Event: i
20 | rhs:
21 | Integer: 1
22 | enabled: true
23 | name: r1
24 | sources:
25 | - EventSource:
26 | name: range
27 | source_args:
28 | limit: 5
29 | source_filters: []
30 | source_name: range
31 |
--------------------------------------------------------------------------------
/tests/asts/33_run_playbook_retry.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 33 run playbook and retry after an interval
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_playbook
10 | action_args:
11 | delay: 1
12 | name: playbooks/fail_and_succeed.yml
13 | retry: true
14 | condition:
15 | AllCondition:
16 | - EqualsExpression:
17 | lhs:
18 | Event: i
19 | rhs:
20 | Integer: 1
21 | enabled: true
22 | name: r1
23 | sources:
24 | - EventSource:
25 | name: range
26 | source_args:
27 | limit: 5
28 | source_filters: []
29 | source_name: range
30 |
--------------------------------------------------------------------------------
/tests/asts/34_run_playbook_retries.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: 34 run playbook and retry a number of times
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: run_playbook
10 | action_args:
11 | name: playbooks/fail_and_succeed.yml
12 | retries: 1
13 | condition:
14 | AllCondition:
15 | - EqualsExpression:
16 | lhs:
17 | Event: i
18 | rhs:
19 | Integer: 1
20 | enabled: true
21 | name: r1
22 | sources:
23 | - EventSource:
24 | name: range
25 | source_args:
26 | limit: 5
27 | source_filters: []
28 | source_name: range
29 |
--------------------------------------------------------------------------------
/tests/asts/37_hosts_facts.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: Host facts
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Fact: meta.hosts
16 | rhs:
17 | String: localhost
18 | - EqualsExpression:
19 | lhs:
20 | Event: i
21 | rhs:
22 | Integer: 1
23 | enabled: true
24 | name: Host 1 rule
25 | - Rule:
26 | action:
27 | Action:
28 | action: debug
29 | action_args: {}
30 | condition:
31 | AllCondition:
32 | - EqualsExpression:
33 | lhs:
34 | Fact: os
35 | rhs:
36 | String: linux
37 | - EqualsExpression:
38 | lhs:
39 | Event: i
40 | rhs:
41 | Integer: 4
42 | enabled: true
43 | name: Host 2 rule
44 | sources:
45 | - EventSource:
46 | name: range
47 | source_args:
48 | limit: 5
49 | source_filters: []
50 | source_name: range
51 |
--------------------------------------------------------------------------------
/tests/asts/38_shutdown.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: Test shutdown action
5 | rules:
6 | - Rule:
7 | action:
8 | Action:
9 | action: shutdown
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: Host 1 rule
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/rules_with_assignment.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - localhost
4 | name: Demo rules with assignment
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args:
11 | var: events.first
12 | condition:
13 | AllCondition:
14 | - AssignmentExpression:
15 | lhs:
16 | Events: first
17 | rhs:
18 | EqualsExpression:
19 | lhs:
20 | Event: i
21 | rhs:
22 | Integer: 0
23 | enabled: true
24 | name: assignment
25 | sources:
26 | - EventSource:
27 | name: range
28 | source_args:
29 | limit: 5
30 | source_filters: []
31 | source_name: range
32 |
--------------------------------------------------------------------------------
/tests/asts/rules_with_assignment2.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - localhost
4 | name: Demo rules with assignment2
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args:
11 | var: events.first
12 | condition:
13 | AllCondition:
14 | - AssignmentExpression:
15 | lhs:
16 | Facts: first
17 | rhs:
18 | EqualsExpression:
19 | lhs:
20 | Fact: i
21 | rhs:
22 | Integer: 0
23 | enabled: true
24 | name: assignment
25 | sources:
26 | - EventSource:
27 | name: range
28 | source_args:
29 | limit: 5
30 | source_filters: []
31 | source_name: range
32 |
--------------------------------------------------------------------------------
/tests/asts/rules_with_multiple_conditions.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - localhost
4 | name: Demo rules multiple conditions any
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AnyCondition:
13 | - AssignmentExpression:
14 | lhs:
15 | Events: event
16 | rhs:
17 | EqualsExpression:
18 | lhs:
19 | Event: i
20 | rhs:
21 | Integer: 0
22 | - AssignmentExpression:
23 | lhs:
24 | Events: event
25 | rhs:
26 | EqualsExpression:
27 | lhs:
28 | Event: i
29 | rhs:
30 | Integer: 1
31 | enabled: true
32 | name: multiple conditions
33 | sources:
34 | - EventSource:
35 | name: range
36 | source_args:
37 | limit: 5
38 | source_filters: []
39 | source_name: range
40 |
--------------------------------------------------------------------------------
/tests/asts/rules_with_multiple_conditions2.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - localhost
4 | name: Demo rules multiple conditions all
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - AssignmentExpression:
14 | lhs:
15 | Events: first
16 | rhs:
17 | EqualsExpression:
18 | lhs:
19 | Event: i
20 | rhs:
21 | Integer: 0
22 | - AssignmentExpression:
23 | lhs:
24 | Events: second
25 | rhs:
26 | EqualsExpression:
27 | lhs:
28 | Event: i
29 | rhs:
30 | Integer: 1
31 | enabled: true
32 | name: multiple conditions
33 | sources:
34 | - EventSource:
35 | name: range
36 | source_args:
37 | limit: 5
38 | source_filters: []
39 | source_name: range
40 |
--------------------------------------------------------------------------------
/tests/asts/rules_with_vars.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - localhost
4 | name: Rules with vars
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - AssignmentExpression:
14 | lhs:
15 | Events: first
16 | rhs:
17 | EqualsExpression:
18 | lhs:
19 | Event: i
20 | rhs:
21 | Integer: 0
22 | - AssignmentExpression:
23 | lhs:
24 | Events: second
25 | rhs:
26 | EqualsExpression:
27 | lhs:
28 | Event: i
29 | rhs:
30 | Integer: 1
31 | enabled: true
32 | name: multiple conditions
33 | sources:
34 | - EventSource:
35 | name: range
36 | source_args:
37 | limit: '{{limit}}'
38 | source_filters: []
39 | source_name: range
40 |
--------------------------------------------------------------------------------
/tests/asts/rules_without_assignment.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - localhost
4 | name: Demo rules multiple conditions all
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args:
11 | event: '{{event}}'
12 | condition:
13 | AllCondition:
14 | - EqualsExpression:
15 | lhs:
16 | Fact: i
17 | rhs:
18 | Integer: 0
19 | enabled: true
20 | name: assignment
21 | sources:
22 | - EventSource:
23 | name: range
24 | source_args:
25 | limit: 5
26 | source_filters: []
27 | source_name: range
28 |
--------------------------------------------------------------------------------
/tests/asts/test_rules_multiple_hosts2.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: Test rules multiple hosts 2
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/asts/test_rules_multiple_hosts3.yml:
--------------------------------------------------------------------------------
1 | - RuleSet:
2 | hosts:
3 | - all
4 | name: Test rules multiple hosts 3
5 | rules:
6 | - Rule:
7 | actions:
8 | - Action:
9 | action: debug
10 | action_args: {}
11 | condition:
12 | AllCondition:
13 | - EqualsExpression:
14 | lhs:
15 | Event: i
16 | rhs:
17 | Integer: 1
18 | enabled: true
19 | name: r1
20 | sources:
21 | - EventSource:
22 | name: range
23 | source_args:
24 | limit: 5
25 | source_filters: []
26 | source_name: range
27 |
--------------------------------------------------------------------------------
/tests/data/bad_source.py:
--------------------------------------------------------------------------------
1 | print("This is a bad source plugin")
2 |
--------------------------------------------------------------------------------
/tests/data/not_asyncio.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from typing import Any, Dict
3 |
4 |
5 | def main(queue: asyncio.Queue, args: Dict[str, Any]):
6 | print("Not asyncio should fail")
7 |
--------------------------------------------------------------------------------
/tests/data/rulebook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Sample Rulebook
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 0
11 | action:
12 | debug:
13 | - name: r2
14 | condition: event.i == 1
15 | action:
16 | debug:
17 | msg: "This is a sample message with {{ event.i }}"
18 | - name: r3
19 | condition: event.i == 2
20 | action:
21 | debug:
22 | msg:
23 | - "Hello World {{ event }}"
24 | - "Hello Java"
25 | - "Hello Java again {{ event }}"
26 | - name: r4
27 | condition: event.i == 3
28 | action:
29 | debug:
30 | var: event.does_not_exist
31 | - name: r5
32 | condition: event.i == 4
33 | action:
34 | debug:
35 | var: event.i
36 |
--------------------------------------------------------------------------------
/tests/data/test_cert.pem:
--------------------------------------------------------------------------------
1 | This is a bogus certfile
2 |
--------------------------------------------------------------------------------
/tests/data/test_env.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ENV1: abc
3 | ENV2: xyz
4 |
--------------------------------------------------------------------------------
/tests/data/test_key.pem:
--------------------------------------------------------------------------------
1 | This is a bogus keyfile
2 |
--------------------------------------------------------------------------------
/tests/data/test_vars.yml:
--------------------------------------------------------------------------------
1 | ---
2 | person:
3 | name: Fred
4 | age: 42
5 | town: Bedrock
6 | employed: True
7 |
--------------------------------------------------------------------------------
/tests/e2e/README.md:
--------------------------------------------------------------------------------
1 | # E2E test suite for ansible-rulebook
2 |
3 | ## Install
4 |
5 | *Requirements*: A working installation of ansible-rulebook see [official documentation for more details](https://ansible-rulebook.readthedocs.io/en/latest/installation.html).
6 |
7 | ```sh
8 | git clone git@github.com:ansible/ansible-rulebook.git
9 | pip install -r requirements_test.txt
10 | ```
11 |
12 | ## Usage
13 |
14 | ```sh
15 | pytest -m e2e -n auto
16 | ```
17 |
18 | ## Configuration
19 |
20 | Configuration is managed by [dynaconf library](https://www.dynaconf.com/)
21 |
22 | Default configuration is located in `tests/e2e/config/default.yml`
23 | You can use your custom configuration file by setting `EDA_E2E_SETTINGS` environment variable:
24 |
25 | ```sh
26 | export EDA_E2E_SETTINGS=/path/to/your/config.yml
27 | ```
28 |
29 | You can also override configuration by setting environment variables with the name of the configuration key in uppercase and prefixed by `EDA_E2E_`:
30 |
31 | ```sh
32 | export EDA_E2E_CMD_TIMEOUT=60
33 | ```
34 |
--------------------------------------------------------------------------------
/tests/e2e/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ansible/ansible-rulebook/da1bed4a19a08e37eb45394248941156692a304f/tests/e2e/__init__.py
--------------------------------------------------------------------------------
/tests/e2e/config/default.yml:
--------------------------------------------------------------------------------
1 | default_event_delay: 1
2 | default_shutdown_after: 5
3 | default_startup_delay: 30
4 | operators_shutdown_after: 1
5 | shutdown_now_startup_delay: 0.5
6 | disabled_rules_event_delay: 0.5
7 | cmd_timeout: 25
8 | controller_url: http://localhost:8080
9 | controller_token: secret
10 |
--------------------------------------------------------------------------------
/tests/e2e/conftest.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import Dict, Optional
3 |
4 | import pytest
5 |
6 |
7 | @pytest.fixture(scope="function")
8 | def update_environment():
9 | """Fixture factory to update environment variables
10 | Returns the updated environment variables,
11 | and restores the original environment variables after the test
12 | """
13 | env_backup = os.environ.copy()
14 |
15 | def _update_environment(env: Optional[Dict] = None) -> Dict:
16 | if env:
17 | os.environ.update(env)
18 | return os.environ
19 |
20 | yield _update_environment
21 | os.environ.clear()
22 | os.environ.update(env_backup)
23 |
--------------------------------------------------------------------------------
/tests/e2e/files/extra_vars/operator_variables.yml:
--------------------------------------------------------------------------------
1 | # logical, membership & relational vars
2 | universe_meaning: 42
3 | in_operator_int_array:
4 | - 42
5 | - 2.7182
6 | - 3.1415
7 | - 3
8 | - 2
9 | - 173.035
10 | - 20000000000000000426408380189087937446025157425359298935486676996 # > uint64
11 | - -6000
12 |
13 | in_operator_int_array_b:
14 | - 42
15 | - 2.7182
16 | - 3.1415
17 | - 173.035
18 | - 20000000000000000426408380189087937446025157425359298935486676996 # > uint64
19 | - -6000
20 |
21 | houses:
22 | - Lannister
23 | - Stark
24 | - Targaryen
25 | - Baratheon
26 |
27 | targaryen_motto: fire and blood
28 |
29 | mixed_types:
30 | - 4
31 | - 2.7182
32 | - "Vhagar"
33 | - true
34 | - Stark
35 |
36 | # is select vars
37 | type_asteroid: "asteroid"
38 | has_moons: true
39 | halleys_radius: 11
40 | halleys_min_op: 27000.123
41 |
42 | # is selectattr vars
43 | not_planet: false
44 | pluto_radius: 1188.30
45 | pluto_moons: 5
46 | eris_moon: "dysnomia"
47 | total_moons:
48 | - 50
49 | - 6.2e+1
50 | - 79.99
51 | best_moons:
52 | - "deimos"
53 | - "phobos"
54 |
--------------------------------------------------------------------------------
/tests/e2e/files/extra_vars/test_debug.yml:
--------------------------------------------------------------------------------
1 | controller_password: dummy
2 | tower_password: dummy
3 | aap_password: dummy
4 | postgres_db_password: dummy
5 | postgres_db_username: admin
6 | controller_username: admin
7 | private_key: dummy
8 | aap_passphrase: dummy
9 | service_nested_list:
10 | - service1_username: admin
11 | service1_password: dummy
12 | service_dict:
13 | service2_username: admin
14 | service2_token: dummy
--------------------------------------------------------------------------------
/tests/e2e/files/extra_vars/test_variables_extra_vars.yml:
--------------------------------------------------------------------------------
1 | alarm_location: hobart
2 | alarm_monitoring: enabled
3 | notify_police: true
4 | lockdown_enabled: true
5 | lockdown_threshold: 7.5
6 | zones: [1, 3, 5, 7, 11]
7 | intruder_status: null
8 |
--------------------------------------------------------------------------------
/tests/e2e/files/extra_vars/vaulted_variables.yml:
--------------------------------------------------------------------------------
1 | go_var: !vault |
2 | $ANSIBLE_VAULT;1.1;AES256;label2
3 | 32353335346335396166356435383034666639356435323933353136633637306331396234343361
4 | 3631353062306433646264653165393238653464373765610a633336643266383538356263346365
5 | 32306265623832326231613433366532643636636133663639363437633166303261386534663030
6 | 6434323034623338610a373736333365623861646430636562333763633536383562373231663939
7 | 3233
--------------------------------------------------------------------------------
/tests/e2e/files/inventories/default_inventory.ini:
--------------------------------------------------------------------------------
1 | localhost ansible_connection=local
2 |
--------------------------------------------------------------------------------
/tests/e2e/files/inventories/default_inventory.yml:
--------------------------------------------------------------------------------
1 | all:
2 | hosts:
3 | localhost:
4 | ansible_connection: local
5 |
--------------------------------------------------------------------------------
/tests/e2e/files/inventories/inventory_as_dir/group_vars/customgroup.yml:
--------------------------------------------------------------------------------
1 | groupvar: groupvar_value
2 |
--------------------------------------------------------------------------------
/tests/e2e/files/inventories/inventory_as_dir/host_vars/localhost.yml:
--------------------------------------------------------------------------------
1 | hostvar: hostvar_value
2 |
--------------------------------------------------------------------------------
/tests/e2e/files/inventories/inventory_as_dir/hosts.yml:
--------------------------------------------------------------------------------
1 | customgroup:
2 | hosts:
3 | localhost:
4 | ansible_connection: local
5 |
--------------------------------------------------------------------------------
/tests/e2e/files/passwords/pass1.txt:
--------------------------------------------------------------------------------
1 | secret1
--------------------------------------------------------------------------------
/tests/e2e/files/passwords/pass2.txt:
--------------------------------------------------------------------------------
1 | secret2
--------------------------------------------------------------------------------
/tests/e2e/files/passwords/pass3.txt:
--------------------------------------------------------------------------------
1 | secret3
--------------------------------------------------------------------------------
/tests/e2e/files/playbooks/long_running.yml:
--------------------------------------------------------------------------------
1 | - name: A long running playbook
2 | hosts: all
3 | gather_facts: false
4 | vars:
5 | pause_time: "{{ sleep_seconds | default(5) }}"
6 | tasks:
7 | - name: Print sleep message
8 | ansible.builtin.debug:
9 | msg: "Sleeping..."
10 |
11 | - name: Sleep
12 | ansible.builtin.pause:
13 | seconds: "{{ pause_time }}"
14 |
15 | - name: Print wake-up message
16 | ansible.builtin.debug:
17 | msg: "Rise and shine..."
18 |
--------------------------------------------------------------------------------
/tests/e2e/files/playbooks/print_event.yml:
--------------------------------------------------------------------------------
1 | - hosts: all
2 | gather_facts: false
3 | tasks:
4 | - name: Print event
5 | when: ansible_eda.event is defined
6 | ansible.builtin.debug:
7 | msg: "Event matched: {{ ansible_eda.event }}"
8 |
9 | - name: Print events
10 | when: ansible_eda.events is defined
11 | ansible.builtin.debug:
12 | msg: "Event matched: {{ ansible_eda.events }}"
13 |
--------------------------------------------------------------------------------
/tests/e2e/files/playbooks/print_group_vars.yml:
--------------------------------------------------------------------------------
1 | - hosts: customgroup
2 | gather_facts: false
3 | tasks:
4 | - name: Show vars
5 | ansible.builtin.debug:
6 | msg:
7 | - "groupvar: {{ groupvar }}"
8 | - "hostvar: {{ hostvar }}"
9 |
--------------------------------------------------------------------------------
/tests/e2e/files/playbooks/print_rule_name.yml:
--------------------------------------------------------------------------------
1 | - name: Print rule name that called this playbook
2 | hosts: all
3 | gather_facts: false
4 | tasks:
5 | - name: Print rule name
6 | when: ansible_eda.rule is defined
7 | ansible.builtin.debug:
8 | msg: "Rule name: {{ ansible_eda.rule }}"
9 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/actions/test_shutdown_now.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Ruleset 1
3 | hosts: all
4 | sources:
5 | - generic:
6 | event_delay: "{{ DEFAULT_EVENT_DELAY }}"
7 | payload:
8 | - action: "long_running_playbook"
9 | - action: "send_msg"
10 |
11 | rules:
12 | - name: Start long-running playbook
13 | condition: event.action == "long_running_playbook"
14 | actions:
15 | - debug:
16 | msg: "Sequential action triggered successfully"
17 | - run_playbook:
18 | name: ./playbooks/long_running.yml
19 | extra_vars:
20 | pause_time: 30
21 |
22 | - name: Send message after shutdown
23 | condition: event.action == "send_msg"
24 | action:
25 | debug:
26 | msg: "This condition should not fire"
27 |
28 |
29 | - name: Ruleset 2
30 | hosts: all
31 | sources:
32 | - generic:
33 | startup_delay: "{{ SHUTDOWN_NOW_STARTUP_DELAY }}"
34 | payload:
35 | - action: "trigger_shutdown"
36 |
37 | rules:
38 | - name: Shutdown
39 | condition: event.action == "trigger_shutdown"
40 | action:
41 | shutdown:
42 | kind: now
43 | message: "Shutdown triggered from Ruleset 2"
44 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/hello_events_with_var.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Hello Events with variable
3 | hosts: all
4 | sources:
5 | - generic:
6 | event_delay: "{{ EVENT_DELAY }}"
7 | payload:
8 | - action: "go"
9 |
10 | rules:
11 | - name: Say Hello
12 | condition: event.action == "go"
13 | action:
14 | debug:
15 | msg: Hello there!
16 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/malformed_rulebook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Malformed rulebook
3 | hosts: all
4 | sources:
5 | - range:
6 | rules:
7 | - name: This is poorly formatted
8 | condition: event.i == 1
9 | action:
10 | run_module:
11 | name: ansible.builtin.debug
12 | module_args:
13 | msg: I am invalid
14 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_debug_no_params.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Validate debug action does not output secrets with no params
3 | hosts: all
4 | sources:
5 | - generic:
6 | payload:
7 | - action: "all"
8 | rules:
9 | - name: Validate all variables are masked in debug
10 | condition: event.action == "all"
11 | actions:
12 | - debug:
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_debug_var_and_message.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Validate debug action does not output secrets with no params
3 | hosts: all
4 | sources:
5 | - generic:
6 | payload:
7 | - action: "postgres"
8 | - action: "controller"
9 | - action: "tower"
10 | - action: "msg"
11 | - action: "username"
12 | rules:
13 | - name: Validate variable "postgres" is masked in debug
14 | condition: event.action == "postgres"
15 | actions:
16 | - debug:
17 | var: postgres_db_password
18 | - name: Validate variable "controller" is masked directly in debug
19 | condition: event.action == "controller"
20 | actions:
21 | - debug:
22 | var: controller_password
23 | - name: Validate variable "tower" is masked directly in debug
24 | condition: event.action == "tower"
25 | actions:
26 | - debug:
27 | var: tower_password
28 | - name: Validate variable is masked when specified in msg
29 | condition: event.action == "msg"
30 | actions:
31 | - debug:
32 | msg: "Test message override {{ postgres_db_password }}"
33 | - name: Validate variable is unmasked
34 | condition: event.action == "username"
35 | actions:
36 | - debug:
37 | var: controller_username
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_hot_reload.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Ruleset 1
3 | hosts: all
4 | sources:
5 | - generic:
6 | payload:
7 | - action: "value_a"
8 | shutdown_after: 2
9 | rules:
10 | - name: Matching for value_a
11 | condition: event.action == "value_a"
12 | action:
13 | debug:
14 | msg: "Rule 1: I matched for value_a"
15 | - name: Matching for value_b
16 | condition: event.action == "value_b"
17 | action:
18 | debug:
19 | msg: "Rule 2: I have now matched for value_b"
20 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_inventory_as_dir.yml:
--------------------------------------------------------------------------------
1 | - name: Test inventory as dir
2 | hosts: all
3 | sources:
4 | - ansible.eda.generic:
5 | shutdown_after: 2
6 | payload:
7 | motto: winter is coming
8 | rules:
9 | - name: Test rule
10 | condition: event.motto == "winter is coming"
11 | action:
12 | run_playbook:
13 | name: ./playbooks/print_group_vars.yml
14 | copy_files: true
15 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_match_multiple_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test match multiple rules
3 | hosts: all
4 | match_multiple_rules: true
5 | sources:
6 | - name: range
7 | range:
8 | limit: 5
9 | rules:
10 | - name: r1
11 | condition: event.i == 1
12 | action:
13 | debug:
14 | - name: r11
15 | condition: event.i == 1
16 | action:
17 | print_event:
18 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_process_sigint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Ruleset 1
3 | hosts: all
4 | sources:
5 | - generic:
6 | loop_count: 10
7 | loop_delay: 1
8 | payload:
9 | - action: "long_loop"
10 |
11 | rules:
12 | - name: Trigger loop
13 | condition: event.action == "long_loop"
14 | action:
15 | print_event:
16 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_process_source_end.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Ruleset 1
3 | hosts: all
4 | sources:
5 | - generic:
6 | event_delay: 0.05
7 | payload:
8 | - action: "long_running_playbook"
9 | - action: "send_msg"
10 | - action: "send_msg"
11 | - action: "send_msg"
12 |
13 | rules:
14 | - name: Start long-running playbook
15 | condition: event.action == "long_running_playbook"
16 | actions:
17 | - run_playbook:
18 | name: ./playbooks/long_running.yml
19 | extra_vars:
20 | pause_time: 3
21 |
22 | - name: Send message in parallel
23 | condition: event.action == "send_msg"
24 | action:
25 | debug:
26 | msg: "Parallel action triggered successfully"
27 |
28 |
29 | - name: Ruleset 2
30 | hosts: all
31 | sources:
32 | - generic:
33 | loop_count: -1 # source is in an infinite loop
34 | loop_delay: 1
35 | payload:
36 | - action: "infinite_loop"
37 |
38 | rules:
39 | - name: Trigger loop
40 | condition: event.action == "infinite_loop"
41 | action:
42 | none:
43 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_source_stacktrace.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Raise exception midst processing
3 | hosts: localhost
4 | sources:
5 | - name: Raise Exception
6 | fail_after:
7 | limit: "{{ LIMIT | default(10) }}"
8 | after: "{{ FAIL_AFTER | default(4) }}"
9 | rules:
10 | - name: Simple Rule
11 | condition: true
12 | action:
13 | debug:
14 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_vaulted_rulebook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Hello Events with variable
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - action: "{{ go_var }}"
8 | - alert:
9 | level: warning
10 | message: !vault |
11 | $ANSIBLE_VAULT;1.1;AES256
12 | 30366463666430383031623536623666326633636437393337383731366262313231653830393865
13 | 3463376431303861383933303331323432346333656231330a623031383537623930316162346336
14 | 36363539303762306262363938653765323031316361313834336335326662363131303866643037
15 | 3239336434323230310a393163373636393163653764386632653965363537353939366631326133
16 | 3534
17 |
18 | rules:
19 | - name: Say Hello
20 | condition: event.action == "go"
21 | action:
22 | debug:
23 | msg: !vault |
24 | $ANSIBLE_VAULT;1.1;AES256
25 | 63306363613865633762616535386364653738363839623239373463343164633230343165643730
26 | 6266323465326638653964313932303164623639393736310a643666643532613262353735616532
27 | 39666662386364313739623732616333316536343762306463353036353335653537656537373763
28 | 3032623464633265610a333531343830373134366466366262313637623139373135383161363366
29 | 3732
30 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_vaulted_rulebook_interpolate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Hello Events with string interpolation
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - action: "pay and {{ go_var }}"
8 | - alert:
9 | level: warning
10 | message: !vault |
11 | $ANSIBLE_VAULT;1.1;AES256
12 | 30366463666430383031623536623666326633636437393337383731366262313231653830393865
13 | 3463376431303861383933303331323432346333656231330a623031383537623930316162346336
14 | 36363539303762306262363938653765323031316361313834336335326662363131303866643037
15 | 3239336434323230310a393163373636393163653764386632653965363537353939366631326133
16 | 3534
17 |
18 | rules:
19 | - name: Say Hello
20 | condition: event.action == "pay and go"
21 | action:
22 | debug:
23 | msg: !vault |
24 | $ANSIBLE_VAULT;1.1;AES256
25 | 63306363613865633762616535386364653738363839623239373463343164633230343165643730
26 | 6266323465326638653964313932303164623639393736310a643666643532613262353735616532
27 | 39666662386364313739623732616333316536343762306463353036353335653537656537373763
28 | 3032623464633265610a333531343830373134366466366262313637623139373135383161363366
29 | 3732
30 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/test_vaulted_v2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Hello Events with variable
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - action: go
8 | rules:
9 | - name: Say Hello
10 | condition: event.action == "go"
11 | action:
12 | debug:
13 | msg: !vault |
14 | $ANSIBLE_VAULT;1.1;AES256
15 | 63306363613865633762616535386364653738363839623239373463343164633230343165643730
16 | 6266323465326638653964313932303164623639393736310a643666643532613262353735616532
17 | 39666662386364313739623732616333316536343762306463353036353335653537656537373763
18 | 3032623464633265610a333531343830373134366466366262313637623139373135383161363366
19 | 3732
20 |
--------------------------------------------------------------------------------
/tests/e2e/files/rulebooks/websockets/test_websocket_range.yml:
--------------------------------------------------------------------------------
1 | - name: Test websocket range events
2 | hosts: all
3 | sources:
4 | - name: Generate a range
5 | ansible.eda.range:
6 | limit: 2000
7 | rules:
8 | - name: match the event
9 | condition: event.i == 700
10 | action:
11 | run_playbook:
12 | name: ./playbooks/print_event.yml
13 |
--------------------------------------------------------------------------------
/tests/e2e/settings.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import dynaconf
4 |
5 | HERE = os.path.dirname(os.path.abspath(__file__))
6 | DEFAULT_CONFIG_PATH = os.path.join(HERE, "config")
7 | DEFAULT_CONFIG_FILE = "default.yml"
8 |
9 |
10 | def get_settings() -> dynaconf.LazySettings:
11 | """
12 | Get the settings.
13 | """
14 | return dynaconf.LazySettings(
15 | environments=False,
16 | load_dotenv=True,
17 | envvar="EDA_E2E_SETTINGS",
18 | envvar_prefix="EDA_E2E",
19 | root_path=DEFAULT_CONFIG_PATH,
20 | settings_file=DEFAULT_CONFIG_FILE,
21 | )
22 |
23 |
24 | SETTINGS = get_settings()
25 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | # Disable warnings about localhost
3 | localhost_warning = False
4 |
5 | # Disable warnings about unparsed inventory
6 | [inventory]
7 | inventory_unparsed_warning = False
8 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/create-cluster.yml:
--------------------------------------------------------------------------------
1 | - name: Create kind cluster
2 | hosts: localhost
3 | connection: local
4 | tasks:
5 | - name: Create kind cluster
6 | ansible.builtin.command:
7 | cmd: kind create cluster --config kind-config.yml
8 |
9 | - name: Deploy ingress controller
10 | kubernetes.core.k8s:
11 | apply: true
12 | src: https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
13 |
14 | - name: Wait for controller
15 | kubernetes.core.k8s_info:
16 | namespace: ingress-nginx
17 | kind: pod
18 | label_selectors:
19 | - app.kubernetes.io/component=controller
20 | wait: yes
21 | wait_sleep: 1
22 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/install-awx.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Install AWX to Kubernetes Cluster
3 | hosts: localhost
4 | connection: local
5 | roles:
6 | - install-awx
7 | tasks:
8 | - name: Wait for controller
9 | kubernetes.core.k8s_info:
10 | namespace: ingress-nginx
11 | kind: pod
12 | label_selectors:
13 | - app.kubernetes.io/component=controller
14 | wait: yes
15 | wait_sleep: 3
16 |
17 | - name: Wait for http response
18 | uri:
19 | url: https://localhost:9443/api/v2/ping/
20 | return_content: no
21 | validate_certs: no
22 | status_code:
23 | - 200
24 | until: uri_output.status == 200
25 | retries: 60
26 | delay: 1
27 | register: uri_output
28 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/kind-config.yml:
--------------------------------------------------------------------------------
1 | kind: Cluster
2 | apiVersion: kind.x-k8s.io/v1alpha4
3 | name: awx-kind-cluster
4 | nodes:
5 | - role: control-plane
6 | kubeadmConfigPatches:
7 | - |
8 | kind: InitConfiguration
9 | nodeRegistration:
10 | kubeletExtraArgs:
11 | node-labels: "ingress-ready=true"
12 | extraPortMappings:
13 | - containerPort: 80
14 | hostPort: 9080
15 | protocol: TCP
16 | - containerPort: 443
17 | hostPort: 9443
18 | protocol: TCP
19 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/readme.md:
--------------------------------------------------------------------------------
1 | # E2E test for AWX integration
2 |
3 | This subproject allows to run a k8s cluster for testing using kind and install AWX in it.
4 | Kind is a tool for running local k8s clusters using docker/podman containers as nodes.
5 |
6 | # Create a k8s cluster with kind
7 |
8 | Requirements:
9 |
10 | * docker/podman
11 | * ansible
12 | * kind
13 | * kubernetes ansible collection `ansible-galaxy collection install kubernetes.core`
14 |
15 | You may need to install the requirements with `pip install -r requirements.txt`
16 | if you are not using the ansible-rulebook dev environment.
17 |
18 | # Steps
19 |
20 | 0. When using Podman
21 |
22 | ```
23 | export KIND_EXPERIMENTAL_PROVIDER=podman
24 | ```
25 |
26 | 1. Create the cluster
27 |
28 | ```
29 | ansible-playbook create-cluster.yml
30 | ```
31 |
32 | 2. Install AWX
33 |
34 | ```
35 | ansible-playbook install-awx.yml
36 | ```
37 |
38 | You should be able to reach awx in with admin/password
39 |
40 | # Cleanup
41 |
42 | ```
43 | kind delete cluster -n awx-kind-cluster
44 | ```
45 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/requirements.txt:
--------------------------------------------------------------------------------
1 | oauthlib>=3.2.0
2 | kubernetes
3 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/roles/install-awx/defaults/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | awx_name: awx
3 | awx_image: quay.io/ansible/awx
4 | awx_image_tag: latest
5 | awx_operator_image: quay.io/ansible/awx-operator
6 | awx_operator_image_tag: "2.15.0"
7 | awx_namespace: awx
8 | awx_hostname: "localhost"
9 | awx_admin_password: password
10 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/roles/install-awx/templates/admin-password-secret.yml.j2:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: {{ awx_name }}-admin-password
6 | namespace: {{ awx_namespace }}
7 | stringData:
8 | password: {{ awx_admin_password }}
9 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/roles/install-awx/templates/awx.yaml.j2:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: awx.ansible.com/v1beta1
3 | kind: AWX
4 | metadata:
5 | name: {{ awx_name }}
6 | namespace: {{ awx_namespace }}
7 | spec:
8 | hostname: {{ awx_hostname }}
9 | image: {{ awx_image }}
10 | image_version: {{ awx_image_tag }}
11 | service_type: nodeport
12 | ingress_type: ingress
13 |
--------------------------------------------------------------------------------
/tests/e2e/utils/awx/roles/install-awx/templates/kustomization/kustomization.yaml.j2:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | # Find the latest tag here: https://github.com/ansible/awx-operator/releases
5 | - github.com/ansible/awx-operator/config/default?ref={{ awx_operator_image_tag }}
6 |
7 | # Set the image tags to match the git version from above
8 | images:
9 | - name: {{ awx_operator_image }}
10 | newTag: {{ awx_operator_image_tag }}
11 |
12 | # Specify a custom namespace in which to install AWX
13 | namespace: {{ awx_namespace }}
--------------------------------------------------------------------------------
/tests/event_filter/noop.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | noop.py: An event filter that does nothing to the input.
17 | """
18 |
19 |
20 | def main(event):
21 | return event
22 |
--------------------------------------------------------------------------------
/tests/examples/01_noop.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 01 No operation
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | none:
13 |
--------------------------------------------------------------------------------
/tests/examples/02_debug.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 02 Debug
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/examples/03_print_event.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 03 Print event
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | print_event:
13 |
--------------------------------------------------------------------------------
/tests/examples/04_set_fact.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 04 Assert Fact
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | fact:
14 | msg: hello world
15 | - name: r2
16 | condition: event.msg == "hello world"
17 | action:
18 | print_event:
19 |
--------------------------------------------------------------------------------
/tests/examples/05_post_event.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 05 Post event
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | post_event:
13 | event:
14 | msg: hello world
15 | - name: r2
16 | condition: event.msg == "hello world"
17 | action:
18 | print_event:
19 |
--------------------------------------------------------------------------------
/tests/examples/06_retract_fact.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 06 Retract Fact
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | fact:
14 | msg: hello world
15 | - name: r2
16 | condition: event.msg == "hello world"
17 | action:
18 | retract_fact:
19 | fact:
20 | msg: hello world
21 | - name: r3
22 | condition: event.msg is not defined
23 | action:
24 | debug:
25 |
26 |
--------------------------------------------------------------------------------
/tests/examples/07_and.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 07 And
3 | hosts: all
4 | sources:
5 | - nested:
6 | i_limit: 5
7 | j_limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.nested.i == 1 and event.nested.j == 1
11 | action:
12 | debug:
13 |
14 |
--------------------------------------------------------------------------------
/tests/examples/08_or.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 08 Or
3 | hosts: all
4 | sources:
5 | - nested:
6 | i_limit: 5
7 | j_limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.nested.i == 1 or event.nested.j == 1
11 | action:
12 | debug:
13 |
14 |
--------------------------------------------------------------------------------
/tests/examples/09_gt.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 09 Greater Than
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i > 2
10 | action:
11 | debug:
12 |
13 |
--------------------------------------------------------------------------------
/tests/examples/10_lt.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 10 Less Than
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i < 2
10 | action:
11 | debug:
12 |
13 |
--------------------------------------------------------------------------------
/tests/examples/11_le.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 11 Less Than Or Equal To
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i <= 2
10 | action:
11 | debug:
12 |
13 |
--------------------------------------------------------------------------------
/tests/examples/12_ge.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 09 Greater Than or Equal To
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i >= 2
10 | action:
11 | debug:
12 |
13 |
--------------------------------------------------------------------------------
/tests/examples/13_add.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 09 Add
3 | hosts: all
4 | sources:
5 | - nested:
6 | i_limit: 5
7 | j_limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.nested.i == event.nested.j + 1
11 | action:
12 | debug:
13 |
14 |
--------------------------------------------------------------------------------
/tests/examples/14_sub.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 14 Subtract
3 | hosts: all
4 | sources:
5 | - nested:
6 | i_limit: 5
7 | j_limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.nested.i == event.nested.j - 1
11 | action:
12 | debug:
13 |
14 |
--------------------------------------------------------------------------------
/tests/examples/15_multiple_events_all.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 15 multiple events all
3 | hosts: all
4 | sources:
5 | - nested:
6 | i_limit: 5
7 | j_limit: 5
8 | rules:
9 | - name: r1
10 | condition:
11 | all:
12 | - event.nested.i == 1
13 | - event.nested.j == 1
14 | action:
15 | debug:
16 |
17 |
--------------------------------------------------------------------------------
/tests/examples/16_multiple_events_any.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 16 multiple events any
3 | hosts: all
4 | sources:
5 | - nested:
6 | i_limit: 5
7 | j_limit: 5
8 | rules:
9 | - name: r1
10 | condition:
11 | any:
12 | - event.nested.i == 1
13 | - event.nested.j == 1
14 | action:
15 | debug:
16 |
17 |
--------------------------------------------------------------------------------
/tests/examples/17_multiple_sources_any.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 17 multiple sources
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | - range2:
8 | limit: 5
9 | rules:
10 | - name: r1
11 | condition:
12 | any:
13 | - event.i == 1
14 | - event.range2.i == 1
15 | action:
16 | debug:
17 |
18 |
--------------------------------------------------------------------------------
/tests/examples/18_multiple_sources_all.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 18 multiple sources all
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | - range2:
8 | limit: 5
9 | rules:
10 | - name: r1
11 | condition:
12 | all:
13 | - event.i == 1
14 | - event.range2.i == 1
15 | action:
16 | debug:
17 |
18 |
--------------------------------------------------------------------------------
/tests/examples/19_is_defined.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 19 is defined
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | set_fact:
12 | fact:
13 | msg: hello
14 | - name: r2
15 | condition: event.msg is defined
16 | action:
17 | debug:
18 | - name: r3
19 | condition: event.payload is defined
20 | action:
21 | print_event:
22 | pretty: true
23 |
--------------------------------------------------------------------------------
/tests/examples/20_is_not_defined.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 20 is not defined
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | set_fact:
12 | fact:
13 | msg: hello
14 | - name: r2
15 | condition: event.msg is defined
16 | action:
17 | retract_fact:
18 | fact:
19 | msg: hello
20 | - name: r3
21 | condition: event.msg is not defined
22 | action:
23 | debug:
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/examples/21_run_playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 21 run playbook
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | run_playbook:
12 | name: playbooks/hello.yml
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/examples/22_run_playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 22 run playbook
3 | hosts: all
4 | sources:
5 | - range2:
6 | limit: 5
7 | rules:
8 | - name:
9 | condition: event.range2.i == 1
10 | action:
11 | run_playbook:
12 | name: playbooks/hello.yml
13 | var_root: range2
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/examples/23_nested_data.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 23 run playbook
3 | hosts: all
4 | sources:
5 | - replay:
6 | directory: examples/replays/23_nested_data
7 | rules:
8 | - name: r1
9 | condition: event.root.nested.i == 1
10 | action:
11 | debug:
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/examples/24_max_attributes.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 24 max attributes
3 | hosts: all
4 | sources:
5 | - replay:
6 | directory: examples/replays/24_max_attributes
7 | rules:
8 | - name: r1
9 | condition: event.attr_1 == 1
10 | action:
11 | debug:
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/examples/25_max_attributes_nested.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 25 max attributes nested
3 | hosts: all
4 | sources:
5 | - replay:
6 | directory: examples/replays/25_max_attributes_nested
7 | rules:
8 | - name: r1
9 | condition: event.branch_0.branch_0.branch_0.leaf_1 == 1
10 | action:
11 | debug:
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/examples/26_print_events.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 26 Print events
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition:
11 | all:
12 | - event.i == 1
13 | - event.i == 2
14 | action:
15 | print_event:
16 |
--------------------------------------------------------------------------------
/tests/examples/27_var_root.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 27 multiple events all with var_root
3 | hosts: all
4 | sources:
5 | - name: generic
6 | ansible.eda.generic:
7 | payload:
8 | - webhook:
9 | payload:
10 | url: http://www.example.com
11 | action: merge
12 | - kafka:
13 | message:
14 | topic: testing
15 | channel: red
16 | - webhook:
17 | payload:
18 | url: http://www.example.com
19 | action: merge
20 | - kafka:
21 | message:
22 | topic: testing
23 | channel: red
24 | rules:
25 | - name: r1
26 | condition:
27 | all:
28 | - events.webhook << event.webhook.payload.url == "http://www.example.com"
29 | - events.kafka << event.kafka.message.channel == "red"
30 | action:
31 | print_event:
32 | var_root:
33 | webhook.payload: webhook
34 | kafka.message: kafka
35 |
--------------------------------------------------------------------------------
/tests/examples/28_right_side_condition_template.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 28 test vars
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == vars.custom.expected_index
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/examples/29_run_module.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 29 run module
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - i: 1
8 | - i: 2
9 | - i: 3
10 | rules:
11 | - name: r1
12 | condition: event.i == 1
13 | action:
14 | run_module:
15 | post_events: True
16 | name: ansible.builtin.debug
17 | module_args:
18 | msg: "I am Malenia, blade of Miquella"
19 | - name: r2
20 | condition: event.msg == "I am Malenia, blade of Miquella"
21 | action:
22 | print_event:
23 |
--------------------------------------------------------------------------------
/tests/examples/30_run_module_missing.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 30 run module missing
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | run_module:
12 | name: ansible.eda.upcase2
13 | module_args:
14 | name: fred
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/examples/31_run_module_missing_args.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 31 run module missing args
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - name: fred
8 | i: 1
9 | - name: fred
10 | i: 2
11 | rules:
12 | - name: r1
13 | condition: event.i == 1
14 | action:
15 | run_module:
16 | name: ansible.builtin.debug
17 | module_args:
18 | idonotexist: fred
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/tests/examples/32_run_module_fail.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 32 run module fail
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | run_module:
12 | name: ansible.builtin.fail
13 | module_args:
14 | msg: expected failure
15 | retry: True
16 |
--------------------------------------------------------------------------------
/tests/examples/33_run_playbook_retry.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 33 run playbook and retry after an interval
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | run_playbook:
12 | name: playbooks/fail_and_succeed.yml
13 | retry: True
14 | delay: 1
15 | extra_vars:
16 | rulebook_file_path: /tmp/33_demo.txt
17 |
--------------------------------------------------------------------------------
/tests/examples/34_run_playbook_retries.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 34 run playbook and retry a number of times
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | run_playbook:
12 | name: playbooks/fail_and_succeed.yml
13 | retries: 1
14 | extra_vars:
15 | rulebook_file_path: /tmp/34_demo.txt
16 |
--------------------------------------------------------------------------------
/tests/examples/35_multiple_rulesets_1_fired.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 35 multiple rulesets 1
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | set_fact:
12 | fact:
13 | do_not_fire_rule: True
14 | ruleset: 35 multiple rulesets 1
15 | - name: r2
16 | condition: event.do_not_fire_rule == True
17 | action:
18 | none:
19 | - name: 35 multiple rulesets 2
20 | hosts: all
21 | sources:
22 | - range:
23 | limit: 5
24 | rules:
25 | - name: r1
26 | condition: event.do_not_fire_rule == True
27 | action:
28 | debug:
29 | msg: Should not run
30 |
--------------------------------------------------------------------------------
/tests/examples/36_multiple_rulesets_both_fired.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 36 multiple rulesets 1
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | loop_count: 5
7 | startup_delay: 1
8 | create_index: i
9 | payload:
10 | - x: 1
11 | rules:
12 | - name: r1
13 | condition: event.i == 1
14 | action:
15 | set_fact:
16 | fact:
17 | fire_rule: True
18 | ruleset: 36 multiple rulesets 2
19 | - name: Will not fire, fact in other ruleset
20 | condition: event.fire_rule == True
21 | action:
22 | print_event:
23 | - name: 36 multiple rulesets 2
24 | hosts: all
25 | sources:
26 | - ansible.eda.generic:
27 | loop_count: 5
28 | shutdown_after: 10
29 | payload:
30 | - y: 1
31 | - y: 2
32 | rules:
33 | - name: r1
34 | condition: event.fire_rule == True
35 | action:
36 | debug:
37 | msg: Should run
38 |
--------------------------------------------------------------------------------
/tests/examples/37_hosts_facts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Host facts
3 | hosts: all
4 | gather_facts: true
5 | sources:
6 | - range:
7 | limit: 5
8 | rules:
9 | - name: "Host 1 rule"
10 | condition:
11 | all:
12 | - fact.meta.hosts == "localhost"
13 | - event.i == 1
14 | action:
15 | debug:
16 | - name: "Host 2 rule"
17 | condition:
18 | all:
19 | - fact.os == "linux"
20 | - event.i == 4
21 | action:
22 | debug:
23 |
--------------------------------------------------------------------------------
/tests/examples/38_shutdown.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test shutdown action
3 | hosts: all
4 | gather_facts: false
5 | sources:
6 | - range:
7 | limit: 2
8 | delay: 3
9 | rules:
10 | - name: "Host 1 rule"
11 | condition: event.i == 1
12 | action:
13 | shutdown:
14 | delay: 1.1845
15 | message: My rule has triggered a shutdown
16 |
--------------------------------------------------------------------------------
/tests/examples/39_is_defined.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 39 is defined
3 | hosts: all
4 | sources:
5 | - replay:
6 | directory: examples/replays/39_is_defined
7 | rules:
8 | - name: r1
9 | condition: event.root is defined
10 | action:
11 | debug:
12 |
--------------------------------------------------------------------------------
/tests/examples/40_in.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 40 in
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 1
8 | rules:
9 | - name: r1
10 | condition: event.i in [0,1,2,3,4]
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/examples/41_not_in.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 41 not in
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 1
8 | rules:
9 | - name: r1
10 | condition: event.i not in [11,21,31,41]
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/examples/42_contains.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 42 contains
3 | hosts: all
4 | sources:
5 | - name: generic
6 | ansible.eda.generic:
7 | payload:
8 | - id_list:
9 | - 1
10 | - 2
11 | - 3
12 | rules:
13 | - name: r1
14 | condition: event.id_list contains 1
15 | action:
16 | debug:
17 |
--------------------------------------------------------------------------------
/tests/examples/43_not_contains.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 43 not contains
3 | hosts: all
4 | sources:
5 | - name: generic
6 | ansible.eda.generic:
7 | payload:
8 | - id_list:
9 | - 1
10 | - 2
11 | - 3
12 | rules:
13 | - name: r1
14 | condition: event.id_list not contains 10
15 | action:
16 | debug:
17 |
--------------------------------------------------------------------------------
/tests/examples/44_in_and.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 44 in and
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i > 3 and event.i in [1,2,3,4]
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/examples/45_in_or.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 45 in or
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i > 5 or event.i in [1,2,3,4]
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/examples/46_job_template.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run job templates
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: "Run job template"
9 | condition: event.i == 1
10 | action:
11 | run_job_template:
12 | name: Demo Job Template
13 | organization: Default
14 | job_args:
15 | extra_vars:
16 | hello: Fred
17 | retries: 1
18 | delay: 10
19 | set_facts: True
20 |
--------------------------------------------------------------------------------
/tests/examples/47_generic_plugin.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 47 Generic Plugin
3 | hosts: all
4 | sources:
5 | - name: generic
6 | ansible.eda.generic:
7 | payload:
8 | - b: true
9 | - i: 42
10 | rules:
11 | - name: r1
12 | condition: event.b
13 | action:
14 | print_event:
15 | - name: r2
16 | condition: event.i == 42
17 | action:
18 | print_event:
19 |
--------------------------------------------------------------------------------
/tests/examples/48_echo.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 48 echo
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 | msg: Hurray it works
14 |
--------------------------------------------------------------------------------
/tests/examples/49_float.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 49 float
3 | hosts: all
4 | sources:
5 | - name: generic
6 | ansible.eda.generic:
7 | payload:
8 | - pi: 3.14159
9 | - mass: 5.97219
10 | - radius: 300.42
11 | rules:
12 | - name: r1
13 | condition: event.pi == 3.14159
14 | action:
15 | debug:
16 | - name: r2
17 | condition: event.mass in [3.14159, 5.97219]
18 | action:
19 | debug:
20 | - name: r3
21 | condition: event.radius > 2.12345e+2
22 | action:
23 | debug:
24 |
--------------------------------------------------------------------------------
/tests/examples/50_negation.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 50 Negation on booleans
3 | hosts: all
4 | sources:
5 | - name: generic
6 | ansible.eda.generic:
7 | payload:
8 | - b: false
9 | - bt: true
10 | - i: 10
11 | - msg: Fred
12 | - j: 9
13 | rules:
14 | - name: r1
15 | condition: not event.b
16 | action:
17 | print_event:
18 | - name: r2
19 | condition: event.bt
20 | action:
21 | print_event:
22 | - name: r3
23 | condition: not (event.i > 50 or event.i < 10)
24 | action:
25 | print_event:
26 | - name: r4
27 | condition: not event.msg == "Barney"
28 | action:
29 | print_event:
30 | - name: r5
31 | condition: not event.j >= 10
32 | action:
33 | print_event:
34 |
--------------------------------------------------------------------------------
/tests/examples/52_once_within.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 52 once within
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | loop_count: 20
7 | payload:
8 | - alert:
9 | level: warning
10 | message: Low disk space
11 | meta:
12 | hosts: HostA
13 | - alert:
14 | level: error
15 | message: Disk failure
16 | meta:
17 | hosts: HostA
18 | rules:
19 | - name: r1
20 | condition: event.alert.level == "warning" or event.alert.level == "error"
21 | action:
22 | debug:
23 | throttle:
24 | once_within: 2 seconds
25 | group_by_attributes:
26 | - event.meta.hosts
27 | - event.alert.level
28 |
--------------------------------------------------------------------------------
/tests/examples/53_once_within_multiple_hosts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 53 once within multiple hosts
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | loop_count: 20
7 | payload:
8 | - alert:
9 | level: warning
10 | message: Low disk space
11 | meta:
12 | hosts: HostA
13 | - alert:
14 | level: warning
15 | message: Low disk space
16 | meta:
17 | hosts: HostB
18 | rules:
19 | - name: r1
20 | condition: event.alert.level == "warning" or event.alert.level == "error"
21 | action:
22 | debug:
23 | throttle:
24 | once_within: 2 seconds
25 | group_by_attributes:
26 | - event.meta.hosts
27 | - event.alert.level
28 |
--------------------------------------------------------------------------------
/tests/examples/54_time_window.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 54 time window
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | create_index: event_index
7 | shutdown_after: 15
8 | event_delay: 5
9 | payload:
10 | - alert:
11 | code: 1001
12 | message: Applying maintenance
13 | - alert:
14 | code: 1002
15 | message: Restarted
16 | rules:
17 | - name: maint cycle
18 | condition:
19 | all:
20 | - event.alert.code == 1001
21 | - event.alert.code == 1002
22 | timeout: 10 seconds
23 | action:
24 | print_event:
25 |
--------------------------------------------------------------------------------
/tests/examples/55_not_all.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 55 not all
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | create_index: event_index
7 | timestamp: true
8 | event_delay: 15
9 | display: false
10 | shutdown_after: 5
11 | payload:
12 | - alert:
13 | code: 1001
14 | message: Applying maintenance
15 | - alert:
16 | code: 1002
17 | message: Restarted
18 | rules:
19 | - name: maint failed
20 | condition:
21 | not_all:
22 | - event.alert.code == 1001
23 | - event.alert.code == 1002
24 | timeout: 10 seconds
25 | action:
26 | debug:
27 | msg: "Not all conditions met"
28 |
--------------------------------------------------------------------------------
/tests/examples/56_once_after.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 56 once after
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | loop_count: 2
7 | loop_delay: 1
8 | timestamp: true
9 | shutdown_after: 15
10 | create_index: event_index
11 | payload:
12 | - alert:
13 | level: warning
14 | message: Low disk space
15 | meta:
16 | hosts: localhost0
17 | - alert:
18 | level: warning
19 | message: Low disk space
20 | meta:
21 | hosts: localhost1
22 | rules:
23 | - name: r1
24 | condition: event.alert.level == "warning" or event.alert.level == "error"
25 | action:
26 | debug:
27 | msg: Once after 10 seconds
28 | throttle:
29 | once_after: 10 seconds
30 | group_by_attributes:
31 | - event.meta.hosts
32 | - event.alert.level
33 |
--------------------------------------------------------------------------------
/tests/examples/59_multiple_actions.yml:
--------------------------------------------------------------------------------
1 | - hosts: all
2 | name: 59 Multiple Actions
3 | sources:
4 | - name: range
5 | range:
6 | limit: 5
7 | delay: 0.05
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | actions:
12 | - debug:
13 | - print_event:
14 | pretty: true
15 | - debug:
16 | msg: "Multiple Action Message1"
17 | - debug:
18 | msg: "Multiple Action Message2"
19 | - name: r2
20 | condition: event.i == 2
21 | action:
22 | debug:
23 | msg: Single Action
24 |
--------------------------------------------------------------------------------
/tests/examples/60_json_filter.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 60 json filter
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | key1:
8 | key2:
9 | f_ignore_1: 1
10 | f_ignore_2: 2
11 | key3:
12 | key4:
13 | f_use_1: 42
14 | f_use_2: 45
15 | filters:
16 | - ansible.eda.json_filter:
17 | include_keys:
18 | - key3
19 | - key4
20 | - f_use*
21 | exclude_keys:
22 | - "*"
23 |
24 | rules:
25 | - name: r1
26 | condition: event.key3.key4.f_use_1 == 42
27 | action:
28 | debug:
29 | msg: Hurray filtering works
30 | - name: r2
31 | condition: event.key1.key2.f_ignore_1 == 1
32 | action:
33 | debug:
34 | msg: Should never fire
35 |
--------------------------------------------------------------------------------
/tests/examples/61_select_1.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 61 select 1
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - name: Fred
8 | age: 54
9 | levels:
10 | - 10
11 | - 20
12 | - 30
13 | - name: Barney
14 | age: 53
15 | levels:
16 | - 11
17 | - 15
18 | - 16
19 | - name: Wilma
20 | age: 53
21 | levels:
22 | - 1
23 | - 5
24 | - 6
25 | rules:
26 | - name: r1
27 | condition: event.levels is select('>', 25)
28 | action:
29 | debug:
30 | msg: Found a player with level greater than 25
31 |
--------------------------------------------------------------------------------
/tests/examples/62_select_2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 62 select 2
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - name: Fred
8 | age: 54
9 | addresses:
10 | - 123 Main St, Bedrock, MI
11 | - 545 Spring St, Cresskill, NJ
12 | - 435 Wall Street, New York, NY
13 | - name: Barney
14 | age: 53
15 | addresses:
16 | - 345 Bleeker St, Bedrock, MI
17 | - 145 Wall St, Dumont, NJ
18 | - name: Wilma
19 | age: 47
20 | addresses:
21 | - 123 Main St, Bedrock, MI
22 | - 432 Raymond Blvd, Newark, NJ
23 | rules:
24 | - name: r1
25 | condition: event.addresses is select('regex', 'Main St')
26 | action:
27 | debug:
28 | msg: Some one lives on Main Street
29 | - name: r2
30 | condition: event.addresses is not select('regex', 'Major St')
31 | action:
32 | debug:
33 | msg: No one lives on Major St
34 |
--------------------------------------------------------------------------------
/tests/examples/63_selectattr_1.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 63 selectattr 1
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - people:
8 | - person:
9 | name: Fred
10 | age: 54
11 | - person:
12 | name: Barney
13 | age: 45
14 | - person:
15 | name: Wilma
16 | age: 23
17 | - person:
18 | name: Betty
19 | age: 25
20 | - friends:
21 | - person:
22 | name: Barney
23 | hobby: golf
24 | - person:
25 | name: Fred
26 | hobby: driving
27 |
28 |
29 | rules:
30 | - name: r1
31 | condition: event.people is selectattr('person.age', '>', 30)
32 | action:
33 | debug:
34 | msg: Has a person greater than 30
35 | - name: r2
36 | condition: event.friends is selectattr('person.name', 'regex', 'Barney|Fred')
37 | action:
38 | debug:
39 | msg: Barney or Fred in friends list
40 |
--------------------------------------------------------------------------------
/tests/examples/64_selectattr_2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 64 selectattr 2
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - people:
8 | - person:
9 | name: Fred
10 | age: 54
11 | - person:
12 | name: Barney
13 | age: 45
14 | - person:
15 | name: Wilma
16 | age: 23
17 | - person:
18 | name: Betty
19 | age: 25
20 | rules:
21 | - name: r1
22 | condition: event.people is selectattr('person.age', 'in', [55,25])
23 | action:
24 | debug:
25 | msg: Found person who is either 55 or 25
26 |
--------------------------------------------------------------------------------
/tests/examples/65_selectattr_3.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 65 selectattr 3
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - person:
8 | name: Fred
9 | age: 54
10 | rules:
11 | - name: r1
12 | # event.person is not an array here its an object
13 | # we convert it to an array of 1
14 | condition: event.person is selectattr('age', '>', 30)
15 | action:
16 | debug:
17 | msg: Has a person greater than 30
18 |
--------------------------------------------------------------------------------
/tests/examples/66_sleepy_playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 66 sleepy playbook
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | create_index: i
7 | loop_count: 5
8 | shutdown_after: 45
9 | payload:
10 | - name: fred
11 | rules:
12 | - name: r1
13 | condition: event.i == 0
14 | action:
15 | print_event:
16 | - name: r2
17 | condition: event.i == 1
18 | action:
19 | run_playbook:
20 | name: playbooks/sleeper.yml
21 | - name: terminate gracefully
22 | hosts: all
23 | sources:
24 | - ansible.eda.generic:
25 | create_index: j
26 | loop_count: 5
27 | shutdown_after: 45
28 | payload:
29 | - name: barney
30 | rules:
31 | - name: r11
32 | condition: event.j == 0
33 | action:
34 | debug:
35 | msg: Next issuing shutdown
36 | - name: r12
37 | condition: event.j == 1
38 | action:
39 | shutdown:
40 | message: Issuing graceful shutdown after 5 seconds
41 | delay: 5.0
42 | kind: graceful
43 |
--------------------------------------------------------------------------------
/tests/examples/67_shutdown_now.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 67 shutdown now
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | create_index: i
7 | loop_count: 5
8 | shutdown_after: 45
9 | payload:
10 | - name: fred
11 | rules:
12 | - name: r1
13 | condition: event.i == 0
14 | action:
15 | print_event:
16 | - name: r2
17 | condition: event.i == 1
18 | action:
19 | run_playbook:
20 | name: playbooks/sleeper.yml
21 | - name: terminate now
22 | hosts: all
23 | sources:
24 | - ansible.eda.generic:
25 | create_index: j
26 | loop_count: 5
27 | shutdown_after: 45
28 | payload:
29 | - name: barney
30 | rules:
31 | - name: r11
32 | condition: event.j == 0
33 | action:
34 | debug:
35 | msg: Next issuing ungraceful shutdown
36 | - name: r12
37 | condition: event.j == 1
38 | action:
39 | shutdown:
40 | message: Issuing shutdown now
41 | kind: now
42 |
--------------------------------------------------------------------------------
/tests/examples/68_disabled_rule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 68 disabled rule
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 | msg: Should get fired
14 | - name: r2
15 | enabled: false
16 | condition: event.i == 2
17 | action:
18 | debug:
19 | msg: Should not get fired
20 |
--------------------------------------------------------------------------------
/tests/examples/69_enhanced_debug.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 69 enhanced debug
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 0
11 | action:
12 | debug:
13 | - name: r2
14 | condition: event.i == 1
15 | action:
16 | debug:
17 | msg: "This is a sample message with {{ event.i }}"
18 | - name: r3
19 | condition: event.i == 2
20 | action:
21 | debug:
22 | msg:
23 | - "Hello World {{ event }}"
24 | - "Hello Java"
25 | - "Hello Java again {{ event }}"
26 | - name: r5
27 | condition: event.i == 4
28 | action:
29 | debug:
30 | var: event.i
31 |
--------------------------------------------------------------------------------
/tests/examples/70_null.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 70 null
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - x: 1
8 | y: null
9 | - persons:
10 | - age: 45
11 | name: Fred
12 | occupation: Dino Driver
13 | - age: 46
14 | name: Barney
15 | occupation: null
16 | - z : null
17 |
18 | rules:
19 | - name: r1
20 | condition: event.x == 1 and event.y == null
21 | action:
22 | print_event:
23 | pretty: true
24 | - name: r2
25 | condition: event.persons is selectattr('occupation', '==', null)
26 | action:
27 | print_event:
28 | pretty: true
29 | - name: r3
30 | condition: event.z in [5,6,7, null]
31 | action:
32 | print_event:
33 | pretty: true
34 |
--------------------------------------------------------------------------------
/tests/examples/72_set_fact_with_type.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 72 set fact with type
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | shutdown_after: 1
7 | payload:
8 | - action: "go"
9 | rules:
10 | - name: r1
11 | condition: event.action == "go"
12 | action:
13 | set_fact:
14 | fact:
15 | var_bool: "{{ my_bool }}"
16 | var_int: "{{ my_int }}"
17 | var_float: "{{ my_float }}"
18 | literal_int: 5
19 | string_int: "5"
20 |
21 | - name: Match the bool
22 | condition: event.var_bool
23 | action:
24 | debug:
25 | msg: "The var bool matches"
26 |
27 | - name: Match the int
28 | condition: event.var_int == 2
29 | action:
30 | debug:
31 | msg: "The var int matches"
32 |
33 | - name: Match the float
34 | condition: event.var_float == 3.123
35 | action:
36 | debug:
37 | msg: "The var int matches"
38 |
39 | - name: Match the literal int
40 | condition: event.literal_int == 5
41 | action:
42 | debug:
43 | msg: "The literal int matches"
44 | - name: Match the string int
45 | condition: event.string_int == "5"
46 | action:
47 | debug:
48 | msg: "The string int matches"
49 |
--------------------------------------------------------------------------------
/tests/examples/73_mix_and_match_list.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 73 mix and match list
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - my_bool: false
8 | - my_str: fred
9 | - my_null: null
10 | - my_int: 42
11 | - my_float: 3.1415
12 |
13 | rules:
14 | - name: Match bool in list
15 | condition: events.my_bool in [null, "fred", false, 42]
16 | action:
17 | print_event:
18 | - name: Match str in list
19 | condition: events.my_str in [null, "fred", false, 42]
20 | action:
21 | print_event:
22 | - name: "Match null in list"
23 | condition: events.my_null in [null, "fred", false, 42]
24 | action:
25 | print_event:
26 | - name: Match int in list
27 | condition: events.my_int in [null, "fred", false, 42]
28 | action:
29 | print_event:
30 | - name: Match float in list
31 | condition: events.my_float in [null, "fred", false, 42, 3.1415]
32 | action:
33 | print_event:
34 |
--------------------------------------------------------------------------------
/tests/examples/74_self_referential.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 74 Self referential
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - x: Fred
8 | y: Fred
9 |
10 | rules:
11 | - name: rule1
12 | condition: event.x == event.y
13 | action:
14 | print_event:
15 |
--------------------------------------------------------------------------------
/tests/examples/75_all_conditions.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 75 all conditions
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - friend_list:
8 | names:
9 | - fred
10 | - barney
11 | - request:
12 | type: Delete
13 | friend_name: fred
14 | rules:
15 | - name: r1
16 | condition:
17 | all:
18 | - event.request.type == "Delete"
19 | - event.friend_list.names is select("search", events.m_0.request.friend_name)
20 | action:
21 | print_event:
22 | pretty: true
23 |
--------------------------------------------------------------------------------
/tests/examples/76_all_conditions.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 76 all conditions
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - request:
8 | type: Delete
9 | friend_name: fred
10 | - request:
11 | type: Delete
12 | friend_name: wilma
13 | - friend_list:
14 | names:
15 | - fred
16 | - barney
17 | - friend_list:
18 | names:
19 | - wilma
20 | - betty
21 | rules:
22 | - name: r1
23 | condition:
24 | all:
25 | - event.request.type == "Delete"
26 | - event.friend_list.names is select("search", events.m_0.request.friend_name)
27 | action:
28 | print_event:
29 | pretty: true
30 |
--------------------------------------------------------------------------------
/tests/examples/77_default_events_ttl.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 77 default events ttl
3 | hosts: all
4 | default_events_ttl: 2 seconds
5 | sources:
6 | - ansible.eda.generic:
7 | event_delay: 4
8 | payload:
9 | - i: 1
10 | - j: 2
11 | - k: 3
12 | rules:
13 | - name: r1
14 | condition:
15 | all:
16 | - event.i == 1
17 | - event.j == 2
18 | action:
19 | print_event:
20 | pretty: true
21 | - name: r2
22 | condition: event.k == 3
23 | action:
24 | print_event:
25 | pretty: true
26 |
--------------------------------------------------------------------------------
/tests/examples/78_complete_retract_fact.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 78 complete retract fact
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | fact:
14 | msg: hello world
15 | creator: Kernighan
16 | - name: r2
17 | condition: event.msg == "hello world"
18 | action:
19 | retract_fact:
20 | fact:
21 | msg: hello world
22 | creator: Kernighan
23 | partial: false
24 | - name: r3
25 | condition: event.msg is not defined
26 | action:
27 | debug:
28 | msg: Complete retract works
29 |
30 |
--------------------------------------------------------------------------------
/tests/examples/79_workflow_template.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run workflow templates
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: "Run workflow template"
9 | condition: event.i == 1
10 | action:
11 | run_workflow_template:
12 | name: Demo Workflow Template
13 | job_args:
14 | extra_vars:
15 | hello: Fred
16 | retries: 1
17 | delay: 10
18 | set_facts: True
19 | organization: Default
20 |
--------------------------------------------------------------------------------
/tests/examples/80_match_multiple_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 80 match multiple rules
3 | hosts: all
4 | match_multiple_rules: true
5 | sources:
6 | - name: range
7 | range:
8 | limit: 5
9 | rules:
10 | - name: r1
11 | condition: event.i == 1
12 | action:
13 | debug:
14 | - name: r11
15 | condition: event.i == 1
16 | action:
17 | print_event:
18 |
--------------------------------------------------------------------------------
/tests/examples/81_match_single_rule.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 81 match single rule
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 | - name: r11
14 | condition: event.i == 1
15 | action:
16 | print_event:
17 |
--------------------------------------------------------------------------------
/tests/examples/82_non_alpha_keys.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: 82 non alpha keys
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - "http://www.example.com": "down"
8 | - urls:
9 | "http://www.example.com": "up"
10 | - नाम: മധു
11 |
12 | rules:
13 | - name: r1
14 | condition: event["http://www.example.com"] == "down"
15 | action:
16 | debug:
17 | msg: "First check worked"
18 | - name: r2
19 | condition: event.urls["http://www.example.com"] == "up"
20 | action:
21 | debug:
22 | msg: "Second check worked"
23 | - name: r3
24 | condition: event["नाम"] is search("മധു", ignorecase=true)
25 | action:
26 | print_event:
27 |
--------------------------------------------------------------------------------
/tests/examples/83_boolean_true.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "83 boolean true"
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 3
8 | rules:
9 | - name: r1
10 | condition: true
11 | action:
12 | print_event:
13 |
--------------------------------------------------------------------------------
/tests/examples/84_job_template_exclude_events.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run job templates without event payload
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - age: 55
8 | name: Fred
9 | zip: 12345
10 | rules:
11 | - name: "Run job template"
12 | condition: event.name == "Fred"
13 | action:
14 | run_job_template:
15 | name: Demo Job Template
16 | organization: Default
17 | include_events: false
18 | job_args:
19 | extra_vars:
20 | name: "{{ event.name }}"
21 |
--------------------------------------------------------------------------------
/tests/examples/85_workflow_template_exclude_events.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run workflow templates without event payload
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - age: 55
8 | name: Fred
9 | zip: "12345"
10 | rules:
11 | - name: "Run workflow template"
12 | condition: event.name == "Fred"
13 | action:
14 | run_workflow_template:
15 | name: Demo Workflow Template
16 | organization: Default
17 | include_events: false
18 | job_args:
19 | extra_vars:
20 | name: "{{ event.name }}"
21 |
--------------------------------------------------------------------------------
/tests/examples/86_job_template_include_events.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run job templates with event payload
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - age: 55
8 | name: Fred
9 | zip: 12345
10 | rules:
11 | - name: "Run job template"
12 | condition: event.name == "Fred"
13 | action:
14 | run_job_template:
15 | name: Demo Job Template
16 | organization: Default
17 | job_args:
18 | extra_vars:
19 | name: "{{ event.name }}"
20 |
--------------------------------------------------------------------------------
/tests/examples/87_workflow_template_include_events.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run workflow templates with event payload
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - age: 55
8 | name: Fred
9 | zip: "12345"
10 | rules:
11 | - name: "Run workflow template"
12 | condition: event.name == "Fred"
13 | action:
14 | run_workflow_template:
15 | name: Demo Workflow Template
16 | organization: Default
17 | job_args:
18 | extra_vars:
19 | name: "{{ event.name }}"
20 |
--------------------------------------------------------------------------------
/tests/examples/88_job_template_no_args.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test run job templates with no args
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - age: 55
8 | name: Fred
9 | zip: 12345
10 | rules:
11 | - name: "Run job template"
12 | condition: event.name == "Fred"
13 | action:
14 | run_job_template:
15 | name: Demo Job Template
16 | organization: Default
17 |
--------------------------------------------------------------------------------
/tests/examples/89_source_error_with_msg.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "89 source error with msg"
3 | hosts: all
4 | sources:
5 | - name: range_fail_with_msg
6 | source_with_exception:
7 | error_msg: "range fail with msg"
8 | rules:
9 | - name: r1
10 | condition: true
11 | action:
12 | print_event:
13 |
--------------------------------------------------------------------------------
/tests/examples/90_source_error_without_msg.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "90 source error without msg"
3 | hosts: all
4 | sources:
5 | - name: range_fail_without_msg
6 | source_with_exception:
7 | error_msg: ""
8 | rules:
9 | - name: r1
10 | condition: true
11 | action:
12 | print_event:
13 |
--------------------------------------------------------------------------------
/tests/examples/91_mask_senstive_variables.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test sensitive variable is masked with missing key
3 | hosts: all
4 | sources:
5 | - ansible.eda.generic:
6 | payload:
7 | - name: Fred
8 | rules:
9 | - name: "Run job template"
10 | condition: event.name == 'Fred'
11 | actions:
12 | - debug:
13 | var: organization
14 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/00.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 0
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/01.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 1
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/02.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 2
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/03.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 3
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/04.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 4
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/05.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 5
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/06.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 6
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/07.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 7
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/08.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 8
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/09.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 9
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/23_nested_data/generate_data.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2022 Red Hat, Inc.
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 |
18 | import json
19 |
20 | for i in range(10):
21 | data = {}
22 |
23 | with open(f"{i:02}.json", "w") as f:
24 | data = dict(root=dict(nested=dict(i=i)))
25 | f.write(json.dumps(data, sort_keys=True, indent=4))
26 |
--------------------------------------------------------------------------------
/tests/examples/replays/24_max_attributes/generate_data.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2022 Red Hat, Inc.
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 |
18 | import json
19 |
20 | MAX_ATTRIBUTES = 250
21 |
22 |
23 | for i in range(1):
24 | data = {}
25 |
26 | with open(f"{i:02}.json", "w") as f:
27 | data = {}
28 | for j in range(MAX_ATTRIBUTES):
29 | data[f"attr_{j}"] = j
30 | f.write(json.dumps(data, sort_keys=True, indent=4))
31 |
--------------------------------------------------------------------------------
/tests/examples/replays/25_max_attributes_nested/generate_data.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2022 Red Hat, Inc.
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 |
18 | import json
19 |
20 | DEPTH = 3
21 | WIDTH = 3
22 |
23 |
24 | def recursive(o, depth):
25 | if depth == 0:
26 | for i in range(WIDTH):
27 | o[f"leaf_{i}"] = i
28 | else:
29 | for i in range(WIDTH):
30 | new_o = dict()
31 | o[f"branch_{i}"] = new_o
32 | recursive(new_o, depth - 1)
33 |
34 |
35 | for i in range(1):
36 | data = {}
37 |
38 | with open(f"{i:02}.json", "w") as f:
39 | data = {}
40 | recursive(data, DEPTH)
41 | f.write(json.dumps(data, sort_keys=True, indent=4))
42 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/00.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 0
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/01.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 1
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/02.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 2
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/03.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 3
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/04.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 4
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/05.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 5
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/06.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 6
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/07.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 7
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/08.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 8
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/09.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "nested": {
4 | "i": 9
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/examples/replays/39_is_defined/generate_data.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2022 Red Hat, Inc.
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 |
18 | import json
19 |
20 | for i in range(10):
21 | data = {}
22 |
23 | with open(f"{i:02}.json", "w") as f:
24 | data = dict(root=dict(nested=dict(i=i)))
25 | f.write(json.dumps(data, sort_keys=True, indent=4))
26 |
--------------------------------------------------------------------------------
/tests/pass1.txt:
--------------------------------------------------------------------------------
1 | pass1
2 |
--------------------------------------------------------------------------------
/tests/playbooks/check_facts_playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Playbook to check if the facts are correct
3 | hosts: localhost
4 | gather_facts: false
5 | tasks:
6 | - name: Fail if the value is missing
7 | ansible.builtin.fail:
8 | msg: "Failing because hello world fact does not match"
9 | when: fact.msg != "hello world"
10 |
11 | - name: Fail if the alpha is missing
12 | ansible.builtin.fail:
13 | msg: "Failing because alpha fact does not match"
14 | when: fact.alpha != 1
15 |
16 | - name: Fail if the beta.location doesn't match
17 | ansible.builtin.fail:
18 | msg: "Failing because beta.location fact does not match"
19 | when: fact.beta.location != "Naboo"
20 |
--------------------------------------------------------------------------------
/tests/playbooks/compare_value.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Retrieve expected value
3 | ansible.builtin.set_fact:
4 | expected_value: "{{ vars_json | from_json | community.general.json_query(item.key) }}"
5 |
6 | - name: Fail the task if mismatch
7 | ansible.builtin.fail:
8 | msg: "{{ item.key }} mismatch"
9 | # since jinja2 doesn't preserve the type we have to do a string comparison
10 | when: expected_value != item.value|string
11 |
--------------------------------------------------------------------------------
/tests/playbooks/fail_and_succeed.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Playbook to fail the first run and succeed the second run
3 | hosts: localhost
4 | gather_facts: false
5 | tasks:
6 | - name: Define a temp file
7 | ansible.builtin.set_fact:
8 | my_path: "{{ rulebook_file_path }}"
9 |
10 | - name: Check that the temp file exists
11 | ansible.builtin.stat:
12 | path: "{{ my_path }}"
13 | register: my_file
14 |
15 | - name: Create the file
16 | ansible.builtin.file:
17 | path: "{{ my_path }}"
18 | state: touch
19 | mode: "0644"
20 | when: not my_file.stat.exists
21 |
22 | - name: Fail if the file does not exist
23 | ansible.builtin.fail:
24 | msg: "Failing because the test file does not exist"
25 | when: not my_file.stat.exists
26 |
27 | - name: Delete the file
28 | ansible.builtin.file:
29 | path: "{{ my_path }}"
30 | state: absent
31 | when: my_file.stat.exists
32 |
--------------------------------------------------------------------------------
/tests/playbooks/hello.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Print Hello World and set as fact
3 | hosts: localhost
4 | gather_facts: false
5 | tasks:
6 | - name: Print Hello World
7 | ansible.builtin.debug:
8 | msg: 'Hello world'
9 |
10 | - name: Print event information
11 | ansible.builtin.debug:
12 | msg: '{{ ansible_eda.event }}'
13 |
14 | - name: Set msg fact
15 | ansible.builtin.set_fact:
16 | msg: 'hello world'
17 | cacheable: true
18 | ...
19 |
--------------------------------------------------------------------------------
/tests/playbooks/hello_events.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Debug Hello event and facts
3 | hosts: all
4 | gather_facts: false
5 | tasks:
6 | - name: Debug Hello event
7 | ansible.builtin.debug:
8 | msg: 'Hello event {{ ansible_eda.event }}'
9 |
10 | - name: Debug Hello facts
11 | ansible.builtin.debug:
12 | msg: 'Hello facts {{ ansible_eda.facts }}'
13 | ...
14 |
--------------------------------------------------------------------------------
/tests/playbooks/hello_world_set_fact.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Set Hello World fact
3 | hosts: localhost
4 | gather_facts: false
5 | tasks:
6 | - name: Debug Hello World
7 | ansible.builtin.debug:
8 | msg: 'Hello world'
9 |
10 | - name: Set Hello World fact
11 | ansible.builtin.set_fact:
12 | msg: 'hello world'
13 | cacheable: true
14 | ...
15 |
--------------------------------------------------------------------------------
/tests/playbooks/inventory.yml:
--------------------------------------------------------------------------------
1 | ---
2 | all:
3 | hosts:
4 | localhost:
5 | ansible_connection: local
6 | ansible_python_interpreter: "{{ansible_playbook_python}}"
7 |
--------------------------------------------------------------------------------
/tests/playbooks/inventory1.yml:
--------------------------------------------------------------------------------
1 | ---
2 | all:
3 | hosts:
4 | localhost0:
5 | ansible_connection: local
6 | localhost1:
7 | ansible_connection: local
8 |
--------------------------------------------------------------------------------
/tests/playbooks/sleeper.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Sleeps for 5 minutes
3 | hosts: all
4 | gather_facts: false
5 | tasks:
6 | - name: Sleepy
7 | ansible.builtin.debug:
8 | msg: 'Hello from Sleepy, will sleep for next 5 minutes'
9 |
10 | - name: snore
11 | ansible.builtin.pause:
12 | minutes: 5
13 | ...
14 |
--------------------------------------------------------------------------------
/tests/playbooks/validate_args_playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Playbook to check if the passed in values in my_vars are correct
3 | hosts: localhost
4 | gather_facts: false
5 | tasks:
6 | - name: Validate rule name
7 | ansible.builtin.fail:
8 | msg: "Rule name did not match"
9 | when: ansible_eda.rule != "r2"
10 | - name: Validate ruleset name
11 | ansible.builtin.fail:
12 | msg: "Rule name did not match"
13 | when: ansible_eda.ruleset != "Test Assert Fact of different data types"
14 | - name: Convert vars to json so we can use nested keys
15 | ansible.builtin.set_fact:
16 | vars_json: "{{ ansible_eda | to_json }}"
17 |
18 | - name: Compare value
19 | ansible.builtin.include_tasks: compare_value.yml
20 | loop: "{{ my_vars | dict2items }}"
21 |
--------------------------------------------------------------------------------
/tests/playbooks/vars.yml:
--------------------------------------------------------------------------------
1 | ---
2 | limit: 2
3 |
--------------------------------------------------------------------------------
/tests/rules/rule_names_with_substitution.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Rules with names being substituted
3 | hosts: localhost
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: "{{ custom.name1 }}"
9 | condition: event.i == 1
10 | action:
11 | debug:
12 | - name: "{{ custom.name2 }}"
13 | condition: event.i == 2
14 | action:
15 | debug:
16 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_assignment.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules with assignment
3 | hosts: localhost
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: assignment
10 | condition: events.first << event.i == 0
11 | action:
12 | debug:
13 | var: events.first
14 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_assignment2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules with assignment2
3 | hosts: localhost
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: assignment
10 | condition: facts.first << fact.i == 0
11 | action:
12 | debug:
13 | var: events.first
14 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_multiple_conditions.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules multiple conditions any
3 | hosts: localhost
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: multiple conditions
10 | condition:
11 | any:
12 | - events.event << event.i == 0
13 | - events.event << event.i == 1
14 | action:
15 | debug:
16 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_multiple_conditions2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules multiple conditions all
3 | hosts: localhost
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: multiple conditions
10 | condition:
11 | all:
12 | - events.first << event.i == 0
13 | - events.second << event.i == 1
14 | action:
15 | debug:
16 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_multiple_conditions3.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules multiple conditions reference assignment
3 | hosts: localhost
4 | sources:
5 | - range:
6 | limit: 5
7 | rules:
8 | - name: multiple conditions
9 | condition:
10 | all:
11 | - events.first << event.i == 0
12 | - events.second << event.i == 1
13 | - events.third << event.i == events.first.i + 2
14 | action:
15 | debug:
16 | first: "{{events.first}}"
17 | second: "{{events.second}}"
18 | third: "{{events.third}}"
19 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_time.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules with time
3 | hosts: localhost
4 | sources:
5 | - tick:
6 | rules:
7 | - name: promote time.tick to current_time fact
8 | condition: event.time.tick is defined
9 | action:
10 | set_fact:
11 | fact:
12 | current_time: "{{event.time.tick}}"
13 | - name: retract current_time fact
14 | condition: fact.current_time is defined
15 | action:
16 | retract_fact:
17 | fact:
18 | current_time: "{{event.current_time}}"
19 | - name: matches current_time fact before it is retracted since facts fire all matching rules
20 | condition: fact.current_time is defined
21 | action:
22 | debug:
23 | - name: shutdown after 5 ticks
24 | condition: fact.current_time >= 5
25 | action:
26 | shutdown:
27 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_timestamp.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules with timestamp
3 | hosts: localhost
4 | sources:
5 | - timestamp:
6 | rules:
7 | - name: promote timestamp.unix_timestamp to current_time fact
8 | condition: event.timestamp.unix_timestamp is defined
9 | action:
10 | set_fact:
11 | fact:
12 | current_time: "{{event.timestamp.unix_timestamp}}"
13 | - name: set the initial time
14 | condition:
15 | all:
16 | - facts.time << fact.current_time is defined
17 | - event.initial_time is not defined
18 | action:
19 | set_fact:
20 | fact:
21 | initial_time: "{{facts.time.current_time}}"
22 | - name: retract current_time fact
23 | condition: fact.current_time is defined
24 | action:
25 | retract_fact:
26 | fact:
27 | current_time: "{{fact.current_time}}"
28 | - name: debug
29 | condition: fact.initial_time is defined
30 | action:
31 | debug:
32 | - name: shutdown
33 | condition:
34 | all:
35 | - facts.a << fact.initial_time is defined
36 | - fact.current_time >= facts.a.initial_time + 5
37 | action:
38 | shutdown:
39 |
--------------------------------------------------------------------------------
/tests/rules/rules_with_vars.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Rules with vars
3 | hosts: localhost
4 | sources:
5 | - range:
6 | limit: "{{limit}}"
7 | rules:
8 | - name: multiple conditions
9 | condition:
10 | all:
11 | - events.first << event.i == 0
12 | - events.second << event.i == 1
13 | action:
14 | debug:
15 |
--------------------------------------------------------------------------------
/tests/rules/rules_without_assignment.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Demo rules multiple conditions all
3 | hosts: localhost
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: assignment
10 | condition: fact.i == 0
11 | action:
12 | debug:
13 | event: "{{event}}"
14 |
--------------------------------------------------------------------------------
/tests/rules/test_blank_rule_name.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test ruleset with blank rule names
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: ' '
10 | condition: event.i == 1
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/rules/test_blank_ruleset_name.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: ' '
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/rules/test_combine_hosts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Combine hosts when run the same playbook
3 | hosts: localhost0, localhost1
4 | sources:
5 | - name: range
6 | range:
7 | limit: 2
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | run_playbook:
13 | name: playbooks/hello_events.yml
--------------------------------------------------------------------------------
/tests/rules/test_combine_hosts_module.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Combine hosts when run the same module
3 | hosts: localhost0, localhost1
4 | sources:
5 | - name: range
6 | range:
7 | limit: 2
8 | rules:
9 | - name: r1
10 | condition: event.i is defined
11 | action:
12 | run_module:
13 | name: ansible.eda.upcase
14 | module_args:
15 | name: Fred Flintstone
--------------------------------------------------------------------------------
/tests/rules/test_duplicate_rule_names.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test ruleset with duplicate rule names
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: rule1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 | - name: rule1
14 | condition: event.i == 2
15 | action:
16 | debug:
17 |
--------------------------------------------------------------------------------
/tests/rules/test_duplicate_ruleset_names.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: ruleset1
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 | - name: ruleset1
14 | hosts: all
15 | sources:
16 | - name: range
17 | range:
18 | limit: 5
19 | rules:
20 | - name: r1
21 | condition: event.i == 1
22 | action:
23 | debug:
24 |
--------------------------------------------------------------------------------
/tests/rules/test_empty_rule_names.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test ruleset with empty rule names
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name:
10 | condition: event.i == 1
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/rules/test_filters.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rule filters
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | filters:
9 | - noop:
10 | rules:
11 | - name: r1
12 | condition: event.i == 0
13 | action:
14 | print_event:
15 | pretty: true
16 | var_root: i
17 | - name: r2
18 | condition: event.i == 1
19 | action:
20 | print_event:
21 | - name: r3
22 | condition: event.i == 2
23 | action:
24 | run_playbook:
25 | name: playbooks/hello_world_set_fact.yml
26 | var_root: i
27 | post_events: true
28 | - name: r4
29 | condition: event.msg is defined
30 | action:
31 | print_event:
32 |
33 |
--------------------------------------------------------------------------------
/tests/rules/test_host_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test host rules
3 | hosts: all
4 | sources:
5 | - name: hosts
6 | hosts:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | ruleset: Test host rules
14 | fact:
15 | j: 1
16 | - name: r2
17 | condition: event.i == 2
18 | action:
19 | run_playbook:
20 | name: playbooks/hello_events.yml
21 | - name: r3
22 | condition: event.i == 3
23 | action:
24 | retract_fact:
25 | ruleset: Test host rules
26 | fact:
27 | j: 3
28 | - name: r4
29 | condition: event.i == 4
30 | action:
31 | post_event:
32 | ruleset: Test host rules
33 | event:
34 | j: 4
35 | - name: r5
36 | condition: event.j is defined
37 | action:
38 | none:
39 |
--------------------------------------------------------------------------------
/tests/rules/test_missing_rule_names.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test ruleset with missing rule names
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - condition: event.i == 1
10 | action:
11 | debug:
12 |
--------------------------------------------------------------------------------
/tests/rules/test_missing_ruleset_name.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: all
3 | sources:
4 | - name: range
5 | range:
6 | limit: 5
7 | rules:
8 | - name: r1
9 | condition: event.i == 1
10 | action:
11 | debug:
12 |
--------------------------------------------------------------------------------
/tests/rules/test_multiple_sources.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test multiple sources
3 | hosts: all
4 | sources:
5 | - range:
6 | limit: 6
7 | - range2:
8 | limit: 5
9 | rules:
10 | - name:
11 | condition: event.range2.i == 2
12 | action:
13 | run_playbook:
14 | name: playbooks/hello_world_set_fact.yml
15 | - name:
16 | condition: +event.range2.i
17 | action:
18 | none:
19 |
--------------------------------------------------------------------------------
/tests/rules/test_rules.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules4
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | ruleset: Test rules4
14 | fact:
15 | j: 1
16 | - name: r2
17 | condition: event.i == 2
18 | action:
19 | run_playbook:
20 | name: playbooks/hello_world_set_fact.yml
21 | - name: r3
22 | condition: event.i == 3
23 | action:
24 | retract_fact:
25 | ruleset: Test rules4
26 | fact:
27 | j: 3
28 | - name: r4
29 | condition: event.i == 4
30 | action:
31 | post_event:
32 | ruleset: Test rules4
33 | event:
34 | j: 4
35 | - name: r5
36 | condition: event.j is defined
37 | action:
38 | none:
39 |
--------------------------------------------------------------------------------
/tests/rules/test_rules_expanded_conditions.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: run playbooks
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: hello1
10 | condition:
11 | any:
12 | - i == 2
13 | - j == 2
14 | action:
15 | run_playbooks:
16 | - name: playbooks/hello_world_set_fact.yml
17 | - name: hello2
18 | condition:
19 | all:
20 | - i == 2
21 | - j == 2
22 | action:
23 | run_playbooks:
24 | - name: playbooks/hello_world_set_fact.yml
25 |
--------------------------------------------------------------------------------
/tests/rules/test_rules_multiple_hosts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules multiple hosts
3 | hosts: localhost0, localhost1
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | ruleset: Test rules multiple hosts
14 | fact:
15 | j: 1
16 | - name: r2
17 | condition: event.i == 2
18 | action:
19 | run_playbook:
20 | name: playbooks/hello_events.yml
21 | - name: r3
22 | condition: event.i == 3
23 | action:
24 | retract_fact:
25 | ruleset: Test rules multiple hosts
26 | fact:
27 | j: 3
28 | - name: r4
29 | condition: event.i == 4
30 | action:
31 | post_event:
32 | ruleset: Test rules multiple hosts
33 | event:
34 | j: 4
35 | - name: r5
36 | condition: event.j is defined
37 | action:
38 | none:
39 |
--------------------------------------------------------------------------------
/tests/rules/test_rules_multiple_hosts2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules multiple hosts 2
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/rules/test_rules_multiple_hosts3.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules multiple hosts 3
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | debug:
13 |
--------------------------------------------------------------------------------
/tests/rules/test_rules_playbooks.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: run playbooks
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name:
10 | condition: i == 2 and j == 2
11 | action:
12 | run_playbooks:
13 | - name: playbooks/hello_world_set_fact.yml
14 |
--------------------------------------------------------------------------------
/tests/rules/test_set_facts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test Assert Fact of different data types
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 1
11 | action:
12 | set_fact:
13 | fact:
14 | msg: hello world
15 | alpha: 1
16 | beta:
17 | name: R2D2
18 | location: "{{ Naboo }}"
19 | - name: r2
20 | condition: event.msg == "hello world"
21 | action:
22 | run_playbook:
23 | name: playbooks/validate_args_playbook.yml
24 | extra_vars:
25 | my_vars:
26 | event.msg: hello world
27 | event.alpha: 1
28 | event.beta.name: R2D2
29 | event.beta.location: "{{ Naboo }}"
30 | copy_files: True
31 |
--------------------------------------------------------------------------------
/tests/rules/test_simple.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules simple
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r1
10 | condition: event.i == 0
11 | action:
12 | print_event:
13 | pretty: true
14 | var_root: i
15 | - name: r2
16 | condition: event.i == 1
17 | action:
18 | print_event:
19 | - name: r3
20 | condition: event.i == 2
21 | action:
22 | run_playbook:
23 | name: playbooks/hello_world_set_fact.yml
24 | var_root: i
25 | post_events: true
26 | - name: r4
27 | condition: event.msg is defined
28 | action:
29 | print_event:
30 |
31 |
--------------------------------------------------------------------------------
/tests/rules/test_states.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules4 Prod
3 | hosts: all
4 | sources:
5 | - name: sensu
6 | topic: sensuprod
7 | url: prod
8 | schema: sensu/v1
9 | - name: datadog
10 | topic: datadogprod
11 | schema: datadog/v1
12 | url: prod
13 | states:
14 | - name: Initial
15 | state: dev
16 | rules:
17 | - name:
18 | condition: sensu.data.i == 1 and datadog.header.k == 2
19 | action:
20 | set_fact:
21 | ruleset: Test rules4 Prod
22 | fact:
23 | j: 1
24 | - name:
25 | condition: i == 2
26 | action:
27 | change_state:
28 | name: production
29 | - name: Production
30 | state: production
31 | rules:
32 | - name:
33 | condition: sensu.data.i == 1 and datadog.header.k == 2
34 | action:
35 | set_fact:
36 | ruleset: Test rules4 Prod
37 | fact:
38 | j: 1
39 | - name:
40 | condition: i == 2
41 | action:
42 | change_state:
43 | name: shutdown
44 | - name: Shutdown
45 | state: shutdown
46 | rules: []
47 |
48 |
--------------------------------------------------------------------------------
/tests/rules/webserver_down.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Automatic Remediation of a webserver
3 | hosts: webservers
4 | sources:
5 | - name: ping web server
6 | ping:
7 | ip: "{{gateway_ip}}"
8 | timeout: 10s
9 | repeats_every: 1s
10 | - name: sensu
11 | sensu:
12 | url: "{{sensu_url}}"
13 | token: "{{sensu_token}}"
14 | host_selector: event.sensu.host
15 | rules:
16 | - name: If webserver is down remediate the problem
17 | condition:
18 | all:
19 | - events.ping << event.ping.timeout == true # no host info
20 | - events.process << event.sensu.process.status == "stopped" # web server
21 | - events.database << event.sensu.storage.percent > 95 # database server
22 | timeout: 5 minute
23 | action:
24 | run_playbook:
25 | name: expand_storage.yml
26 | post_events: true
27 | - name: Validate remediation
28 | condition: event.fixed_storage == true
29 | action:
30 | run_playbook:
31 | name: validate_webserver.yml
32 | ...
33 |
--------------------------------------------------------------------------------
/tests/run_examples.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | function run {
5 | echo "RUNNING $1"
6 | ansible-rulebook --rulebook "./${1}" --inventory ./playbooks/inventory.yml -S ./sources/ &>/dev/null
7 | if [[ $? -ne 0 ]]; then
8 | echo "PROBLEM with $1"
9 | fi
10 | }
11 |
12 | for file in examples/*.yml; do
13 | run $file
14 | done
15 |
--------------------------------------------------------------------------------
/tests/sources/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ansible/ansible-rulebook/da1bed4a19a08e37eb45394248941156692a304f/tests/sources/__init__.py
--------------------------------------------------------------------------------
/tests/sources/hosts.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import asyncio
16 | from typing import Any, Dict
17 |
18 |
19 | async def main(queue: asyncio.Queue, args: Dict[str, Any]):
20 |
21 | for i in range(int(args["limit"])):
22 | await queue.put(dict(i=i, meta=dict(hosts="localhost")))
23 |
24 |
25 | if __name__ == "__main__":
26 |
27 | class MockQueue:
28 | async def put(self, event):
29 | print(event)
30 |
31 | asyncio.run(main(MockQueue(), dict(limit=5)))
32 |
--------------------------------------------------------------------------------
/tests/sources/nested.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import asyncio
16 | from typing import Any, Dict
17 |
18 |
19 | async def main(queue: asyncio.Queue, args: Dict[str, Any]):
20 | delay = args.get("delay", 0)
21 | str_enable = args.get("str_enable", False)
22 |
23 | for i in range(int(args["i_limit"])):
24 | for j in range(int(args["j_limit"])):
25 | payload = {"nested": {"i": i, "j": j}}
26 | if str_enable:
27 | payload = {"nested": {"i": f"{i}", "j": f"{j}"}}
28 | await queue.put(payload)
29 | await asyncio.sleep(delay)
30 |
31 |
32 | if __name__ == "__main__":
33 |
34 | class MockQueue:
35 | async def put(self, event):
36 | print(event)
37 |
38 | asyncio.run(main(MockQueue(), dict(i_limit=5, j_limit=5)))
39 |
--------------------------------------------------------------------------------
/tests/sources/ping.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import subprocess
16 | import time
17 |
18 |
19 | def main(queue, args):
20 |
21 | ips = args.get("ips", [])
22 | delay = args.get("delay", 1)
23 | timeout = str(args.get("timeout", 10))
24 |
25 | if not ips:
26 | return
27 |
28 | while True:
29 |
30 | for ip in ips:
31 |
32 | result = subprocess.call(["ping", "-c", "1", "-t", timeout, ip])
33 | queue.put(
34 | dict(ping=dict(ip=ip, timeout=result != 0, exit_code=result))
35 | )
36 |
37 | time.sleep(delay)
38 |
39 |
40 | if __name__ == "__main__":
41 |
42 | class MockQueue:
43 | def put(self, event):
44 | print(event)
45 |
46 | main(MockQueue(), {"ips": ["127.0.0.1"], "timeout": 1})
47 |
--------------------------------------------------------------------------------
/tests/sources/range.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import asyncio
16 | from typing import Any, Dict
17 |
18 |
19 | async def main(queue: asyncio.Queue, args: Dict[str, Any]):
20 | delay = args.get("delay", 0)
21 |
22 | for i in range(int(args["limit"])):
23 | payload = {"i": i}
24 | await queue.put(payload)
25 | await asyncio.sleep(delay)
26 |
27 |
28 | if __name__ == "__main__":
29 |
30 | class MockQueue:
31 | async def put(self, event):
32 | print(event)
33 |
34 | asyncio.run(main(MockQueue(), dict(limit=5)))
35 |
--------------------------------------------------------------------------------
/tests/sources/range2.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import asyncio
16 | from typing import Any, Dict
17 |
18 |
19 | async def main(queue: asyncio.Queue, args: Dict[str, Any]):
20 | delay = args.get("delay", 0)
21 |
22 | for i in range(int(args["limit"])):
23 | await queue.put(dict(range2=dict(i=i)))
24 | await asyncio.sleep(delay)
25 |
26 |
27 | if __name__ == "__main__":
28 |
29 | class MockQueue:
30 | async def put(self, event):
31 | print(event)
32 |
33 | asyncio.run(main(MockQueue(), dict(limit=5)))
34 |
--------------------------------------------------------------------------------
/tests/sources/replays/01.json:
--------------------------------------------------------------------------------
1 | {
2 | "i": 0
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sources/replays/02.json:
--------------------------------------------------------------------------------
1 | {
2 | "i": 1
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sources/replays/03.json:
--------------------------------------------------------------------------------
1 | {
2 | "i": 2
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sources/replays/04.json:
--------------------------------------------------------------------------------
1 | {
2 | "i": 3
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sources/replays/05.json:
--------------------------------------------------------------------------------
1 | {
2 | "i": 4
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sources/source_with_exception.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import asyncio
16 | from typing import Any, Dict
17 |
18 |
19 | class TestException(Exception):
20 | pass
21 |
22 |
23 | async def main(queue: asyncio.Queue, args: Dict[str, Any]):
24 | error_msg = str(args.get("error_msg", ""))
25 | raise TestException(error_msg)
26 |
27 |
28 | if __name__ == "__main__":
29 |
30 | class MockQueue:
31 | async def put(self, event):
32 | print(event)
33 |
34 | asyncio.run(main(MockQueue(), dict(limit=5)))
35 |
--------------------------------------------------------------------------------
/tests/sources/tick.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import itertools
16 | import time
17 |
18 |
19 | def main(queue, args):
20 |
21 | for i in itertools.count(start=1):
22 | queue.put(dict(time=dict(tick=i)))
23 | time.sleep(1)
24 |
25 |
26 | if __name__ == "__main__":
27 |
28 | class MockQueue:
29 | def put(self, event):
30 | print(event)
31 |
32 | main(MockQueue(), dict(limit=5))
33 |
--------------------------------------------------------------------------------
/tests/sources/timestamp.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Red Hat, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import time
16 | from datetime import datetime
17 |
18 |
19 | def main(queue, args):
20 |
21 | while True:
22 | queue.put(
23 | dict(
24 | timestamp=dict(
25 | unix_timestamp=time.mktime(datetime.now().timetuple())
26 | )
27 | )
28 | )
29 | time.sleep(1)
30 |
31 |
32 | if __name__ == "__main__":
33 |
34 | class MockQueue:
35 | def put(self, event):
36 | print(event)
37 |
38 | main(MockQueue(), dict(limit=5))
39 |
--------------------------------------------------------------------------------
/tests/test_ansible_events.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2022 Red Hat, Inc.
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 |
17 | """Tests for `ansible_rulebook` package."""
18 |
19 | import pytest
20 |
21 |
22 | @pytest.fixture
23 | def response():
24 | """Sample pytest fixture.
25 |
26 | See more at: http://doc.pytest.org/en/latest/fixture.html
27 | """
28 | # import requests
29 | # return requests.get('https://github.com/audreyr/cookiecutter-pypackage')
30 |
31 |
32 | def test_content(response):
33 | """Sample pytest test function with the pytest fixture as an argument."""
34 | # from bs4 import BeautifulSoup
35 | # assert 'GitHub' in BeautifulSoup(response.content).title.string
36 |
--------------------------------------------------------------------------------
/tests/test_simple.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Test rules simple
3 | hosts: all
4 | sources:
5 | - name: range
6 | range:
7 | limit: 5
8 | rules:
9 | - name: r0
10 | condition: event.i == 0
11 | action:
12 | print_event:
13 | pretty: true
14 | var_root: i
15 | - name: r1
16 | condition: event.i == 1
17 | action:
18 | print_event:
19 | - name: r2
20 | condition: event.i == 2
21 | action:
22 | run_playbook:
23 | name: playbooks/hello_world_set_fact.yml
24 | var_root: i
25 | post_events: true
26 | - name: r3
27 | condition: event.msg is defined
28 | action:
29 | print_event:
30 |
31 |
--------------------------------------------------------------------------------
/tests/unit/action/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ansible/ansible-rulebook/da1bed4a19a08e37eb45394248941156692a304f/tests/unit/action/__init__.py
--------------------------------------------------------------------------------
/tests/unit/action/conftest.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 |
3 | import pytest
4 |
5 | from ansible_rulebook.action.control import Control
6 | from ansible_rulebook.action.metadata import Metadata
7 |
8 |
9 | @pytest.fixture
10 | def base_metadata():
11 | return Metadata(
12 | rule="r1",
13 | rule_set="rs1",
14 | rule_uuid="u1",
15 | rule_set_uuid="u2",
16 | rule_run_at="abc",
17 | )
18 |
19 |
20 | # TODO : Seems like asyncio.Queue() in a fixture is causing test failure
21 | @pytest.fixture
22 | def base_control():
23 | return Control(
24 | queue=asyncio.Queue(),
25 | inventory="abc",
26 | hosts=["all"],
27 | variables={"a": 1},
28 | project_data_file="",
29 | )
30 |
--------------------------------------------------------------------------------
/tests/unit/action/playbooks/fail.yml:
--------------------------------------------------------------------------------
1 | - name: Fail the rule
2 | hosts: all
3 | gather_facts: false
4 | tasks:
5 | - name: Fail if we have a rule name defined
6 | when: ansible_eda.rule is defined
7 | ansible.builtin.fail:
8 | msg: "Failed because of Rule name: {{ ansible_eda.rule }}"
9 |
--------------------------------------------------------------------------------
/tests/unit/action/playbooks/rule_name.yml:
--------------------------------------------------------------------------------
1 | - name: Print rule name that called this playbook
2 | hosts: all
3 | gather_facts: false
4 | tasks:
5 | - name: Print rule name
6 | when: ansible_eda.rule is defined
7 | ansible.builtin.debug:
8 | msg: "Rule name: {{ ansible_eda.rule }}"
9 | - name: Set the RuleName as a fact
10 | ansible.builtin.set_fact:
11 | results:
12 | my_rule_name: "{{ ansible_eda.rule }}"
13 | my_rule_set_name: "{{ ansible_eda.ruleset }}"
14 | cacheable: true
15 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = flake8,py39,py310,py311,py312
3 | isolated_build = True
4 |
5 | [travis]
6 | python =
7 | 3.9: py39
8 | 3.10: py310
9 | 3.11: py311
10 | 3.12: py312
11 |
12 | [testenv:flake8]
13 | basepython = python
14 | deps = flake8==5.0.4
15 | commands = flake8 ansible_rulebook tests
16 |
17 | [testenv]
18 | passenv = JAVA_HOME
19 | setenv =
20 | PYTHONPATH = {toxinidir}
21 | deps =
22 | -r{toxinidir}/requirements_dev.txt
23 | ; If you want to make tox run the tests with the same versions, create a
24 | ; requirements.txt with the pinned versions and uncomment the following line:
25 | ; -r{toxinidir}/requirements.txt
26 | commands =
27 | pip install -U pip
28 | pytest --basetemp={envtmpdir}
29 |
30 |
--------------------------------------------------------------------------------