11.1 Event Driven Ansible - Basics

In this lab we are going to learn how to use Event Driven Ansible. For the following tasks, server node1 and node2 act as webservers. You can use Lab 4.0 as a guideline.

Task 1

  • Point your webbrowser to the official documentation of ansible-rulebook.
  • Install and configure everything needed to run ansible-rulebook and source plugins.
  • Check the version of ansible-rulebook
Solution Task 1

https://ansible-rulebook.readthedocs.io/en/stable/index.html

Fedora 36+:

1
2
3
4
sudo dnf --assumeyes install java-17-openjdk python3-pip
export JAVA_HOME=/usr/lib/jvm/jre-17-openjdk
pip install ansible ansible-rulebook
ansible-galaxy collection install ansible.eda

Enterprise Linux 9:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
sudo dnf install java-17-openjdk
export JAVA_HOME=/usr/lib/jvm/jre-17-openjdk
sudo dnf install python3-pip
python3 -m venv ~/python
. ~/python/bin/activate
pip install --upgrade pip
pip install ansible ansible-rulebook

ansible-galaxy collection install ansible.eda

sudo dnf install systemd-devel gcc python3-devel

pip install -r  ~/.ansible/collections/ansible_collections/ansible/eda/requirements.txt
1
ansible-rulebook --version

Output on EL9:

1
2
3
4
5
6
version__ = '1.0.0'
Executable location = /home/ansible/python/bin/ansible-rulebook
Drools_jpy version = 0.3.4
Java home = /usr/lib/jvm/java-17-openjdk-17.0.7.0.7-3.el9.x86_64
Java version = 17.0.7
Python version = 3.9.16 (main, Dec  8 2022, 00:00:00) [GCC 11.3.1 20221121 (Red Hat 11.3.1-4)]

Task 2

  • Write a playbook webserver.yml that installs the servers in group web as webservers. See Lab 4.0 for guidelines.
  • Ensure that the playbook also sets a webpage at /var/www/html/index.html.
  • Ensure that the inventory file hosts in the folder inventory has the group web with node1 and node2 as members.
  • Run the playbook webserver.yml and check that the webservers are up and running.
Solution Task 2
1
cat webserver.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
---
- hosts: web
  become: true
  tasks:
    - name: install httpd
      ansible.builtin.dnf:
        name:
          - httpd
          - firewalld
        state: installed
    - name: start and enable httpd
      ansible.builtin.service:
        name: httpd
        state: started
        enabled: yes
    - name: put default webpage
      ansible.builtin.copy:
        content: "Ansible Labs by Puzzle ITC"
        dest: /var/www/html/index.html
        owner: root
        group: root
    - name: start and enable firewalld
      ansible.builtin.service:
        name: firewalld
        state: started
        enabled: yes
    - name: open firewall for http
      firewalld:
        service: http
        state: enabled
        permanent: yes
        immediate: yes
1
cat inventory/hosts
1
2
3
4
5
6
[controller]
control0 ansible_host=<ip-of-control0>

[web]
node1 ansible_host=<ip-of-node1>
node2 ansible_host=<ip-of-node2>
1
2
3
4
ansible-playbook -i inventory/hosts webserver.yml
sudo dnf install -y lynx
lynx http://<ip-of-node1>
lynx http://<ip-of-node2>

Task 3

  • Write a rulebook webserver_rulebook.yml that checks if the webpages on node1 and node2 are up and running.
  • If the webpages are not available anymore, the webserver.yml playbook should be re-run.
  • Use url_check from the ansible.eda collection as the source plugin in your rulebook.
  • Check the availability of the websites every 8 seconds.
Solution Task 3
1
cat webserver_rulebook.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
---
- name: rebuild webservers if site down
  hosts: web
  sources:
    - name: check webserver
      ansible.eda.url_check:
        urls:
          - http://<ip-of-node1>:80/
          - http://<ip-of-node2>:80/
        delay: 8
  rules:
    - name: check if site down and rebuild
      condition: event.url_check.status == "down"
      action:
        run_playbook:
          name: webserver.yml

