— 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 - 💄 — Improve email and gotify notifications
- ✨ — Add command to test gotify configuration - ✨ — Add command to test gotify configuration
- ✨ — Add nagios command to use as a Nagios probe - ✨ — Add nagios command to use as a Nagios probe
- ✨ — Add Apprise as notification way (#50)
## 0.3.1 ## 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") @server.command(short_help="Nagios compatible severities report")
@click.option( @click.option(
"--config", "--config",

View file

@ -23,7 +23,10 @@ general:
frequency: "1m" frequency: "1m"
# Which way do you want to be warned when a check goes to that severity? # Which way do you want to be warned when a check goes to that severity?
# "local" emits a message in the server log # "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: alerts:
ok: ok:
- local - local
@ -58,6 +61,17 @@ general:
# tokens: # tokens:
# - foo # - foo
# - bar # - 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: service:
secrets: secrets:

View file

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

View file

@ -4,14 +4,24 @@ import smtplib
from typing import List from typing import List
from urllib.parse import urlparse from urllib.parse import urlparse
import apprise
import httpx import httpx
from argos.checks.base import Severity from argos.checks.base import Severity
from argos.logging import logger from argos.logging import logger
from argos.schemas.config import Config, Mail, GotifyUrl 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): 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 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( def notify_by_mail(
result, task, severity: str, old_severity: str, config: Mail, request result, task, severity: str, old_severity: str, config: Mail, request
) -> None: ) -> None:
logger.debug("Will send mail notification") logger.debug("Will send mail notification")
icon = "" icon = get_icon_from_severity(severity)
if severity == Severity.OK:
icon = ""
elif severity == Severity.WARNING:
icon = "⚠️"
elif severity == Severity.UNKNOWN:
icon = ""
msg = f"""\ msg = f"""\
URL: {task.url} URL: {task.url}
Check: {task.check} Check: {task.check}
@ -100,17 +142,14 @@ def notify_with_gotify(
logger.debug("Will send gotify notification") logger.debug("Will send gotify notification")
headers = {"accept": "application/json", "content-type": "application/json"} headers = {"accept": "application/json", "content-type": "application/json"}
icon = get_icon_from_severity(severity)
priority = 9 priority = 9
icon = ""
if severity == Severity.OK: if severity == Severity.OK:
priority = 1 priority = 1
icon = ""
elif severity == Severity.WARNING: elif severity == Severity.WARNING:
priority = 5 priority = 5
icon = "⚠️"
elif severity == Severity.UNKNOWN: elif severity == Severity.UNKNOWN:
priority = 5 priority = 5
icon = ""
subject = f"{icon} {urlparse(task.url).netloc}: status {severity}" subject = f"{icon} {urlparse(task.url).netloc}: status {severity}"
msg = f"""\ msg = f"""\

View file

@ -86,6 +86,7 @@ Commands:
nagios Nagios compatible severities report nagios Nagios compatible severities report
reload-config Load or reload tasks configuration reload-config Load or reload tasks configuration
start Starts the server (use only for testing or development!) 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-gotify Send a test gotify notification
test-mail Send a test email test-mail Send a test email
user User management user User management
@ -542,3 +543,30 @@ Options:
<!--[[[end]]] <!--[[[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 = [ dependencies = [
"alembic>=1.13.0,<1.14", "alembic>=1.13.0,<1.14",
"apprise>=1.9.0,<2",
"bcrypt>=4.1.3,<5", "bcrypt>=4.1.3,<5",
"click>=8.1,<9", "click>=8.1,<9",
"fastapi>=0.103,<0.104", "fastapi>=0.103,<0.104",