alarms: integrate ooni alarms
This commit is contained in:
parent
21a5d41e8c
commit
45a6d27c8b
4 changed files with 88 additions and 2 deletions
|
@ -172,7 +172,7 @@ class Alarm(db.Model):
|
||||||
bridge = db.relationship("Bridge", back_populates="alarms")
|
bridge = db.relationship("Bridge", back_populates="alarms")
|
||||||
|
|
||||||
def update_state(self, state: AlarmState, text: str):
|
def update_state(self, state: AlarmState, text: str):
|
||||||
if self.state != state:
|
if self.alarm_state != state:
|
||||||
self.state_changed = datetime.utcnow()
|
self.state_changed = datetime.utcnow()
|
||||||
self.alarm_state = state
|
self.alarm_state = state
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="h2 mt-3">Alarms</h1>
|
<h1 class="h2 mt-3">Alarms</h1>
|
||||||
<h2 class="h3">Proxies</h2>
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-sm">
|
<table class="table table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -11,6 +11,8 @@
|
||||||
<th scope="col">Resource</th>
|
<th scope="col">Resource</th>
|
||||||
<th scope="col">Type</th>
|
<th scope="col">Type</th>
|
||||||
<th scope="col">State</th>
|
<th scope="col">State</th>
|
||||||
|
<th scope="col">Message</th>
|
||||||
|
<th scope="col">Last Update</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -18,11 +20,15 @@
|
||||||
<tr class="bg-{% if alarm.alarm_state.name == "OK" %}success{% elif alarm.alarm_state.name == "UNKNOWN" %}dark{% else %}danger{% endif %} text-light">
|
<tr class="bg-{% if alarm.alarm_state.name == "OK" %}success{% elif alarm.alarm_state.name == "UNKNOWN" %}dark{% else %}danger{% endif %} text-light">
|
||||||
{% if alarm.target == "proxy" %}
|
{% if alarm.target == "proxy" %}
|
||||||
<td>Proxy: {{ alarm.proxy.url }} ({{ alarm.proxy.origin.domain_name }})</td>
|
<td>Proxy: {{ alarm.proxy.url }} ({{ alarm.proxy.origin.domain_name }})</td>
|
||||||
|
{% elif alarm.target == "origin" %}
|
||||||
|
<td>Origin: {{ alarm.origin.domain_name }}</td>
|
||||||
{% elif alarm.target == "service/cloudfront" %}
|
{% elif alarm.target == "service/cloudfront" %}
|
||||||
<td>AWS CloudFront</td>
|
<td>AWS CloudFront</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td>{{ alarm.alarm_type }}</td>
|
<td>{{ alarm.alarm_type }}</td>
|
||||||
<td>{{ alarm.alarm_state.name }}</td>
|
<td>{{ alarm.alarm_state.name }}</td>
|
||||||
|
<td>{{ alarm.text }}</td>
|
||||||
|
<td>{{ alarm.last_updated.strftime("%a, %d %b %Y %H:%M:%S") }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
79
app/terraform/block_ooni.py
Normal file
79
app/terraform/block_ooni.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from app import app
|
||||||
|
from app.extensions import db
|
||||||
|
from app.models import Origin, AlarmState, Alarm
|
||||||
|
|
||||||
|
|
||||||
|
def check_origin(domain_name: str):
|
||||||
|
start_date = (datetime.utcnow() - timedelta(days=2)).strftime("%Y-%m-%dT%H%%3A%M")
|
||||||
|
end_date = datetime.utcnow().strftime("%Y-%m-%dT%H%%3A%M")
|
||||||
|
api_url = f"https://api.ooni.io/api/v1/measurements?domain={domain_name}&since={start_date}&until={end_date}"
|
||||||
|
result = defaultdict(lambda: {"anomaly": 0, "confirmed": 0, "failure": 0, "ok": 0})
|
||||||
|
return _check_origin(api_url, result)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_origin(api_url: str, result: Dict):
|
||||||
|
print(f"Processing {api_url}")
|
||||||
|
req = requests.get(api_url).json()
|
||||||
|
if not req['results']:
|
||||||
|
return result
|
||||||
|
for r in req['results']:
|
||||||
|
not_ok = False
|
||||||
|
for s in ["anomaly", "confirmed", "failure"]:
|
||||||
|
if s in r and r[s]:
|
||||||
|
result[r["probe_cc"]][s] += 1
|
||||||
|
not_ok = True
|
||||||
|
break
|
||||||
|
if not not_ok:
|
||||||
|
result[r["probe_cc"]]["ok"] += 1
|
||||||
|
if req['metadata']['next_url']:
|
||||||
|
return _check_origin(req['metadata']['next_url'], result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def threshold_origin(domain_name):
|
||||||
|
ooni = check_origin(domain_name)
|
||||||
|
for country in ooni:
|
||||||
|
total = sum([
|
||||||
|
ooni[country]["anomaly"],
|
||||||
|
ooni[country]["confirmed"],
|
||||||
|
ooni[country]["failure"],
|
||||||
|
ooni[country]["ok"]
|
||||||
|
])
|
||||||
|
total_blocks = sum([
|
||||||
|
ooni[country]["anomaly"],
|
||||||
|
ooni[country]["confirmed"]
|
||||||
|
])
|
||||||
|
block_perc = round((total_blocks / total * 100), 1)
|
||||||
|
ooni[country]["block_perc"] = block_perc
|
||||||
|
ooni[country]["state"] = AlarmState.CRITICAL if block_perc > 20 else AlarmState.OK
|
||||||
|
ooni[country]["message"] = f"Blocked in {block_perc}% of measurements"
|
||||||
|
return ooni
|
||||||
|
|
||||||
|
|
||||||
|
def set_ooni_alarm(origin_id: int, country: str, state: AlarmState, text: str):
|
||||||
|
alarm = Alarm.query.filter(
|
||||||
|
Alarm.origin_id == origin_id,
|
||||||
|
Alarm.alarm_type == f"origin-block-ooni-{country}"
|
||||||
|
).first()
|
||||||
|
if alarm is None:
|
||||||
|
alarm = Alarm()
|
||||||
|
alarm.origin_id = origin_id
|
||||||
|
alarm.alarm_type = f"origin-block-ooni-{country}"
|
||||||
|
alarm.target = "origin"
|
||||||
|
db.session.add(alarm)
|
||||||
|
alarm.update_state(state, text)
|
||||||
|
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
origins = Origin.query.filter(Origin.destroyed == None).all()
|
||||||
|
for origin in origins:
|
||||||
|
ooni = threshold_origin(origin.domain_name)
|
||||||
|
for country in ooni:
|
||||||
|
set_ooni_alarm(origin.id, country.lower(), ooni[country]["state"], ooni[country]["message"])
|
|
@ -14,6 +14,7 @@ def set_http_alarm(proxy_id: int, state: AlarmState, text: str):
|
||||||
alarm = Alarm()
|
alarm = Alarm()
|
||||||
alarm.proxy_id = proxy_id
|
alarm.proxy_id = proxy_id
|
||||||
alarm.alarm_type = "http-status"
|
alarm.alarm_type = "http-status"
|
||||||
|
alarm.target = "proxy"
|
||||||
db.session.add(alarm)
|
db.session.add(alarm)
|
||||||
alarm.update_state(state, text)
|
alarm.update_state(state, text)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue