diff --git a/monitoring/admin.py b/monitoring/admin.py index 8c38f3f..8e02527 100644 --- a/monitoring/admin.py +++ b/monitoring/admin.py @@ -1,3 +1,11 @@ from django.contrib import admin +from .models import RouterDownTime -# Register your models here. + +class RouterDownTimeAdmin(admin.ModelAdmin): + list_display = ('router', 'start_time', 'end_time', 'total_down_time', 'updated', 'created', 'uuid') + search_fields = ('router', 'start_time', 'end_time', 'total_down_time', 'updated', 'created', 'uuid') + readonly_fields = ('updated', 'created', 'uuid') + + +admin.site.register(RouterDownTime, RouterDownTimeAdmin) diff --git a/monitoring/models.py b/monitoring/models.py index 6c77973..7b5f97a 100644 --- a/monitoring/models.py +++ b/monitoring/models.py @@ -7,8 +7,13 @@ class RouterDownTime(models.Model): router = models.ForeignKey(Router, on_delete=models.CASCADE) start_time = models.DateTimeField(blank=True, null=True) end_time = models.DateTimeField(blank=True, null=True) - total_down_time = models.IntegerField(default=0) # minutes + total_down_time = models.IntegerField(default=0) # seconds updated = models.DateTimeField(auto_now=True) created = models.DateTimeField(auto_now_add=True) uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4) + + def save(self, *args, **kwargs): + if self.end_time: + self.total_down_time = int((self.end_time - self.start_time).total_seconds()) + super().save(*args, **kwargs) \ No newline at end of file diff --git a/monitoring/views.py b/monitoring/views.py index 4bf4cf0..72cdd40 100644 --- a/monitoring/views.py +++ b/monitoring/views.py @@ -1,4 +1,6 @@ from django.shortcuts import render + +from monitoring.models import RouterDownTime from router_manager.models import Router from django.http import JsonResponse from django.utils import timezone @@ -40,6 +42,10 @@ def view_export_router_list(request): def view_update_router_status(request): router = Router.objects.get(uuid=request.GET.get('uuid')) new_status = request.GET.get('status') + if router.routerstatus.status_online: + current_status = 'online' + else: + current_status = 'offline' if new_status not in ['online', 'offline']: return JsonResponse({'status': 'error', 'error_message': 'Invalid status'}, status=400) if new_status == 'online': @@ -47,6 +53,23 @@ def view_update_router_status(request): else: router.routerstatus.status_online = False router.routerstatus.save() + + if current_status != new_status: + + if new_status == 'online': + router.routerstatus.status_online = True + downtime = RouterDownTime.objects.filter(router=router, end_time=None).first() + if downtime: + downtime.end_time = timezone.now() + downtime.save() + else: + router.routerstatus.status_online = False + downtime = RouterDownTime.objects.create(router=router, start_time=timezone.now()) + router.routerstatus.last_status_change = timezone.now() + router.routerstatus.save() + if downtime: + RouterDownTime.objects.filter(router=router, end_time=None).exclude(uuid=downtime.uuid).delete() + webadmin_settings, _ = WebadminSettings.objects.get_or_create(name='webadmin_settings') webadmin_settings.monitoring_last_run = timezone.now() webadmin_settings.save() diff --git a/router_manager/views.py b/router_manager/views.py index 673703e..f9dd641 100644 --- a/router_manager/views.py +++ b/router_manager/views.py @@ -1,10 +1,12 @@ from django.contrib import messages +from django.db.models import Sum from django.utils import timezone from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from backup.models import BackupProfile from backup_data.models import RouterBackup +from monitoring.models import RouterDownTime from routerfleet_tools.models import WebadminSettings from .models import Router, RouterGroup, RouterStatus, SSHKey, BackupSchedule from .forms import RouterForm, RouterGroupForm, SSHKeyForm @@ -34,11 +36,29 @@ def view_router_list(request): return render(request, 'router_manager/router_list.html', context=context) +@login_required() +def view_router_availability(request): + router = get_object_or_404(Router, uuid=request.GET.get('uuid')) + data = { + 'router': router, + 'downtime_list': router.routerdowntime_set.all().order_by('-start_time'), + } + return render(request, 'router_manager/router_availability.html', context=data) + + @login_required() def view_router_details(request): router = get_object_or_404(Router, uuid=request.GET.get('uuid')) router_status, _ = RouterStatus.objects.get_or_create(router=router) router_backup_list = router.routerbackup_set.all().order_by('-created') + downtime_last_week = router.routerdowntime_set.filter(start_time__gte=timezone.now() - timezone.timedelta(days=7)).aggregate(total=Sum('total_down_time'))['total'] + if downtime_last_week is None: + downtime_last_week = 0 + total_last_week = 7 * 24 * 60 * 60 # total seconds in a week + last_week_availability = round((total_last_week - downtime_last_week) / total_last_week * 100, 3) + if downtime_last_week > 0 and last_week_availability == 100: + last_week_availability = 99.999 + if router_status.backup_lock: if not router_backup_list.filter(success=False, error=False).exists(): router_status.backup_lock = None @@ -50,6 +70,9 @@ def view_router_details(request): 'router_status': router_status, 'router_backup_list': router_backup_list, 'page_title': 'Router Details', + 'offline_time_last_week': downtime_last_week, + 'last_week_availability': last_week_availability, + } diff --git a/routerfleet/settings.py b/routerfleet/settings.py index acb61a1..9248144 100644 --- a/routerfleet/settings.py +++ b/routerfleet/settings.py @@ -140,6 +140,6 @@ STATICFILES_DIRS = [ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' MEDIA_ROOT = '/var/lib/routerfleet/' -ROUTERFLEET_VERSION = 7007 +ROUTERFLEET_VERSION = 7008 from routerfleet.production_settings import * diff --git a/routerfleet/urls.py b/routerfleet/urls.py index e52e399..0b3c3d1 100644 --- a/routerfleet/urls.py +++ b/routerfleet/urls.py @@ -4,7 +4,7 @@ from dashboard.views import view_dashboard, view_status from integration_manager.views import view_wireguard_webadmin_launcher, view_manage_wireguard_integration, view_launch_wireguard_webadmin from user_manager.views import view_manage_user, view_user_list from accounts.views import view_login, view_logout, view_create_first_user -from router_manager.views import view_router_list, view_manage_router, view_router_group_list, view_ssh_key_list, view_manage_router_group, view_manage_sshkey, view_router_details, view_create_instant_backup_task +from router_manager.views import view_router_list, view_manage_router, view_router_group_list, view_ssh_key_list, view_manage_router_group, view_manage_sshkey, view_router_details, view_create_instant_backup_task, view_router_availability from backup.views import view_backup_profile_list, view_manage_backup_profile, view_backup_list, view_backup_details, view_debug_run_backups, view_compare_backups, view_backup_download, view_backup_delete from monitoring.views import view_export_router_list, view_update_router_status, view_router_config_timestamp from backup_data.views import view_generate_backup_schedule, view_create_backup_tasks, view_perform_backup_tasks, view_housekeeping @@ -24,6 +24,7 @@ urlpatterns = [ path('router/list/', view_router_list, name='router_list'), path('router/manage/', view_manage_router, name='manage_router'), path('router/details/', view_router_details, name='router_details'), + path('router/availability/', view_router_availability, name='router_availability'), path('router/group_list/', view_router_group_list, name='router_group_list'), path('router/ssh_keys/', view_ssh_key_list, name='ssh_keys_list'), path('router/manage_group/', view_manage_router_group, name='manage_router_group'), diff --git a/templates/router_manager/router_availability.html b/templates/router_manager/router_availability.html new file mode 100644 index 0000000..5564c02 --- /dev/null +++ b/templates/router_manager/router_availability.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} + +{% block content %} +
Start Time | +End Time | +Duration | +
---|---|---|
{{ downtime.start_time }} | +{{ downtime.end_time }} | +{{ downtime.total_down_time }} | +