mirror of
https://github.com/eduardogsilva/routerfleet.git
synced 2025-06-21 01:25:41 +02:00
Backup download and delete.
This commit is contained in:
parent
60e1d557aa
commit
31b1c663f2
10 changed files with 110 additions and 11 deletions
|
@ -1,6 +1,6 @@
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.http import JsonResponse, HttpResponse, FileResponse
|
||||
from django.shortcuts import render, get_object_or_404, redirect, Http404
|
||||
from django.contrib import messages
|
||||
|
||||
from routerlib.backup_functions import perform_backup
|
||||
|
@ -10,6 +10,7 @@ from router_manager.models import Router
|
|||
from backup_data.models import RouterBackup
|
||||
import difflib
|
||||
import unicodedata
|
||||
from routerlib.functions import gen_backup_name, get_router_backup_file_extension
|
||||
|
||||
|
||||
@login_required()
|
||||
|
@ -137,3 +138,36 @@ def view_debug_run_backups(request):
|
|||
perform_backup(backup)
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_backup_download(request):
|
||||
backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid'))
|
||||
if request.GET.get('type') == 'text':
|
||||
response = HttpResponse(backup.backup_text, content_type='text/plain')
|
||||
if backup.backup_text_filename:
|
||||
filename = backup.backup_text_filename
|
||||
else:
|
||||
filename = gen_backup_name(backup)
|
||||
filename += f'.missing_backup_name.{get_router_backup_file_extension(backup.router.router_type)["text"]}'
|
||||
print(filename)
|
||||
response['Content-Disposition'] = f'attachment; filename={filename}'
|
||||
return response
|
||||
elif request.GET.get('type') == 'binary':
|
||||
response = FileResponse(backup.backup_binary, as_attachment=True)
|
||||
return response
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
|
||||
@login_required()
|
||||
def view_backup_delete(request):
|
||||
backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid'))
|
||||
redirect_url = f'/router/details/?uuid={backup.router.uuid}'
|
||||
if request.GET.get('confirmation') == f'delete{backup.id}':
|
||||
backup.delete()
|
||||
messages.success(request, 'Backup deleted successfully')
|
||||
return redirect(redirect_url)
|
||||
else:
|
||||
messages.warning(request, 'Backup not deleted|Invalid confirmation')
|
||||
return redirect(f'/backup/backup_details/?uuid={backup.uuid}')
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-04-01 12:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('backup_data', '0005_alter_routerbackup_backup_text_hash'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='routerbackup',
|
||||
name='backup_text_filename',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
|
@ -2,6 +2,7 @@ from django.db import models
|
|||
from router_manager.models import Router
|
||||
import uuid
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
|
||||
class RouterBackup(models.Model):
|
||||
|
@ -19,6 +20,7 @@ class RouterBackup(models.Model):
|
|||
finish_time = models.DateTimeField(blank=True, null=True)
|
||||
backup_text = models.TextField(blank=True, null=True)
|
||||
backup_text_hash = models.CharField(max_length=64, blank=True, db_index=True)
|
||||
backup_text_filename = models.CharField(max_length=255, blank=True, null=True)
|
||||
backup_binary = models.FileField(upload_to='backups/', blank=True, null=True)
|
||||
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
@ -32,4 +34,3 @@ class RouterBackup(models.Model):
|
|||
self.backup_text_hash = ''
|
||||
super(RouterBackup, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ crispy-bootstrap4==2024.1
|
|||
crispy-bootstrap5==2024.2
|
||||
cryptography==42.0.5
|
||||
Django==5.0.3
|
||||
django-cleanup==8.1.0
|
||||
django-crispy-forms==2.1
|
||||
idna==3.6
|
||||
paramiko==3.4.0
|
||||
|
|
18
router_manager/migrations/0010_alter_router_router_type.py
Normal file
18
router_manager/migrations/0010_alter_router_router_type.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.3 on 2024-04-01 12:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('router_manager', '0009_router_backup_profile'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='router',
|
||||
name='router_type',
|
||||
field=models.CharField(choices=[('monitoring', 'Monitoring Only'), ('routeros', 'Mikrotik (RouterOS)'), ('openwrt', 'OpenWRT')], max_length=100),
|
||||
),
|
||||
]
|
|
@ -37,6 +37,7 @@ INSTALLED_APPS = [
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_cleanup.apps.CleanupConfig',
|
||||
'crispy_forms',
|
||||
'crispy_bootstrap4',
|
||||
'user_manager',
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 backup.views import view_backup_profile_list, view_manage_backup_profile, view_backup_list, view_backup_details, view_debug_run_backups, view_compare_backups
|
||||
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
|
||||
|
||||
|
||||
|
@ -30,6 +30,8 @@ urlpatterns = [
|
|||
path('backup/backup_list/', view_backup_list, name='backup_list'),
|
||||
path('backup/backup_details/', view_backup_details, name='backup_info'),
|
||||
path('backup/compare/', view_compare_backups, name='compare_backups'),
|
||||
path('backup/download/', view_backup_download, name='download_backup'),
|
||||
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'),
|
||||
]
|
||||
|
|
|
@ -5,6 +5,7 @@ import paramiko
|
|||
import os
|
||||
from scp import SCPClient
|
||||
from django.core.files.base import ContentFile
|
||||
from routerlib.functions import gen_backup_name
|
||||
|
||||
|
||||
def perform_backup(router_backup: RouterBackup):
|
||||
|
@ -70,7 +71,7 @@ def execute_backup(router_backup: RouterBackup):
|
|||
router_backup.router.address, username=router_backup.router.username,
|
||||
password=router_backup.router.password, look_for_keys=False, allow_agent=False, timeout=10
|
||||
)
|
||||
backup_name = f"backup-routerfleet-{router_backup.schedule_type}-{router_backup.uuid}"
|
||||
backup_name = gen_backup_name(router_backup)
|
||||
ssh_client.exec_command(f'/system backup save name={backup_name}.backup')
|
||||
ssh_client.exec_command(f'/export file={backup_name}.rsc')
|
||||
return True, [f"{backup_name}.backup", f"{backup_name}.rsc"], error_message
|
||||
|
@ -86,7 +87,7 @@ def execute_backup(router_backup: RouterBackup):
|
|||
|
||||
def retrieve_backup(router_backup: RouterBackup):
|
||||
error_message = ""
|
||||
backup_name = f"backup-routerfleet-{router_backup.schedule_type}-{router_backup.uuid}"
|
||||
backup_name = gen_backup_name(router_backup)
|
||||
|
||||
success = False
|
||||
ssh_client = paramiko.SSHClient()
|
||||
|
@ -110,6 +111,7 @@ def retrieve_backup(router_backup: RouterBackup):
|
|||
rsc_content_cleaned = '\n'.join(
|
||||
line for line in rsc_content.split('\n') if not line.strip().startswith('#'))
|
||||
router_backup.backup_text = rsc_content_cleaned
|
||||
router_backup.backup_text_filename = f"{backup_name}.rsc"
|
||||
|
||||
with open(backup_file_path, 'rb') as backup_file:
|
||||
router_backup.backup_binary.save(f"{backup_name}.backup", ContentFile(backup_file.read()))
|
||||
|
@ -141,7 +143,7 @@ def clean_up_backup_files(router_backup: RouterBackup):
|
|||
router_backup.router.address, username=router_backup.router.username,
|
||||
password=router_backup.router.password, look_for_keys=False, timeout=10, allow_agent=False
|
||||
)
|
||||
ssh_client.exec_command('file remove [find where name~"backup-routerfleet-"]')
|
||||
ssh_client.exec_command('file remove [find where name~"routerfleet-backup-"]')
|
||||
else:
|
||||
print(f"Router type not supported: {router_backup.router.get_router_type_display()}")
|
||||
except Exception as e:
|
||||
|
|
|
@ -16,6 +16,10 @@ def get_router_backup_file_extension(router_type):
|
|||
return {'text': 'txt', 'binary': 'bin'}
|
||||
|
||||
|
||||
def gen_backup_name(router_backup):
|
||||
return f'routerfleet-backup-{router_backup.id}-{router_backup.schedule_type}-{router_backup.router.address}-{router_backup.created.strftime("%Y-%m-%d_%H-%M")}'
|
||||
|
||||
|
||||
def test_authentication(router_type, address, username, password, sshkey=None):
|
||||
router_features = get_router_features(router_type)
|
||||
if 'ssh' in router_features:
|
||||
|
|
|
@ -83,12 +83,19 @@
|
|||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
|
||||
<li class="list-group-item">
|
||||
<b>Delete backup</b>
|
||||
<span class="float-right">
|
||||
|
||||
<a href='javascript:void(0)' class='text-danger' data-command='delete' onclick='openCommandDialog(this)'>
|
||||
<i class="far fa-trash-alt"></i>
|
||||
</a>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -165,5 +172,16 @@
|
|||
|
||||
{% block custom_page_scripts %}
|
||||
|
||||
<script>
|
||||
function openCommandDialog(element) {
|
||||
var command = element.getAttribute('data-command');
|
||||
var confirmation = prompt("Please type 'delete{{ backup.id }}' to proceed.");
|
||||
if (confirmation) {
|
||||
var url = "/backup/delete/?uuid={{ backup.uuid }}&action=delete&confirmation=" + encodeURIComponent(confirmation);
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue