Adding notifier to allow sending some kind of event to outside recipients (as emails, telegram, ...)

This commit is contained in:
Adolfo Gómez García 2022-02-08 20:24:34 +01:00
parent c7f96251ac
commit 9e5b06e835
4 changed files with 69 additions and 23 deletions

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -29,6 +29,7 @@
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
""" """
import typing import typing
import enum
from django.utils.translation import gettext_noop as _ from django.utils.translation import gettext_noop as _
@ -37,6 +38,16 @@ from uds.core import Module
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from uds.core.environment import Environment from uds.core.environment import Environment
class NotifierLevel(enum.IntEnum):
"""
Notifier levels
"""
INFO = 0
WARNING = 1
ERROR = 2
CRITICAL = 3
class Notifier(Module): class Notifier(Module):
""" """
this class provides an abstraction of a notifier system for administrator defined events this class provides an abstraction of a notifier system for administrator defined events
@ -67,6 +78,7 @@ class Notifier(Module):
# : your own :py:meth:uds.core.module.BaseModule.icon method. # : your own :py:meth:uds.core.module.BaseModule.icon method.
iconFile: typing.ClassVar[str] = 'notifier.png' iconFile: typing.ClassVar[str] = 'notifier.png'
level: NotifierLevel = NotifierLevel.ERROR
def __init__(self, environment: 'Environment', values: Module.ValuesType): def __init__(self, environment: 'Environment', values: Module.ValuesType):
super().__init__(environment, values) super().__init__(environment, values)
@ -88,6 +100,17 @@ class Notifier(Module):
Default implementation does nothing Default implementation does nothing
""" """
def notify(self, title: str, message: str) -> bool: def notify(self, level: NotifierLevel, message: str, *args, **kwargs) -> None:
return False """
This method will be invoked from UDS to notify an event to this notifier.
This method will be invoked in real time, so ensure this method does not block or
do any long operations. (use threading if you need to do that)
:param level: Level of event
:param message: Message to be shown
:param args: Arguments to be used in message
:param kwargs: Keyword arguments to be used in message
:return: None
"""
pass

View File

@ -1,4 +1,4 @@
# Generated by Django 4.0 on 2022-02-08 19:08 # Generated by Django 4.0 on 2022-02-08 19:25
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -82,7 +82,7 @@ class Migration(migrations.Migration):
('name', models.CharField(default='', max_length=128)), ('name', models.CharField(default='', max_length=128)),
('comments', models.CharField(default='', max_length=256)), ('comments', models.CharField(default='', max_length=256)),
('enabled', models.BooleanField(default=True)), ('enabled', models.BooleanField(default=True)),
('level', models.CharField(choices=[('INFO', 'Info'), ('WARNING', 'Warning'), ('ERROR', 'Error'), ('CRITICAL', 'Critical')], default='ERROR', max_length=16)), ('level', models.PositiveSmallIntegerField(choices=[(1, 'Info'), (2, 'Warning'), (3, 'Error'), (4, 'Critical')], default=1)),
('tags', models.ManyToManyField(to='uds.Tag')), ('tags', models.ManyToManyField(to='uds.Tag')),
], ],
options={ options={

View File

@ -34,36 +34,23 @@ import typing
from django.db import models from django.db import models
from uds.core.alerts import notifier
from uds.core.util.singleton import Singleton
from uds.core.workers import initialize
from .managed_object_model import ManagedObjectModel from .managed_object_model import ManagedObjectModel
from .tag import TaggingMixin from .tag import TaggingMixin
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
if typing.TYPE_CHECKING:
from uds.core.alerts import notifier
class Notifier(ManagedObjectModel, TaggingMixin): class Notifier(ManagedObjectModel, TaggingMixin):
NOTIFIER_LEVEL_INFO = 'INFO'
NOTIFIER_LEVEL_WARNING = 'WARNING'
NOTIFIER_LEVEL_ERROR = 'ERROR'
NOTIFIER_LEVEL_CRITICAL = 'CRITICAL'
NOTIFIER_LEVEL_CHOICES = (
(NOTIFIER_LEVEL_INFO, 'Info'),
(NOTIFIER_LEVEL_WARNING, 'Warning'),
(NOTIFIER_LEVEL_ERROR, 'Error'),
(NOTIFIER_LEVEL_CRITICAL, 'Critical'),
)
name = models.CharField(max_length=128, default='') name = models.CharField(max_length=128, default='')
comments = models.CharField(max_length=256, default='') comments = models.CharField(max_length=256, default='')
enabled = models.BooleanField(default=True) enabled = models.BooleanField(default=True)
level = models.CharField( level = models.PositiveSmallIntegerField(
max_length=16, default=notifier.NotifierLevel.ERROR,
choices=NOTIFIER_LEVEL_CHOICES,
default=NOTIFIER_LEVEL_ERROR
) )
class Meta: class Meta:
@ -78,3 +65,39 @@ class Notifier(ManagedObjectModel, TaggingMixin):
self, values: typing.Optional[typing.Dict[str, str]] = None self, values: typing.Optional[typing.Dict[str, str]] = None
) -> 'notifier.Notifier': ) -> 'notifier.Notifier':
return typing.cast('notifier.Notifier', super().getInstance(values=values)) return typing.cast('notifier.Notifier', super().getInstance(values=values))
class Notifiers(Singleton):
"""
This class is a singleton that contains all notifiers, so we can
easily notify to all of them.
"""
notifiers: typing.Dict[str, 'notifier.Notifier'] = {}
initialized: bool = False
def __init__(self):
super().__init__()
self.notifiers: typing.Dict[str, 'notifier.Notifier'] = {}
def reload(self) -> None:
"""
Loads all notifiers from db.
"""
for n in Notifier.objects.filter(enabled=True):
self.notifiers[n.name] = n.getInstance()
def notify(self, level: 'notifier.NotifierLevel', message: str, *args, **kwargs) -> None:
"""
Notifies all notifiers with level equal or higher than given level.
:param level: Level to notify
:param message: Message to notify
:return: None
"""
# initialize notifiers if needed
if not self.initialized:
self.reload()
self.initialized = True
for n in (n for n in self.notifiers.values() if n.level >= level):
n.notify(level, message, *args, **kwargs)