Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add new EDA server labs and refactor #215

Merged
merged 6 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions content/en/docs/11/02/_index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
---
title: 11.2. Event Driven Ansible - Events and Facts
weight: 112
sectionnumber: 11
---

In this lab we will have a closer look at events and facts.

### Task 1

* Copy the rulebook from Lab 11.2 Task 3 to a new one with the name `debug_event_rulebook.yml`.
* Substitute the `run_playbook` action with a `debug` action.
* That debug action should print out all information from the event.
* Stop the httpd service on node1.
* Run the rulebook in verbose mode. The debug action should show all information about the event.

{{% details title="Solution Task 1" %}}
```bash
cat debug_event_rulebook.yml
```
```bash
---
- name: show event json 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 debug
condition: event.url_check.status == "down"
action:
debug:
var: event
```
```bash
ansible node1 -i inventory/hosts -b -m service -a "name=httpd state=stopped"
```
```bash
ansible-rulebook --rulebook debug_event_rulebook.yml -i inventory/hosts -vv
```
```bash
...
2023-06-26 15:04:55,381 - ansible_rulebook.rule_set_runner - INFO - call_action debug
2023-06-26 15:04:55,381 - ansible_rulebook.rule_set_runner - INFO - substitute_variables [{'var': 'event'}] [{'event': {'url_check': {'error_msg': "Cannot connect to host 5.102.146.223:80 ssl:default [Connect call failed ('5.102.146.223', 80)]", 'url': 'http://5.102.146.223/', 'status': 'down'}, 'meta': {'received_at': '2023-06-26T13:04:55.379428Z', 'source': {'name': 'check webserver', 'type': 'ansible.eda.url_check'}, 'uuid': '6710f9a8-c489-4699-a804-8e796855e290'}}}]
2023-06-26 15:04:55,381 - ansible_rulebook.rule_set_runner - INFO - action args: {'var': 'event'}
{'url_check': {'error_msg': "Cannot connect to host 5.102.146.223:80 ssl:default [Connect call failed ('5.102.146.223', 80)]", 'url': 'http://5.102.146.223/', 'status': 'down'}, 'meta': {'received_at': '2023-06-26T13:04:55.379428Z', 'source': {'name': 'check webserver', 'type': 'ansible.eda.url_check'}, 'uuid': '6710f9a8-c489-4699-a804-8e796855e290'}}
...
```
{{% /details %}}

### Task 2

* Rewrite the rulebook `debug_event_rulebook.yml`:
* Use a `run_playbook` action to start a playbook named `sos.yml`
* The playbook `sos.yml` should create an unattended sos report labeled with the fully qualified collection name of the source plugin used. Be sure to install the appropriate packages so that the sos report can be created.
* The name of the source plugin should be taken from the json output as a variable.
* The creation of the sos report takes quite some time.
* Ensure that the condition is throttled to run the action once within 5 minutes at most.
* The delay of the source check should stay at 8 seconds.
* Run the rulebook `debug_event_rulebook.yml` and ensure the sos reports on the webservers have the needed label.