Task 4

  • Start webserver_rulebook.yml in verbose mode.
  • Stop the httpd service on node1 with ansible from another terminal on control0 and see how the playbook webserver.yml is re-run. (You could also just stop the service directly on node1.)
Solution Task 4
1
2
3
ansible-rulebook --rulebook webserver_rulebook.yml -i inventory/hosts --verbose

ansible node1 -i inventory/hosts -b -m service -a "name=httpd state=stopped"

Task 5

  • Write the rulebook webhook_rulebook.yml that opens a webhook on port 5000 of the control node control0.
  • The rulebook should re-run the playbook webserver.yml if the webhook receives a message matching exactly the string “webservers down”.
  • Use webhook from the ansible.eda collection as the source plugin in your rulebook.
Solution Task 5
1
cat webhook_rulebook.yml 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
---
- name: rebuild webserver if webhook receives message that matches rule condition
  hosts: web
  sources:
    - name: start webhook and listen for messages
      ansible.eda.webhook:
        host: 0.0.0.0
        port: 5000
  rules:
    - name: rebuild webserver if monitoring tool sends alert
      condition: event.payload.message == "webservers down"
      action:
        run_playbook:
          name: webserver.yml

Task 6

  • Run the rulebook webhook_rulebook.yml in verbose mode.
  • Send the string “webservers running” to the webhook.
  • You can do this by issuing: curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers running\"}" 127.0.0.1:5000/endpoint
  • See how the message is received, processed, but no actions are taken since the message doesn’t match the condition defined.
  • Now send the message “webservers down” to the webhook. See how the playbook webserver.yml is run.
Solution Task 6
1
ansible-rulebook --rulebook webhook_rulebook.yml -i inventory/hosts --verbose
1
curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers running\"}" 127.0.0.1:5000/endpoint
1
curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers down\"}" 127.0.0.1:5000/endpoint

Task 7

  • Write the rulebook complex_rulebook.yml. It has to meet the following requirements:
  • It should check for three things:
    • check if the website on one of the two webservers is down. (Same as Task 3 above)
    • check if the message matches exactly the string “webservers down” (Same as Task 5 above)
    • check if the message contains the string “ERROR” or “error”
  • If one of the criterias above are met, do two things:
    1. run the ansible shell module to print the string “WEBSERVER ISSUES, REMEDIATION IN PROGRESS.” into the journald log. (Use the command systemd-cat echo "WEBSERVER ISSUES, REMEDIATION IN PROGRESS.")
    2. run playbook webservers.yml
  • Start the rulebook complex_rulebook.yml and send the message “webservers down” to the webhook again.
Solution Task 7
1
cat complex_rulebook.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
- name: rebuild webserver if webhook receives message that matches rule condition
  hosts: web
  sources:
    - name: check webserver
      ansible.eda.url_check:
        urls:
          - http://<ip-of-node1>:80/
          - http://<ip-of-node2>:80/
        delay: 8
    - name: start webhook and listen for messages
      ansible.eda.webhook:
        host: 0.0.0.0
        port: 5000
  rules:
    - name: rebuild webserver if any source reports an alert
      condition:
        any:
          - event.url_check.status == "down"
          - event.payload.message == "webservers down"
          - event.payload.message is search("ERROR",ignorecase=true)
      actions:
        - run_module:
            name: ansible.builtin.shell
            module_args:
              cmd: "systemd-cat echo \"WEBSERVER ISSUES, REMEDIATION IN PROGRESS.\""
        - run_playbook:
            name: webserver.yml
1
ansible-rulebook --rulebook complex_rulebook.yml -i inventory/hosts --verbose
1
curl -H 'Content-Type: application/json' -d "{\"message\": \"webservers down\"}" 127.0.0.1:5000/endpoint

Note, that you would have to open port 5000 on the firewall if the curl command is not sent from the controller itself.

Task 8

Solution Task 8

Event Driven Ansible on Github

All done?