Initial commit

master
jeltz 3 years ago
commit 0771c87e41

1
.gitignore vendored

@ -0,0 +1 @@
/config.yaml

@ -0,0 +1,15 @@
FROM python:3-alpine
LABEL description="A Matrix bot for Alertmanager"
# Instal gcc to build wheels
RUN apk add --no-cache gcc musl-dev
# Force the stdout and stderr streams to be unbuffered
ENV PYTHONUNBUFFERED 1
# Install requirements from PyPI
COPY requirements.txt /var/www/alertbot/
RUN pip install --no-cache-dir -r /var/www/alertbot/requirements.txt
# Copy the all the necessary files
COPY . /var/www/alertbot/
# Move the rigth directory
WORKDIR /var/www/alertbot
EXPOSE 8000
ENTRYPOINT python3 /var/www/alertbot/bot.py

@ -0,0 +1 @@
# Alertbot

118
bot.py

@ -0,0 +1,118 @@
#!/usr/bin/env python3
import argparse
import asyncio
import dataclasses
import logging
import aiohttp.web
import jinja2
import markdown
import nio
import yaml
@dataclasses.dataclass
class Config:
matrix_homeserver: str
matrix_user: str
matrix_password: str
matrix_room: str
webhook_token: str
TEMPLATE = (
"{% if status == 'resolved' %}"
"<b><font color='green'>RÉSOLU</font></b> "
"{% elif labels.severity == 'critical' %}"
"@room <b><font color='red'>CRITIQUE</font></b> "
"{% elif labels.severity == 'warning' %}"
"<b><font color='orange'>ATTENTION</font></b> "
"{% endif %}"
"<b>{{ labels.alertname }}</b> "
"{{ labels.instance }}<br/>"
"<blockquote>{{ annotations.summary }}</blockquote>"
)
async def format_messages(config, src, dest):
env = jinja2.Environment()
template = env.from_string(TEMPLATE)
while True:
message = await src.get()
for alert in message["alerts"]:
rendered = template.render(**alert)
await dest.put((rendered))
async def send_notices(config, messages):
client = nio.AsyncClient(config.matrix_homeserver, config.matrix_user)
await client.login(config.matrix_password)
while True:
formatted = await messages.get()
await client.room_send(
config.matrix_room,
message_type="m.room.message",
content={
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"body": formatted, # à corriger
"formatted_body": formatted,
},
)
async def run_app(config, out, host, port):
async def webhook(request):
tokens = request.query.getall("token", [])
if config.webhook_token not in tokens:
logging.warning("Invalid tokens: %s", tokens)
raise aiohttp.web.HTTPForbidden("Invalid tokens")
message = await request.json()
logging.debug("Incoming message: %s", message)
await out.put(message)
return aiohttp.web.Response()
app = aiohttp.web.Application()
app.add_routes([aiohttp.web.post("/webhook", webhook)])
runner = aiohttp.web.AppRunner(app)
await runner.setup()
await aiohttp.web.TCPSite(runner, host, port).start()
async def main():
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", default="config.yaml")
parser.add_argument("--host", default="*")
parser.add_argument("--port", type=int, default=8000)
args = parser.parse_args()
with open(args.config) as f:
config = yaml.safe_load(f)
config = Config(**config)
messages = asyncio.Queue()
formatted = asyncio.Queue()
logging.info("Started Alertbot on %s:%d", args.host, args.port)
tasks = (
asyncio.create_task(run_app(config, messages, args.host, args.port)),
asyncio.create_task(format_messages(config, messages, formatted)),
asyncio.create_task(send_notices(config, formatted)),
)
# on propage les exceptions
await asyncio.gather(*tasks, return_exceptions=False)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(main())

@ -0,0 +1,7 @@
---
matrix_homeserver: https://example.com
matrix_user: "@alertbot:example.com"
matrix_password: "Ch@ngeMe!?"
matrix_room: "!room:example.com"
webhook_token: "MyVerySecretToken"
...

@ -0,0 +1,12 @@
---
version: '3'
services:
alertbot:
image: alertbot
restart: always
volumes:
- ./config.yaml:/var/www/alertbot/config.yaml:ro
ports:
- 8080:8080
...
Loading…
Cancel
Save