— Add Apprise as notification way (fix #50)

This commit is contained in:
Luc Didry 2024-09-04 17:13:22 +02:00
parent 7998333fc1
commit 6c3c44f5be
No known key found for this signature in database
GPG key ID: EA868E12D0257E3C
7 changed files with 166 additions and 15 deletions

View file

@ -5,6 +5,7 @@
- 💄 — Improve email and gotify notifications
- ✨ — Add command to test gotify configuration
- ✨ — Add nagios command to use as a Nagios probe
- ✨ — Add Apprise as notification way (#50)
## 0.3.1

View file

@ -678,6 +678,73 @@ async def test_gotify(config, domain, severity):
)
@server.command()
@click.option(
"--config",
default="argos-config.yaml",
help="Path of the configuration file. "
"If ARGOS_YAML_FILE environment variable is set, its value will be used instead.",
envvar="ARGOS_YAML_FILE",
callback=validate_config_access,
)
@click.option("--domain", help="Domain for the notification", default="example.org")
@click.option("--severity", help="Severity", default="CRITICAL")
@click.option(
"--apprise-group", help="Apprise group for the notification", required=True
)
@coroutine
async def test_apprise(config, domain, severity, apprise_group):
"""Send a test apprise notification"""
os.environ["ARGOS_YAML_FILE"] = config
from datetime import datetime
from argos.logging import set_log_level
from argos.server.alerting import notify_with_apprise
from argos.server.main import read_config
from argos.server.models import Result, Task
conf = read_config(config)
if not conf.general.apprise:
click.echo("Apprise notifications are not configured, cannot test", err=True)
sysexit(1)
else:
now = datetime.now()
task = Task(
url=f"https://{domain}",
domain=domain,
check="body-contains",
expected="foo",
frequency=1,
selected_by="test",
selected_at=now,
)
result = Result(
submitted_at=now,
status="success",
context={"foo": "bar"},
task=task,
agent_id="test",
severity="ok",
)
class _FalseRequest:
def url_for(*args, **kwargs):
return "/url"
set_log_level("debug")
notify_with_apprise(
result,
task,
severity=severity,
old_severity="OLD SEVERITY",
group=conf.general.apprise[apprise_group],
request=_FalseRequest(),
)
@server.command(short_help="Nagios compatible severities report")
@click.option(
"--config",

View file

@ -23,7 +23,10 @@ general:
frequency: "1m"
# Which way do you want to be warned when a check goes to that severity?
# "local" emits a message in the server log
# Youll need to configure mail and gotify below to be able to use them here.
# Youll need to configure mail, gotify or apprise below to be able to use
# them here.
# Use "apprise:john", "apprise:team" (with the quotes!) to use apprise
# notification groups.
alerts:
ok:
- local
@ -58,6 +61,17 @@ general:
# tokens:
# - foo
# - bar
# See https://github.com/caronc/apprise#productivity-based-notifications
# for apprises URLs syntax.
# You need to surround the URLs with quotes like in the examples below.
# Use "apprise:john", "apprise:team" (with the quotes!) in "alerts" settings.
# apprise:
# john:
# - "mastodon://access_key@hostname/@user"
# - "matrixs://token@hostname:port/?webhook=matrix"
# team:
# - "mmosts://user@hostname/authkey"
# - "nctalks://user:pass@host/RoomId1/RoomId2/RoomIdN"
service:
secrets:

View file

@ -168,6 +168,7 @@ class General(BaseModel):
alerts: Alert
mail: Optional[Mail] = None
gotify: Optional[List[GotifyUrl]] = None
apprise: Optional[Dict[str, List[str]]] = None
@field_validator("frequency", mode="before")
def parse_frequency(cls, value):

View file

@ -4,14 +4,24 @@ import smtplib
from typing import List
from urllib.parse import urlparse
import apprise
import httpx
from argos.checks.base import Severity
from argos.logging import logger
from argos.schemas.config import Config, Mail, GotifyUrl
# XXX Implement mail alerts https://framagit.org/framasoft/framaspace/argos/-/issues/15
# XXX Implement gotify alerts https://framagit.org/framasoft/framaspace/argos/-/issues/16
def get_icon_from_severity(severity: str) -> str:
icon = ""
if severity == Severity.OK:
icon = ""
elif severity == Severity.WARNING:
icon = "⚠️"
elif severity == Severity.UNKNOWN:
icon = ""
return icon
def handle_alert(config: Config, result, task, severity, old_severity, request):
@ -39,20 +49,52 @@ def handle_alert(config: Config, result, task, severity, old_severity, request):
result, task, severity, old_severity, config.general.gotify, request
)
if config.general.apprise is not None:
for notif_way in getattr(config.general.alerts, severity):
if notif_way.startswith("apprise:"):
group = notif_way[8:]
notify_with_apprise(
result,
task,
severity,
old_severity,
config.general.apprise[group],
request,
)
def notify_with_apprise(
result, task, severity: str, old_severity: str, group: List[str], request
) -> None:
logger.debug("Will send apprise notification")
apobj = apprise.Apprise()
for channel in group:
apobj.add(channel)
icon = get_icon_from_severity(severity)
title = f"[Argos] {icon} {urlparse(task.url).netloc}: status {severity}"
msg = f"""\
URL: {task.url}
Check: {task.check}
Status: {severity}
Time: {result.submitted_at}
Previous status: {old_severity}
See result on {request.url_for('get_result_view', result_id=result.id)}
See results of task on {request.url_for('get_task_results_view', task_id=task.id)}#{result.id}
"""
apobj.notify(title=title, body=msg)
def notify_by_mail(
result, task, severity: str, old_severity: str, config: Mail, request
) -> None:
logger.debug("Will send mail notification")
icon = ""
if severity == Severity.OK:
icon = ""
elif severity == Severity.WARNING:
icon = "⚠️"
elif severity == Severity.UNKNOWN:
icon = ""
icon = get_icon_from_severity(severity)
msg = f"""\
URL: {task.url}
Check: {task.check}
@ -100,17 +142,14 @@ def notify_with_gotify(
logger.debug("Will send gotify notification")
headers = {"accept": "application/json", "content-type": "application/json"}
icon = get_icon_from_severity(severity)
priority = 9
icon = ""
if severity == Severity.OK:
priority = 1
icon = ""
elif severity == Severity.WARNING:
priority = 5
icon = "⚠️"
elif severity == Severity.UNKNOWN:
priority = 5
icon = ""
subject = f"{icon} {urlparse(task.url).netloc}: status {severity}"
msg = f"""\

View file

@ -86,6 +86,7 @@ Commands:
nagios Nagios compatible severities report
reload-config Load or reload tasks configuration
start Starts the server (use only for testing or development!)
test-apprise Send a test apprise notification
test-gotify Send a test gotify notification
test-mail Send a test email
user User management
@ -542,3 +543,30 @@ Options:
<!--[[[end]]]
-->
#### Test the Apprise settings
You can verify that your Apprise settings are ok by sending a test notification.
<!--
.. [[[cog
help(["server", "test-apprise", "--help"])
.. ]]] -->
```man
Usage: argos server test-apprise [OPTIONS]
Send a test apprise notification
Options:
--config TEXT Path of the configuration file. If ARGOS_YAML_FILE
environment variable is set, its value will be used
instead.
--domain TEXT Domain for the notification
--severity TEXT Severity
--apprise-group TEXT Apprise group for the notification [required]
--help Show this message and exit.
```
<!--[[[end]]]
-->

View file

@ -22,6 +22,7 @@ classifiers = [
dependencies = [
"alembic>=1.13.0,<1.14",
"apprise>=1.9.0,<2",
"bcrypt>=4.1.3,<5",
"click>=8.1,<9",
"fastapi>=0.103,<0.104",