Configure and test an Ansible Rulebook that triggers when it receives a webhook event.
Outcomes
Install the ansible-rulebook package and the ansible.eda content collection.
Create one Ansible Rulebook that triggers when it receives a webhook event and prints payload data from the webhook.
Create another Ansible Rulebook that triggers when it receives a webhook event and appends payload data to a log file.
As the student user on the workstation machine, use the lab command to prepare your environment for this exercise, and to ensure that all required resources are available:
[student@workstation ~]$ lab start intro-webhook
Instructions
On the workstation machine, change to the /home/student/intro-webhook project directory:
[student@workstation ~]$ cd ~/intro-webhook
[student@workstation intro-webhook]$Install the ansible-rulebook package and its dependencies:
[student@workstation intro-webhook]$sudo dnf install ansible-rulebook[sudo] password for student:student..output omitted... Is this ok [y/N]:y..output omitted...
Configure the Ansible project in the /home/student/intro-webhook directory so that the ansible-galaxy command retrieves collections from the classroom's private automation hub.
Enable access to the rh-certified and validated repositories.
Use either VS Code or a command-line tool to examine the ansible.cfg file in the project directory.
Notice that the [galaxy] section has configurations for both the rh-certified and validated repositories, but the configurations are missing the API token.
[defaults] collections_paths = ./collections:/usr/share/ansible/collections [galaxy] server_list = validated, rh-certified [galaxy_server.validated] url=https://hub.lab.example.com/api/galaxy/content/validated/token=<put your token here>[galaxy_server.rh-certified] url=https://hub.lab.example.com/api/galaxy/content/rh-certified/token=<put your token here>
Use a web browser to navigate to the private automation hub at https://hub.lab.example.com, and then log in as student using redhat123 as the password.
If necessary, click the main menu icon at the upper left of the page to display the main menu.
Navigate to → and then click . Copy the API token.
Using the copied token, update both token lines in the ansible.cfg file.
Your token is different from the token displayed in this example.
Save and close the file when done:
...output omitted... [galaxy_server.validated] url=https://hub.lab.example.com/api/galaxy/content/validated/ token=d008a313bfee27f882e6f49f337b41c1fff2ab79[galaxy_server.rh-certified] url=https://hub.lab.example.com/api/galaxy/content/rh-certified/ token=d008a313bfee27f882e6f49f337b41c1fff2ab79
Install the ansible.eda content collection into the collections directory in the project directory.
Install the ansible.eda content collection:
[student@workstation intro-webhook]$ansible-galaxy collection install \ansible.eda -p collections/...output omitted... ansible.eda:1.4.5 was installed successfully
List the installed collections available to the /home/student/intro-webhook directory:
[student@workstation intro-webhook]$ansible-galaxy collection list# /home/student/intro-webhook/collections/ansible_collections Collection Version ------------------------ -------ansible.eda1.4.5...output omitted...
Create and run the webhook_print.yml rulebook.
Create the webhook_print.yml rulebook with the following contents:
---
- name: Listen for events on a webhook
hosts: workstation.lab.example.com
sources:
- name: Match events posted to port 5000
ansible.eda.webhook:
host: 0.0.0.0
port: 5000
rules:
- name: Print output of event.payload
condition: event.payload is defined
action:
run_module:
name: ansible.builtin.debug
module_args:
msg: "{{ event.payload }}"This rulebook uses the ansible.eda.webhook event source that creates a webhook that listens on TCP port 5000.
The rulebook contains a rule that prints the event.payload variable using the ansible.builtin.debug module if the event.payload condition is defined.
Examine the inventory file.
This inventory file only contains the workstation.lab.example.com host.
workstation.lab.example.com
Use the ansible-rulebook command to run the webhook_print.yml rulebook.
Specify the inventory file with the -i option:
[student@workstation intro-webhook]$ansible-rulebook -r webhook_print.yml \-i inventory
Leave this command running in the terminal.
Open a second terminal and use the curl command to send data to the running rulebook, and then examine the output in the first terminal.
Open a second terminal and use the following curl command to send data to the running rulebook:
[student@workstation ~]$curl \--header "Content-Type: application/json" \--request POST \--data '{"log_status": true, "message": "test123"}' \workstation.lab.example.com:5000
This curl command sends a header with the Content-Type key set to application/json.
This states that the data being sent is in the JSON format.
The command sets the request method to POST, and sends the log_status and message keys with their associated values as JSON-formatted data to the workstation.lab.example.com host on TCP port 5000.
The curl command is run from the workstation machine, and consequently does not require opening a port in the firewall for the nonprivileged TCP port 5000.
In the first terminal where the rulebook is running, monitor the output of the rulebook:
...output omitted...
PLAY [wrapper] *****************************************************************
TASK [Module wrapper] **********************************************************
ok: [workstation.lab.example.com] => {
"msg": {
"log_status": true,
"message": "test123"
}
}
TASK [save result] *************************************************************
ok: [workstation.lab.example.com]
PLAY RECAP *********************************************************************
workstation.lab.example.com : ok=2 changed=0 unreachable=0 failed=0 ...The curl command triggered the rulebook and the ansible.builtin.debug module printed the event.payload variable, which contains the log_status and message keys with their associated values.
Close the second terminal and press Ctrl+C in the first terminal to stop the running rulebook.
Create, run, and trigger the webhook_write.yml rulebook.
The rulebook uses the ansible.eda.webhook source and listens on TCP port 5000.
The rulebook defines a condition in a rule where if the event.payload.log_status Boolean is set to true, then the rule uses the run_playbook action to run the provided webhook_log.yml playbook.
The run_playbook action uses the extra_vars option to pass the event.payload.message variable to the playbook as the message variable.
Examine the provided webhook_log.yml playbook:
---
- name: Write webhook messages to log file
hosts: workstation.lab.example.com
gather_facts: true
become: true
become_user: student
vars:
timestamp: "{{ ansible_facts['date_time']['iso8601'] }}"
tasks:
- name: Append the incoming POST message to the log file
ansible.builtin.lineinfile:
path: /home/student/intro-webhook/webhook.log
line: "{{ timestamp }} {{ message }}"
create: true
mode: "0644"Notice that the message variable is not defined in the playbook.
Create the webhook_write.yml rulebook with the following content:
---
- name: Listen for events on a webhook
hosts: workstation.lab.example.com
sources:
- name: Match events posted to port 5000
ansible.eda.webhook:
host: 0.0.0.0
port: 5000
rules:
- name: Print payload message to log file
condition: event.payload.log_status == true
action:
run_playbook:
name: webhook_log.yml
extra_vars:
message: "{{ event.payload.message }}"Run the webhook_write.yml rulebook:
[student@workstation intro-webhook]$ansible-rulebook \-r webhook_write.yml -i inventory
Leave this command running in the terminal.
Open a second terminal and use the following three curl commands to send data to the running rulebook:
[student@workstation ~]$curl \--header "Content-Type: application/json" \--request POST \--data '{"log_status": true, "message": "message 001"}' \workstation.lab.example.com:5000
The log_status Boolean in the second curl command is set to false, which does not match the condition in the rulebook.
[student@workstation ~]$curl \--header "Content-Type: application/json" \--request POST \--data '{"log_status": false, "message": "message 002"}' \workstation.lab.example.com:5000
[student@workstation ~]$curl \--header "Content-Type: application/json" \--request POST \--data '{"log_status": true, "message": "message 003"}' \workstation.lab.example.com:5000
In the first terminal where the rulebook is running, monitor the output of the rulebook:
PLAY [Write webhook messages to log file] ************************************** TASK [Gathering Facts] ********************************************************* ok: [workstation.lab.example.com] TASK [Append the incoming POST message to the log] ***************************** changed: [workstation.lab.example.com] PLAY RECAP ********************************************************************* workstation.lab.example.com : ok=2 changed=1 unreachable=0 failed=0 ... PLAY [Write webhook messages to log file] ************************************** TASK [Gathering Facts] ********************************************************* ok: [workstation.lab.example.com] TASK [Append the incoming POST message to the log] ***************************** changed: [workstation.lab.example.com] PLAY RECAP ********************************************************************* workstation.lab.example.com : ok=2 changed=1 unreachable=0 failed=0 ...
The rulebook ran the webhook_log.yml playbook twice as expected because one of the three curl commands set the log_status key to false.
Close the second terminal and press Ctrl+C in the first terminal to stop the running rulebook.
Examine the webhook.log file that the webhook_log.yml playbook created:
[student@workstation intro-webhook]$ cat webhook.log
2024-01-24T20:13:07Z message 001
2024-01-24T20:14:45Z message 003The content of the log file matches the expectations based on the condition in the webhook_write.yml rulebook.