From 92bb4e44868db6d9427397c1193e4582d156d50a Mon Sep 17 00:00:00 2001 From: Gagan Deep Date: Wed, 13 Sep 2023 12:26:21 +0530 Subject: [PATCH] [feature] Added dashboard pie charts for radius monitoring --- .github/workflows/ci.yml | 1 + .../integrations/monitoring/apps.py | 83 +++++++++++++++++++ .../integrations/monitoring/utils.py | 23 +++++ 3 files changed, 107 insertions(+) create mode 100644 openwisp_radius/integrations/monitoring/utils.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1c099a4..10ca9502 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,6 +64,7 @@ jobs: run: | pip install -e .[saml,openvpn_status] pip install ${{ matrix.django-version }} + pip install --force-reinstall --upgrade --no-cache-dir --no-deps https://github.com/openwisp/openwisp-utils/tarball/dashboard-chart-filter - name: QA checks run: | diff --git a/openwisp_radius/integrations/monitoring/apps.py b/openwisp_radius/integrations/monitoring/apps.py index 9a2fe125..2f4c49dd 100644 --- a/openwisp_radius/integrations/monitoring/apps.py +++ b/openwisp_radius/integrations/monitoring/apps.py @@ -1,5 +1,9 @@ from django.apps import AppConfig +from django.db import models +from django.db.models import Count, Sum +from django.db.models.functions import Cast, Round from django.db.models.signals import post_save +from django.utils.timezone import localdate from django.utils.translation import gettext_lazy as _ from openwisp_monitoring.monitoring.configuration import ( _register_chart_configuration_choice, @@ -7,6 +11,10 @@ ) from swapper import load_model +from openwisp_utils.admin_theme import register_dashboard_chart + +from .utils import get_datetime_filter_start_date, get_datetime_filter_stop_date + class OpenwispRadiusMonitoringConfig(AppConfig): name = 'openwisp_radius.integrations.monitoring' @@ -15,9 +23,84 @@ class OpenwispRadiusMonitoringConfig(AppConfig): def ready(self): super().ready() + self.register_dashboard_charts() self.register_radius_metrics() self.connect_signal_receivers() + def register_dashboard_charts(self): + register_dashboard_chart( + position=30, + config={ + 'name': _("Today's RADIUS sessions"), + 'query_params': { + 'app_label': 'openwisp_radius', + 'model': 'radiusaccounting', + 'filter': { + 'start_time__date': localdate, + }, + 'aggregate': { + 'open': Count( + 'session_id', filter=models.Q(stop_time__isnull=True) + ), + 'closed': Count( + 'session_id', filter=models.Q(stop_time__isnull=False) + ), + }, + }, + 'colors': { + 'open': '#267126', + 'closed': '#a72d1d', + }, + 'filters': { + 'key': 'stop_time__isnull', + 'open': 'True', + 'closed': 'False', + }, + 'main_filters': { + 'start_time__gte': get_datetime_filter_start_date, + 'start_time__lt': get_datetime_filter_stop_date, + }, + 'labels': { + 'open': 'Open', + 'closed': 'Closed', + }, + }, + ) + register_dashboard_chart( + position=31, + config={ + 'name': _("Today's RADIUS traffic (GB)"), + 'query_params': { + 'app_label': 'openwisp_radius', + 'model': 'radiusaccounting', + 'filter': { + 'start_time__date': localdate, + }, + 'aggregate': { + 'download_traffic': Round( + Cast(Sum('input_octets'), models.FloatField()) / 10**9, 1 + ), + 'upload_traffic': Round( + Cast(Sum('output_octets'), models.FloatField()) / 10**9, 1 + ), + }, + }, + 'colors': { + 'download_traffic': '#1f77b4', + 'upload_traffic': '#ff7f0e', + }, + 'labels': { + 'download_traffic': 'Download traffic (GB)', + 'upload_traffic': 'Upload traffic (GB)', + }, + 'main_filters': { + 'start_time__gte': get_datetime_filter_start_date, + 'start_time__lt': get_datetime_filter_stop_date, + }, + 'filtering': 'False', + }, + ) + def register_radius_metrics(self): from .configuration import RADIUS_METRICS diff --git a/openwisp_radius/integrations/monitoring/utils.py b/openwisp_radius/integrations/monitoring/utils.py new file mode 100644 index 00000000..6a005a28 --- /dev/null +++ b/openwisp_radius/integrations/monitoring/utils.py @@ -0,0 +1,23 @@ +from datetime import datetime, timedelta + +from django.utils import timezone + +local_timezone = timezone.get_current_timezone() + + +def _get_formatted_datetime_string(date_time): + return ( + str(datetime.combine(date_time, datetime.min.time()).astimezone(local_timezone)) + .replace(' ', '+') + .replace(':', '%3A') + ) + + +def get_datetime_filter_start_date(): + start_date = timezone.localdate() + return _get_formatted_datetime_string(start_date) + + +def get_datetime_filter_stop_date(): + stop_date = timezone.localdate() + timedelta(days=1) + return _get_formatted_datetime_string(stop_date)