Skip to content

Commit c70b5ad

Browse files
committed
Finishes material
1 parent 09e953e commit c70b5ad

1 file changed

Lines changed: 174 additions & 1 deletion

File tree

2024/day27.md

Lines changed: 174 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ ansible \
128128

129129
Go on and check if the web servers are running on the respective hosts.
130130

131-
> [!TIP]
131+
> [!HINT]
132132
> Ansible is **idempotent** - try running the commands again and see how the output differs.
133133
134134
</details>
@@ -166,3 +166,176 @@ ansible-playbook \
166166
```
167167

168168
</details>
169+
170+
### Lab 2: Event-Driven Ansible
171+
172+
<details>
173+
174+
<summary>Receive Generic Events via Webhook</summary>
175+
176+
#### Receive Generic Events via Webhook
177+
178+
If you followed the setup instructions for the EDA lab, you should already have a running EDA instance on the `eda-controller.example.com` VM.
179+
180+
If you navigate to `/etc/edacontroller/rulebook.yml` on the VM, you'll see the following rulebook:
181+
182+
```yaml
183+
---
184+
- name: Listen to webhook events
185+
hosts: all
186+
sources:
187+
- ansible.eda.webhook:
188+
host: 0.0.0.0
189+
port: 5000
190+
rules:
191+
- name: Debug event output
192+
condition: 1 == 1
193+
action:
194+
debug:
195+
msg: "{{ event }}"
196+
197+
- name: Listen to Alertmanager alerts
198+
hosts: all
199+
sources:
200+
- ansible.eda.alertmanager:
201+
host: 0.0.0.0
202+
port: 9000
203+
data_alerts_path: alerts
204+
data_host_path: labels.instance
205+
data_path_separator: .
206+
rules:
207+
- name: Restart MySQL server
208+
condition: event.alert.labels.alertname == 'MySQL not running' and event.alert.status == 'firing'
209+
action:
210+
run_module:
211+
name: ansible.builtin.service
212+
module_args:
213+
name: mysql
214+
state: restarted
215+
- name: Debug event output
216+
condition: 1 == 1
217+
action:
218+
debug:
219+
msg: "{{ event }}"
220+
221+
```
222+
223+
For this part of the lab, the **first rule** is the one we're interested in: It listens to a generic webhook on port `5000` and prints the event's **metadata** to its logs.
224+
225+
To test this, we can use the `curl` command to send a `POST` request to the webhook `/endpoint` from the VM itself:
226+
227+
```console
228+
curl \
229+
-X POST \
230+
-H "Content-Type: application/json" \
231+
-d '{"foo": "bar"}' \
232+
http://localhost:5000/endpoint
233+
```
234+
235+
If you now check the logs of the EDA controller, you should see the following output:
236+
237+
```console
238+
journalctl -fu eda-controller
239+
240+
Jan 11 16:35:29 eda-controller ansible-rulebook[56882]: {'payload': {'foo': 'bar'}, 'meta': {'endpoint': 'endpoint',
241+
'headers': {'Host': 'localhost:5000', 'User-Agent': 'curl/7.76.1', 'Accept': '*/*', 'Content-Length': '21',
242+
'Content-Type': 'application/x-www-form-urlencoded'}, 'source': {'name': 'ansible.eda.webhook', 'type': 'ansible.eda.webhook'},
243+
'received_at': '2024-01-11T15:35:29.798401Z', 'uuid': '6ebf8dd2-60a2-455a-9383-97b81f535366'}}
244+
```
245+
246+
A rule that always evaluates to `true` is not very useful, so let's change the rule to only print the the value of `foo` if the `foo` key is present in the event's payload, and `no foo :(` otherwise:
247+
248+
```yaml
249+
---
250+
- name: Listen to webhook events
251+
hosts: all
252+
sources:
253+
- ansible.eda.webhook:
254+
host: 0.0.0.0
255+
port: 5000
256+
rules:
257+
- name: Foo
258+
condition: event.payload.foo is defined
259+
action:
260+
debug:
261+
msg: "{{ event.payload.foo }}"
262+
- name: No foo
263+
condition: 1 == 1
264+
action:
265+
debug:
266+
msg: "no foo :("
267+
```
268+
269+
Send the same `curl` request again and check the logs, you should see a line saying `bar` now.
270+
271+
Let's also try a `curl` request with a different payload:
272+
273+
```console
274+
curl \
275+
-X POST \
276+
-H "Content-Type: application/json" \
277+
-d '{"bar": "baz"}' \
278+
http://localhost:5000/endpoint
279+
```
280+
281+
This time, the output should be `no foo :(`.
282+
283+
</details>
284+
285+
<details>
286+
287+
<summary>Restarting Services Automatically with EDA</summary>
288+
289+
#### Restarting Services Automatically with EDA
290+
291+
The last lab is more of a demo - it shows how you can use EDA to automatically react on events observed by **Prometheus** and **Alertmanager**.
292+
293+
For this demo, the second **ruleset** in our rulebook is the one we're interested in:
294+
295+
```yaml
296+
- name: Listen to Alertmanager alerts
297+
hosts: all
298+
sources:
299+
- ansible.eda.alertmanager:
300+
host: 0.0.0.0
301+
port: 9000
302+
data_alerts_path: alerts
303+
data_host_path: labels.instance
304+
data_path_separator: .
305+
rules:
306+
- name: Restart MySQL server
307+
condition: event.alert.labels.alertname == 'MySQL not running' and event.alert.status == 'firing'
308+
action:
309+
run_playbook:
310+
playbook: ./playbook.yml
311+
- name: Debug event output
312+
condition: 1 == 1
313+
action:
314+
debug:
315+
msg: "{{ event }}"
316+
```
317+
318+
With this rule, we can restart our MySQL server if it's not running! But how do we get the event to trigger? With **Prometheus** and **Alertmanager**!
319+
320+
When you ran the setup playbook, it installed **Prometheus** and **Alertmanager** on the `eda-controller.example.com` VM. You can access the **Prometheus** UI at `http://<eda-controller-ip>:9090` and the **Alertmanager** UI at `http://<eda-controller-ip>:9093`.
321+
322+
It also installed a **Prometheus exporter** for the **MySQL** database that runs on the server.
323+
324+
With this setup, we can now shut down our MySQL server and see what happens - make sure to watch the output of the EDA controller's logs:
325+
326+
```console
327+
systemctl stop mysql
328+
journalctl -fu edacontroller
329+
```
330+
331+
332+
Within 30-90 seconds, you should see EDA running our **playbook** and restarting the MySQL server. You can track that process by watching the Prometheus/Alertmanager UIs for firing alerts.
333+
334+
Once you see the playbook being executed in the logs, you can check the MySQL state once more:
335+
336+
```console
337+
systemctl status mysql
338+
```
339+
340+
MySQL should be up and running again!
341+
</details>

0 commit comments

Comments
 (0)