mirror of
https://github.com/eduardogsilva/routerfleet.git
synced 2025-07-24 21:04:38 +02:00
Perform backup tasks
This commit is contained in:
parent
a12a126d38
commit
aaed53ec5f
8 changed files with 189 additions and 10 deletions
|
@ -1,11 +1,14 @@
|
|||
from django.shortcuts import render
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from django.db.models import Q
|
||||
from django.http import JsonResponse
|
||||
from django.utils import timezone
|
||||
|
||||
from backup.models import BackupProfile
|
||||
from backup_data.models import RouterBackup
|
||||
from router_manager.models import Router, BackupSchedule
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from django.utils import timezone
|
||||
from routerlib.backup_functions import perform_backup
|
||||
|
||||
|
||||
def next_weekday(now, weekday, hour):
|
||||
|
@ -69,7 +72,7 @@ def calculate_next_backup(backup_profile):
|
|||
return next_daily_backup, next_weekly_backup, next_monthly_backup
|
||||
|
||||
|
||||
def generate_backup_schedule(request):
|
||||
def view_generate_backup_schedule(request):
|
||||
data = {
|
||||
'backup_schedule_created': 0,
|
||||
'daily_backup_schedule_created': 0,
|
||||
|
@ -138,3 +141,97 @@ def generate_backup_schedule(request):
|
|||
schedule.save()
|
||||
data['monthly_backup_schedule_removed'] += 1
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
def create_backup_tasks_from_schedule_list(schedule_list, schedule_type):
|
||||
tasks_created = 0
|
||||
for schedule in schedule_list:
|
||||
if schedule_type == 'daily':
|
||||
schedule_time = schedule.next_daily_backup
|
||||
schedule.next_daily_backup = None
|
||||
elif schedule_type == 'weekly':
|
||||
schedule_time = schedule.next_weekly_backup
|
||||
schedule.next_weekly_backup = None
|
||||
elif schedule_type == 'monthly':
|
||||
schedule_time = schedule.next_monthly_backup
|
||||
schedule.next_monthly_backup = None
|
||||
else:
|
||||
return
|
||||
schedule.save()
|
||||
|
||||
backup = RouterBackup.objects.create(
|
||||
router=schedule.router, schedule_time=schedule_time, schedule_type=schedule_type
|
||||
)
|
||||
tasks_created += 1
|
||||
backup.save()
|
||||
backup.router.routerstatus.backup_lock = backup.schedule_time
|
||||
backup.router.routerstatus.save()
|
||||
|
||||
return tasks_created
|
||||
|
||||
|
||||
def view_create_backup_tasks(request):
|
||||
data = {
|
||||
'daily_backup_tasks_created': 0,
|
||||
'weekly_backup_tasks_created': 0,
|
||||
'monthly_backup_tasks_created': 0
|
||||
}
|
||||
# Priorize monthly, then weekly, then daily.
|
||||
monthly_pending_schedule_list = BackupSchedule.objects.filter(
|
||||
next_monthly_backup__lte=timezone.now(), router__enabled=True, router__routerstatus__backup_lock__isnull=True
|
||||
).filter(
|
||||
Q(router__monitoring=False) | Q(router__monitoring=True, router__routerstatus__status_online=True)
|
||||
)
|
||||
data['monthly_backup_tasks_created'] = create_backup_tasks_from_schedule_list(
|
||||
monthly_pending_schedule_list, 'monthly'
|
||||
)
|
||||
|
||||
weekly_pending_schedule_list = BackupSchedule.objects.filter(
|
||||
next_weekly_backup__lte=timezone.now(), router__enabled=True, router__routerstatus__backup_lock__isnull=True
|
||||
).filter(
|
||||
Q(router__monitoring=False) | Q(router__monitoring=True, router__routerstatus__status_online=True)
|
||||
)
|
||||
data['weekly_backup_tasks_created'] = create_backup_tasks_from_schedule_list(
|
||||
weekly_pending_schedule_list, 'weekly'
|
||||
)
|
||||
|
||||
daily_pending_schedule_list = BackupSchedule.objects.filter(
|
||||
next_daily_backup__lte=timezone.now(), router__enabled=True, router__routerstatus__backup_lock__isnull=True
|
||||
).filter(
|
||||
Q(router__monitoring=False) | Q(router__monitoring=True, router__routerstatus__status_online=True)
|
||||
)
|
||||
data['daily_backup_tasks_created'] = create_backup_tasks_from_schedule_list(
|
||||
daily_pending_schedule_list, 'daily'
|
||||
)
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
def view_perform_backup_tasks(request):
|
||||
data = {
|
||||
'backup_tasks_performed': 0
|
||||
}
|
||||
max_execution_time = 45 # seconds
|
||||
execution_start_time = timezone.now()
|
||||
pending_backup_list = RouterBackup.objects.filter(success=False, error=False).filter(
|
||||
Q(schedule_time__lte=timezone.now(), next_retry__isnull=True) | Q(next_retry__lte=timezone.now())
|
||||
).filter(
|
||||
Q(router__monitoring=False) | Q(router__monitoring=True, router__routerstatus__status_online=True)
|
||||
)
|
||||
|
||||
for backup in pending_backup_list:
|
||||
perform_backup(backup)
|
||||
data['backup_tasks_performed'] += 1
|
||||
if backup.router.backup_profile.backup_interval >= 60:
|
||||
break
|
||||
else:
|
||||
if timezone.now() - execution_start_time > timedelta(seconds=max_execution_time):
|
||||
break
|
||||
else:
|
||||
if backup.router.backup_profile.backup_interval > 0:
|
||||
time.sleep(backup.router.backup_profile.backup_interval)
|
||||
if timezone.now() - execution_start_time > timedelta(seconds=max_execution_time):
|
||||
break
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
|
|
18
router_manager/migrations/0011_routerstatus_backup_lock.py
Normal file
18
router_manager/migrations/0011_routerstatus_backup_lock.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-04-03 11:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0010_alter_router_router_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='routerstatus',
|
||||
name='backup_lock',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
18
router_manager/migrations/0012_alter_router_router_type.py
Normal file
18
router_manager/migrations/0012_alter_router_router_type.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-04-03 14:03
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0011_routerstatus_backup_lock'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='router',
|
||||
name='router_type',
|
||||
field=models.CharField(choices=[('monitoring', 'Monitoring Only'), ('routeros', 'Mikrotik (RouterOS)')], max_length=100),
|
||||
),
|
||||
]
|
|
@ -26,7 +26,7 @@ class Router(models.Model):
|
|||
monitoring = models.BooleanField(default=True)
|
||||
backup_profile = models.ForeignKey(BackupProfile, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
router_type = models.CharField(max_length=100, choices=(('monitoring', 'Monitoring Only'), ('routeros', 'Mikrotik (RouterOS)'), ('openwrt', 'OpenWRT')))
|
||||
router_type = models.CharField(max_length=100, choices=(('monitoring', 'Monitoring Only'), ('routeros', 'Mikrotik (RouterOS)')))
|
||||
enabled = models.BooleanField(default=True)
|
||||
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
@ -43,6 +43,7 @@ class RouterStatus(models.Model):
|
|||
last_status_change = models.DateTimeField(blank=True, null=True)
|
||||
last_backup = models.DateTimeField(blank=True, null=True)
|
||||
last_backup_failed = models.DateTimeField(blank=True, null=True)
|
||||
backup_lock = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from django.contrib import messages
|
||||
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_data.models import RouterBackup
|
||||
from .models import Router, RouterGroup, RouterStatus, SSHKey, BackupSchedule
|
||||
from .forms import RouterForm, RouterGroupForm, SSHKeyForm
|
||||
|
||||
|
@ -145,3 +148,25 @@ def view_manage_sshkey(request):
|
|||
'instance': sshkey
|
||||
}
|
||||
return render(request, 'generic_form.html', context=context)
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_create_instant_backup_task(request):
|
||||
router = get_object_or_404(Router, uuid=request.GET.get('uuid'))
|
||||
router_details_url = f'/router/details/?uuid={router.uuid}'
|
||||
if RouterBackup.objects.filter(router=router, success=False, error=False).exists():
|
||||
messages.warning(request, 'Backup task not created|Active router backup task already exists')
|
||||
return redirect(router_details_url)
|
||||
if router.routerstatus.backup_lock is not None:
|
||||
messages.warning(request, 'Backup task not created|Router backup is currently locked')
|
||||
return redirect(router_details_url)
|
||||
if not router.backup_profile:
|
||||
messages.warning(request, 'Backup task not created|Router has no backup profile')
|
||||
return redirect(router_details_url)
|
||||
|
||||
router_backup = RouterBackup.objects.create(router=router, schedule_time=timezone.now(), schedule_type='instant')
|
||||
router.routerstatus.backup_lock = router_backup.schedule_time
|
||||
router.routerstatus.save()
|
||||
messages.success(request, 'Backup task created successfully')
|
||||
return redirect(router_details_url)
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ from django.urls import path
|
|||
from dashboard.views import view_dashboard, view_status
|
||||
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
|
||||
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 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
|
||||
from backup_data.views import generate_backup_schedule
|
||||
from backup_data.views import view_generate_backup_schedule, view_create_backup_tasks, view_perform_backup_tasks
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
@ -26,6 +26,7 @@ urlpatterns = [
|
|||
path('router/ssh_keys/', view_ssh_key_list, name='ssh_keys_list'),
|
||||
path('router/manage_group/', view_manage_router_group, name='manage_router_group'),
|
||||
path('router/manage_sshkey/', view_manage_sshkey, name='manage_sshkey'),
|
||||
path('router/create_instant_backup/', view_create_instant_backup_task, name='create_instant_backup_task'),
|
||||
path('backup/profile_list/', view_backup_profile_list, name='backup_profile_list'),
|
||||
path('backup/manage_profile/', view_manage_backup_profile, name='manage_backup_profile'),
|
||||
path('backup/backup_list/', view_backup_list, name='backup_list'),
|
||||
|
@ -35,5 +36,7 @@ urlpatterns = [
|
|||
path('backup/delete/', view_backup_delete, name='delete_backup'),
|
||||
path('monitoring/export_router_list/', view_export_router_list, name='export_router_list'),
|
||||
path('monitoring/update_router_status/', view_update_router_status, name='update_router_status'),
|
||||
path('cron/generate_backup_schedule/', generate_backup_schedule, name='generate_backup_schedule'),
|
||||
path('cron/generate_backup_schedule/', view_generate_backup_schedule, name='generate_backup_schedule'),
|
||||
path('cron/create_backup_tasks/', view_create_backup_tasks, name='create_backup_tasks'),
|
||||
path('cron/perform_backup_tasks/', view_perform_backup_tasks, name='perform_backup_tasks'),
|
||||
]
|
||||
|
|
|
@ -10,15 +10,21 @@ from routerlib.functions import gen_backup_name
|
|||
|
||||
def perform_backup(router_backup: RouterBackup):
|
||||
if router_backup.success or router_backup.error:
|
||||
router_backup.router.routerstatus.backup_lock = None
|
||||
router_backup.router.routerstatus.save()
|
||||
return
|
||||
if not router_backup.router.backup_profile:
|
||||
router_backup.error = True
|
||||
router_backup.error_message = "No backup profile assigned"
|
||||
router_backup.save()
|
||||
router_backup.router.routerstatus.backup_lock = None
|
||||
router_backup.router.routerstatus.save()
|
||||
return
|
||||
if router_backup.retry_count > router_backup.router.backup_profile.max_retry:
|
||||
router_backup.error = True
|
||||
router_backup.save()
|
||||
router_backup.router.routerstatus.backup_lock = None
|
||||
router_backup.router.routerstatus.save()
|
||||
return
|
||||
|
||||
if router_backup.backup_pending_retrieval:
|
||||
|
@ -39,6 +45,8 @@ def perform_backup(router_backup: RouterBackup):
|
|||
router_backup.error_message = ''
|
||||
router_backup.success = True
|
||||
router_backup.save()
|
||||
router_backup.router.routerstatus.backup_lock = None
|
||||
router_backup.router.routerstatus.save()
|
||||
else:
|
||||
handle_backup_failure(router_backup, error_message)
|
||||
else:
|
||||
|
|
|
@ -85,6 +85,15 @@
|
|||
{% endfor %}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<li class="list-group-item">
|
||||
<b>Instant Backup</b>
|
||||
<span class="float-right">
|
||||
<a href="/router/create_instant_backup/?uuid={{ router.uuid }}">
|
||||
Backup now
|
||||
</a>
|
||||
</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>Notes</b>
|
||||
<span class="float-right">{{ router.internal_notes|default_if_none:""|linebreaksbr }}</span>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue