From b15320b0675b4fa5809e57c3b25b7fc8a828cf88 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Thu, 7 Sep 2023 13:35:32 -0500 Subject: [PATCH 1/4] Remove debugging cruft --- netbox_config_backup/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/netbox_config_backup/views.py b/netbox_config_backup/views.py index 5e6a983..0824aaf 100644 --- a/netbox_config_backup/views.py +++ b/netbox_config_backup/views.py @@ -196,8 +196,6 @@ def post(self, request, backup, *args, **kwargs): pk_list = [int(pk) for pk in request.POST.getlist('pk')] backups = pk_list[:2] - print(pk_list) - print(backups) if len(backups) == 2: current = int(backups[0]) From a3f6a1a44fad82b9c27e911f73a9d55c4a44e474 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Thu, 5 Oct 2023 08:55:13 -0500 Subject: [PATCH 2/4] Fix bug with repo committing when user identity is not correct. Update exception catching. Update queryset for view --- netbox_config_backup/git.py | 3 ++ .../management/commands/listbackups.py | 40 +++++++++++++++++++ netbox_config_backup/tables.py | 8 +--- netbox_config_backup/tasks.py | 4 +- netbox_config_backup/views.py | 26 +++++++++++- setup.py | 2 +- 6 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 netbox_config_backup/management/commands/listbackups.py diff --git a/netbox_config_backup/git.py b/netbox_config_backup/git.py index e0f29aa..7383bc4 100644 --- a/netbox_config_backup/git.py +++ b/netbox_config_backup/git.py @@ -80,6 +80,9 @@ def commit(self, message): try: commit = porcelain.commit(self.repository, message, committer=committer, author=author) return commit.decode('ascii') + except repo.InvalidUserIdentity: + committer = 'Your NetBox is misconfigured '.encode('ascii') + author = 'Your NetBox is misconfigured '.encode('ascii') except FileExistsError: sleep(1) failures = failures + 1 diff --git a/netbox_config_backup/management/commands/listbackups.py b/netbox_config_backup/management/commands/listbackups.py new file mode 100644 index 0000000..1a954d2 --- /dev/null +++ b/netbox_config_backup/management/commands/listbackups.py @@ -0,0 +1,40 @@ +import uuid + +from django.core.management.base import BaseCommand +from django.db import transaction +from django.utils import timezone + +from netbox_config_backup.models import BackupJob +from netbox_config_backup.tasks import backup_job +from netbox_config_backup.utils import remove_queued +from netbox_config_backup.utils.rq import can_backup + + +class Command(BaseCommand): + + def handle(self, *args, **options): + from netbox_config_backup.models import Backup + print(f'Backup Name\t\tDevice Name\t\tIP') + for backup in Backup.objects.filter(device__isnull=False): + if backup.ip: + ip = backup.ip + else: + ip = backup.device.primary_ip + + name = f'{backup.name}' + if len(backup.name) > 15: + name = f'{name}\t' + elif len(backup.name) > 7: + name = f'{name}\t\t' + else: + name = f'{name}\t\t\t' + + device_name = f'{backup.device.name}' + if len(backup.device.name) > 15: + device_name = f'{device_name}\t' + elif len(backup.device.name) > 7: + device_name = f'{device_name}\t\t' + else: + device_name = f'{device_name}\t\t\t' + + print(f'{name}{device_name}{ip}') diff --git a/netbox_config_backup/tables.py b/netbox_config_backup/tables.py index bbc511d..0876bc3 100644 --- a/netbox_config_backup/tables.py +++ b/netbox_config_backup/tables.py @@ -41,12 +41,8 @@ class BackupTable(BaseTable): 'args': [Accessor('device_id')], } ) - last_backup = tables.DateTimeColumn( - orderable=False - ) - next_attempt = tables.DateTimeColumn( - orderable=False - ) + last_backup = tables.DateTimeColumn() + next_attempt = tables.DateTimeColumn() class Meta(BaseTable.Meta): model = Backup diff --git a/netbox_config_backup/tasks.py b/netbox_config_backup/tasks.py index de22acf..bb924e0 100644 --- a/netbox_config_backup/tasks.py +++ b/netbox_config_backup/tasks.py @@ -159,10 +159,10 @@ def backup_job(pk): BackupJob.enqueue_if_needed(backup, delay=delay, job_id=job_result.job_id) logger.warning(f'Netmiko read timeout on job: {backup}') except ServiceUnavailable as e: - logger.info(f'Napalm service read failure on job: {backup}') + logger.info(f'Napalm service read failure on job: {backup} ({e})') BackupJob.enqueue_if_needed(backup, delay=delay, job_id=job_result.job_id) except Exception as e: - logger.error(f'Exception at line 148 on job: {backup}') + logger.error(f'Uncaught Exception on job: {backup}') logger.error(e) job_result.set_status(JobResultStatusChoices.STATUS_ERRORED) BackupJob.enqueue_if_needed(backup, delay=delay, job_id=job_result.job_id) diff --git a/netbox_config_backup/views.py b/netbox_config_backup/views.py index 0824aaf..d55e950 100644 --- a/netbox_config_backup/views.py +++ b/netbox_config_backup/views.py @@ -1,5 +1,6 @@ import logging +from django.db import models from django.http import Http404 from django.shortcuts import get_object_or_404, render from django.urls import reverse, NoReverseMatch @@ -20,7 +21,18 @@ class BackupListView(ObjectListView): - queryset = Backup.objects.filter(device__isnull=False) + queryset = Backup.objects.filter(device__isnull=False).prefetch_related('jobs').annotate( + last_backup=models.Subquery( + BackupJob.objects.filter(backup=models.OuterRef('id'), status=JobResultStatusChoices.STATUS_COMPLETED).order_by('completed').values('completed')[:1] + ), + next_attempt=models.Subquery( + BackupJob.objects.filter(backup=models.OuterRef('id'), status__in=['pending', 'running']).order_by('scheduled').values('scheduled')[:1] + ), + last_change=models.Subquery( + BackupCommitTreeChange.objects.filter(backup=models.OuterRef('id')).values('commit__time')[:1] + ) + ) + filterset = BackupFilterSet filterset_form = BackupFilterSetForm table = BackupTable @@ -28,7 +40,17 @@ class BackupListView(ObjectListView): class UnassignedBackupListView(ObjectListView): - queryset = Backup.objects.filter(device__isnull=True) + queryset = Backup.objects.filter(device__isnull=True).annotate( + last_backup=models.Subquery( + BackupJob.objects.filter(backup=models.OuterRef('id'), status=JobResultStatusChoices.STATUS_COMPLETED).order_by('completed').values('completed')[:1] + ), + next_attempt=models.Subquery( + BackupJob.objects.filter(backup=models.OuterRef('id'), status__in=['pending', 'running']).order_by('scheduled').values('scheduled')[:1] + ), + last_change=models.Subquery( + BackupCommitTreeChange.objects.filter(backup=models.OuterRef('id')).values('commit__time')[:1] + ) + ) filterset = BackupFilterSet filterset_form = BackupFilterSetForm table = BackupTable diff --git a/setup.py b/setup.py index 30261df..af86709 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='netbox_config_backup', - version='1.5.0', + version='1.5.1', description='NetBox Configuration Backup', long_description='Plugin to backup device configuration', url='https://github.com/dansheps/netbox-config-backup/', From 3f148e071448ba4606fdb97e3ff93fcd832be98f Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 2 Jan 2024 14:00:17 -0600 Subject: [PATCH 3/4] PRVB --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index af86709..5b1e4fe 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ maintainer='Daniel Sheppard', maintainer_email='dans@dansheps.com', install_requires=[ + 'netmiko>=4.0.0' 'napalm', 'uuid', 'dulwich', @@ -28,4 +29,4 @@ 'Framework :: Django', 'Programming Language :: Python :: 3', ] -) \ No newline at end of file +) From baac77869eb422a41d884f5afd71a31021eef4b2 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 2 Jan 2024 14:00:39 -0600 Subject: [PATCH 4/4] Update for 3.7 --- netbox_config_backup/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_config_backup/__init__.py b/netbox_config_backup/__init__.py index 6d3d6f6..070fa00 100644 --- a/netbox_config_backup/__init__.py +++ b/netbox_config_backup/__init__.py @@ -13,7 +13,7 @@ class NetboxConfigBackup(PluginConfig): author_email = metadata.get('Author-email') base_url = 'configbackup' min_version = '3.5.8' - max_version = '3.6.99' + max_version = '3.7.99' required_settings = [ 'repository', 'committer',