{{% alert title="Note" color="primary" %}}
There are good onlinetools to convert [one-line json to multiline json](https://jsonformatter.curiousconcept.com) as well as [json to yaml converters](https://jsonformatter.org/json-to-yaml). Note: The json copied from the output has sometimes single quotes, RFC 8259 demands double quotes. Be sure that your converter fixes this as well. These converters can come in handy for easier reading of the output.
{{% /alert %}}

{{% details title="Solution Task 2" %}}
See the documentation on how to [throttle event storms](https://ansible.readthedocs.io/projects/rulebook/en/stable/conditions.html#throttle-actions-to-counter-event-storms-reactive).

```bash
cat debug_event_rulebook.yml
```
```bash
---
- name: run sos playbook 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"
throttle:
once_within: 5 minutes
group_by_attributes:
- event.meta.source.type
action:
run_playbook:
name: sos.yml
```

```bash
cat sos.yml
```
```bash
---
- hosts: web
become: true
tasks:
- name: install sos package
ansible.builtin.dnf:
name:
- sos
state: installed

- name: create a sos report unattended containing no sensitive information
ansible.builtin.command: |
"sos report --clean --batch --label {{ ansible_eda.event.meta.source.type }}"
```

```bash
ansible-rulebook --rulebook debug_event_rulebook.yml -i inventory/hosts -vv
```
```bash
...
2023-06-28 11:15:53,766 - ansible_rulebook.builtin - INFO - ruleset: show event \
json if site down, rule: check if site down and rebuild
2023-06-28 11:15:53,766 - ansible_rulebook.builtin - INFO - Calling Ansible runner

PLAY [web] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [node1]

TASK [install sos package] *****************************************************
ok: [node1]

TASK [create a sos report unattended containing no sensitive information] ******
changed: [node1]
...
PLAY RECAP *********************************************************************
node1 : ok=3 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
2023-06-28 11:17:59,741 - ansible_rulebook.builtin - INFO - Ansible Runner \
Queue task cancelled
2023-06-28 11:17:59,742 - ansible_rulebook.builtin - INFO - Playbook rc: 0, \
status: successful
...
```
{{% /details %}}

### All done?

* [Preview of AAP EDA-Controller GUI](https://www.youtube.com/watch?v=7i_EzHyrKQc&t=178s)
235 changes: 235 additions & 0 deletions content/en/docs/11/03/_index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
---
title: 11.3. EDA-Server
weight: 113
sectionnumber: 11
---

In this lab we will learn how to use EDA-Server to run our rulebooks. Some tasks have to be done on Ascender.

### Task 1

To connect your EDA-Server to your Ansible Controller, you have to create an access token on Ascender and add it to EDA-Server

* On Ascender, create an access token for the user Ansible. Be sure to chose the write scope
* On EDA-Server add this controller token to the user Ansible

{{% details title="Solution Task 1" %}}

Go to the Ascender Web-GUI

* On the left hand side, chose `Access`, then `Users`
* Click on user `ansible`, then chose the tab `Tokens` and klick on the blue butten `Add`
friendlypenguin marked this conversation as resolved.
Show resolved Hide resolved
* Leave the `Application` field empty, add a description and chose the write scope.
* Click the `Save` button. Copy the Token from the popup window. This token is shown only once, so remember it.

Go to the EDA-Server Web-GUI

* On the left hand side, chose `User Access` and then `Users`
friendlypenguin marked this conversation as resolved.
Show resolved Hide resolved
* On the right, chose user `ansible`
* Now to to the tab `Controller Tokens`
friendlypenguin marked this conversation as resolved.
Show resolved Hide resolved
* Click on the button `Create controller token`. If you created already one, you have to delete it first to be able to create a new one.
* Enter a name, a description and paste in the token from Ascender in the `Token` field

{% /details %}}

### Task 2

Now we add a git repository with our rulebooks as a project to EDA-Server

* Be sure, your ansible rulebooks are residing in a toplevel folder "rulebooks" inside your git repository
friendlypenguin marked this conversation as resolved.
Show resolved Hide resolved
* Add a Project to EDA-Server pointing to your git repository

{{% alert title="Note" color="primary" %}}
After creation the status of the project will be `failed` as long as you don't have a directory `extensions/eda/rulebooks` or `rulebooks` (relative to the root of the repository) present.
{{% /alert %}}

{{% details title="Solution Task 2" %}}

* On the left side navigate to `Resources` and then `Projects`.
* On the right side click on the `Create project` button.
* Enter a name, description, leave `SCM Type` as `Git`.
* As `SCM URL` enter the path to your git repository on your Controller node (`https://<yourname>-controller.workshop.puzzle.ch:4000/ansible/techlab`). Remember to use port 4000.
* Leave the `Credential` field empty.
* Clink on `Create project` at the bottom of the page.

{{% /details %}}


### Task 3

The last step needed to be able to run rulebooks is creating a Decision Environment.

* Install `ansible-builder` with pip on your `<yourname>-edaserver`. Be sure to install `podman` as well since it's the default container engine for `ansible-builder`.
* Prepare a yaml file `techlab-de.yml` with the definition for your Decision Environment. Take the [blueprint from the ansible-rulebook Github project](https://github.com/ansible/ansible-rulebook/blob/main/minimal-decision-environment.yml) as your base.
* Build the Decision Environment, name the image `techlab-de.yml` and tag it with `latest`.
* Push it to the container registry provided by your teacher.

{{% details title="Solution Task 3" %}}
```bash
pip3 install -y ansible-builder podman
```
```bash
cat techlab-de.yml
```
```
---
version: 3
images:
base_image:
name: 'registry.access.redhat.com/ubi9/python-311:latest'
dependencies:
galaxy:
collections:
- ansible.eda
python:
- azure-servicebus
- aiobotocore
- aiohttp
- aiokafka
- watchdog
- systemd-python
- dpath
- ansible-rulebook
ansible_core:
package_pip: ansible-core==2.14.4
ansible_runner:
package_pip: ansible-runner
system:
- java-17-openjdk-devel [platform:rpm]
```
```bash

```
```bash
ansible-builder build -f techlab-de.yml -t techlab-de:latest
```
```bash
podman login https://<registry_url> -u <username> -p <password>
podman push techlab-de:latest <registry_url>/techlab-de:latest
```

{{% /details %}}

### Task 4

* Add the Decision Environment `techlab-de` you just created to EDA-Server


{{% details title="Solution Task 4" %}}

* On the left side of the EDA-Server Web-GUI navigate to `Resources` then `Decision Environments`.
* On the right side, click on `Create decision environemnt`.
* Enter a name and description.
* In the `Image` field enter the path with tag to your Decision Environment (`<registry_url>/techlab-de:latest`)
* Leave the `Credentials` field empty
* Click on `Create decision environment` at the bottom of the page.

{{% /details %}}

### Task 5

Now have everything ready to run a ansible-rulebook. Ensure you have a job template `Provision_Webserver` in the Organization `Techlab` of your Ascender server. See the Ascender labs to set it up.

Make the following changes to your `webserver_rulebook.yml` rulebook (Lab 11.1):

* Change the action of the rulebook to start a job template `Provision_Webserver` in the organization `Techlab`.
* Be sure to push the changes into your git repository.
* On the EDA-Server create a `Rulebook Activation`

{{% details title="Solution Task 5" %}}
```bash
cat webserver_rulebook.yml
```
```yaml
---
- name: rebuild webservers if site down
hosts: web
sources:
- name: check webserver
ansible.eda.url_check:
urls:
- http://<yourname>-node1.workshop.puzzle.ch:80/
- http://<yourname>-node2.workshop.puzzle.ch:80/
delay: 8
rules:
- name: check if site down and rebuild
condition: event.url_check.status == "down"
action:
run_job_template:
name: Provision_Webserver
organization: Techlab
```

* On the left side of the EDA-Server GUI, navigate to `Views`, then `Rulebook Activiations`
* On the right side click `Create rulebook activation`
* Enter the name `Webserver Provisioning`, add a description and chose the project `Techlab Repo`.
* Chose `webserver_rulebook.yml` in the `Rulebook` field.
* (if no Rulebook shows up, sync the project)
* Chose `techlab-de` in the `Decision environment` field.
* Leave `Restart policy` set to `On failure`.
* Click `Create rulebook activation` at the bottom of the page.

{{% /details %}}

### Task 6

After a successful creation of the `Rulebook Activation` you can follow its logs

* Navigate to `Views`, then `Rulebook Activations` on the left side and then click on your `Webserver Provisioning` Rulebook Activation.
* Click on the `History` tab.
* Now click on the running instance ot the activation.
* In the `Output` field have a look at the logs

{{% details title="Solution Task 6" %}}

Output filed of the activation:

```bash
2023-11-08 14:31:09,925 - ansible_rulebook.app - INFO - Starting worker mode
2023-11-08 14:31:09,925 - ansible_rulebook.websocket - INFO - websocket ws://edaserver-app-daphne:8001/api/eda/ws/ansible-rulebook connecting
2023-11-08 14:31:09,958 - ansible_rulebook.websocket - INFO - websocket ws://edaserver-app-daphne:8001/api/eda/ws/ansible-rulebook connected
2023-11-08 14:31:09,996 - ansible_rulebook.job_template_runner - INFO - Attempting to connect to Controller https://puzzle-ascender.workshop.puzzle.ch
2023-11-08 14:31:10,106 - ansible_rulebook.app - INFO - AAP Version 23.1.0
2023-11-08 14:31:10,106 - ansible_rulebook.app - INFO - Starting sources
2023-11-08 14:31:10,107 - ansible_rulebook.app - INFO - Starting rules
2023-11-08 14:31:10,107 - ansible_rulebook.engine - INFO - run_ruleset
2023-11-08 14:31:10,109 - drools.ruleset - INFO - Using jar: /usr/local/lib/python3.9/site-packages/drools/jars/drools-ansible-rulebook-integration-runtime-1.0.5-SNAPSHOT.jar
2023-11-08 14:31:10 669 [main] INFO org.drools.ansible.rulebook.integration.api.rulesengine.AbstractRulesEvaluator - Start automatic pseudo clock with a tick every 100 milliseconds
2023-11-08 14:31:10,673 - ansible_rulebook.engine - INFO - ruleset define: {"name": "rebuild webservers if site down", "hosts": ["web"], "sources": [{"EventSource": {"name": "check webserver", "source_name": "ansible.eda.url_check", "source_args": {"urls": ["http://puzzle-node1.workshop.puzzle.ch:80/"], "delay": 8}, "source_filters": []}}], "rules": [{"Rule": {"name": "check if site down and rebuild", "condition": {"AllCondition": [{"EqualsExpression": {"lhs": {"Event": "url_check.status"}, "rhs": {"String": "down"}}}]}, "actions": [{"Action": {"action": "run_job_template", "action_args": {"name": "Provision_Webserver", "organization": "Puzzle"}}}], "enabled": true}}]}
2023-11-08 14:31:10,690 - ansible_rulebook.engine - INFO - load source
2023-11-08 14:31:11,166 - ansible_rulebook.engine - INFO - load source filters
2023-11-08 14:31:11,167 - ansible_rulebook.engine - INFO - loading eda.builtin.insert_meta_info
2023-11-08 14:31:11,586 - ansible_rulebook.engine - INFO - Calling main in ansible.eda.url_check
2023-11-08 14:31:11,587 - ansible_rulebook.websocket - INFO - feedback websocket ws://edaserver-app-daphne:8001/api/eda/ws/ansible-rulebook connecting
```
{{% /details %}}

### Task 7

Now, we stop the webserver on node1 and see in the logs of the rulebook activation how the rule triggers the action to start the job template on ascender and rebuild the webservers.

{{% details title="Solution Task 7" %}}

On `<yourname>-node1.workshop.puzzle.ch`:

```bash
sudo systemctl stop httpd
```

In the logs on EDA-Server (see the last task to navigate there):
```bash
...
2023-11-08 14:33:27 847 [main] INFO org.drools.ansible.rulebook.integration.api.rulesengine.RegisterOnlyAgendaFilter - Activation of effective rule "check if site down and rebuild" with facts: {m={url_check={url=http://puzzle-node1.workshop.puzzle.ch:80/, status=down, error_msg=Cannot connect to host puzzle-node1.workshop.puzzle.ch:80 ssl:default [Connect call failed ('5.102.145.36', 80)]}, meta={source={name=check webserver, type=ansible.eda.url_check}, received_at=2023-11-08T14:33:27.845005Z, uuid=65c50f85-89af-4ab3-ac25-81a1f951c469}}}
2023-11-08 14:33:27,848 - ansible_rulebook.rule_generator - INFO - calling check if site down and rebuild
2023-11-08 14:33:40,545 - ansible_rulebook.rule_set_runner - INFO - Task action::run_job_template::rebuild webservers if site down::check if site down and rebuild finished, active actions 0
2023-11-08 14:33:40,550 - ansible_rulebook.rule_set_runner - INFO - call_action run_job_template
2023-11-08 14:33:40,552 - ansible_rulebook.rule_set_runner - INFO - substitute_variables [{'name': 'Provision_Webserver', 'organization': 'Puzzle'}] [{'event': {'url_check': {'url': 'http://puzzle-node1.workshop.puzzle.ch:80/', 'status': 'down', 'error_msg': "Cannot connect to host puzzle-node1.workshop.puzzle.ch:80 ssl:default [Connect call failed ('5.102.145.36', 80)]"}, 'meta': {'source': {'name': 'check webserver', 'type': 'ansible.eda.url_check'}, 'received_at': '2023-11-08T14:33:27.845005Z', 'uuid': '65c50f85-89af-4ab3-ac25-81a1f951c469'}}}]
2023-11-08 14:33:40,552 - ansible_rulebook.rule_set_runner - INFO - action args: {'name': 'Provision_Webserver', 'organization': 'Puzzle'}
2023-11-08 14:33:40,552 - ansible_rulebook.action.run_job_template - INFO - running job template: Provision_Webserver, organization: Puzzle
2023-11-08 14:33:40,552 - ansible_rulebook.action.run_job_template - INFO - ruleset: rebuild webservers if site down, rule check if site down and rebuild
2023-11-08 14:34:01,225 - ansible_rulebook.rule_set_runner - INFO - Task action::run_job_template::rebuild webservers if site down::check if site down and rebuild finished, active actions 0
```

Check the webpage `http://<yourname>-node1.workshop.puzzle.ch/` in your internet browser and ensure the page is available again.

{{% /details %}}