diff --git a/netbox/dns/filters.py b/netbox/dns/filters.py index dcf38b6b3..173320c0c 100644 --- a/netbox/dns/filters.py +++ b/netbox/dns/filters.py @@ -1,10 +1,12 @@ import django_filters +from django.db.models import Q from ipam.models import IPAddress from .models import ( Zone, Record, ) +from .forms import record_type_choices class ZoneFilter(django_filters.FilterSet): name = django_filters.CharFilter( @@ -23,14 +25,27 @@ class RecordFilter(django_filters.FilterSet): to_field_name='name', lookup_type='icontains', queryset=Zone.objects.all(), - label='Zone (name)', + label='Zone (Name)', ) + record_type = django_filters.MultipleChoiceFilter( + name='record_type', + label='Type', + choices=record_type_choices + ) name = django_filters.CharFilter( name='name', lookup_type='icontains', label='Name', ) + name_or_value = django_filters.MethodFilter( + name='name_or_value', + ) class Meta: model=Record field = ['name','record_type','value'] + + def filter_name_or_value(self, queryset, value): + if not value: + return queryset + return queryset.filter(Q(name__icontains=value) | Q(value__icontains=value)) diff --git a/netbox/dns/forms.py b/netbox/dns/forms.py index 6ac1f3c2a..5ba65ae34 100644 --- a/netbox/dns/forms.py +++ b/netbox/dns/forms.py @@ -116,12 +116,19 @@ def record_zone_choices(): zone_choices = Zone.objects.annotate(record_count=Count('records')) return [(z.name, '{} ({})'.format(z.name, z.record_count)) for z in zone_choices] -#def record_name_choices(): - #name_choices = +def record_type_choices(): + type_choices = {} + records = Record.objects.all() + for r in records: + if not r.record_type in type_choices: + type_choices[r.record_type]=1 + else: + type_choices[r.record_type]+=1 + return [(t, '{} ({})'.format(t, count)) for t,count in type_choices.items()] class RecordFilterForm(forms.Form, BootstrapMixin): zone__name = forms.MultipleChoiceField(required=False, choices=record_zone_choices, label='Zone', widget=forms.SelectMultiple(attrs={'size': 8})) - #name = forms.MultipleChoiceField(required=False, choices=record_name_choices, label='Name', widget=forms.SelectMultiple(attrs={'size': 8})) - record_type = forms.CharField(max_length=100, required=False, label='Type') + record_type = forms.MultipleChoiceField(required=False, choices=record_type_choices, label='Type', + widget=forms.SelectMultiple(attrs={'size': 8})) diff --git a/netbox/dns/models.py b/netbox/dns/models.py index 5e2528ee9..4ca2aff37 100644 --- a/netbox/dns/models.py +++ b/netbox/dns/models.py @@ -7,6 +7,8 @@ from django.db import models from ipam.models import IPAddress from utilities.models import CreatedUpdatedModel +import time + class Zone(CreatedUpdatedModel): """ A Zone represents a DNS zone. It contains SOA data but no records, records are represented as Record objects. @@ -43,6 +45,28 @@ class Zone(CreatedUpdatedModel): str(self.soa_minimum), ]) + def to_bind(self,records): + bind_records = '' + for r in records: + bind_records += r.to_bind()+'\n' + bind_export = '\n'.join([ + '; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) ', + '', + '$TTL '+str(self.ttl), + self.soa_name.ljust(30)+' IN '+'SOA '+self.soa_contact+' (', + ' '+self.soa_serial.ljust(30)+' ; serial', + ' '+str(self.soa_refresh).ljust(30)+' ; refresh', + ' '+str(self.soa_retry).ljust(30)+' ; retry', + ' '+str(self.soa_expire).ljust(30)+' ; expire', + ' '+str(self.soa_minimum).ljust(29)+') ; minimum', + '', + '', + '', + ]) + bind_export += '\n'+bind_records + bind_export += '\n'+'; end ' + return bind_export + class Record(CreatedUpdatedModel): @@ -66,6 +90,7 @@ class Record(CreatedUpdatedModel): return reverse('dns:record', args=[self.pk]) def clean(self): + record_type = record_type.upper() if not self.address and not self.value: raise ValidationError("DNS records must have either an IP address or a text value") @@ -79,5 +104,17 @@ class Record(CreatedUpdatedModel): str(self.value) if self.value else '', ]) - #def to_json(self): - # return JSON + def to_bind(self): + return ''.join([ + (self.name if self.name!='@' else '').ljust(30), + ' IN ', + self.record_type.upper().ljust(10), + ' ', + (str(self.priority) if self.priority else '').ljust(4), + ' ', + (str(self.address).split('/')[0] if self.address else self.value).ljust(25), + ' ', + ' ; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) ' + ]) + + diff --git a/netbox/dns/views.py b/netbox/dns/views.py index da914fb29..c2c55c6c6 100644 --- a/netbox/dns/views.py +++ b/netbox/dns/views.py @@ -3,6 +3,7 @@ from django_tables2 import RequestConfig from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count from django.shortcuts import get_object_or_404, render +from django.http import HttpResponse from ipam.models import IPAddress from utilities.paginator import EnhancedPaginator @@ -30,12 +31,24 @@ def zone(request, pk): zone = get_object_or_404(Zone.objects.all(), pk=pk) records = Record.objects.filter(zone=zone) record_count = len(records) + bind_export = zone.to_bind(records) - return render(request, 'dns/zone.html', { - 'zone': zone, - 'records': records, - 'record_count': record_count, - }) + if request.GET.get('bind_export'): + response = HttpResponse( + bind_export, + content_type='text/plain' + ) + response['Content-Disposition'] = 'attachment; filename="netbox_{}.txt"'\ + .format(zone.name) + return response + + else: + return render(request, 'dns/zone.html', { + 'zone': zone, + 'records': records, + 'record_count': record_count, + 'bind_export': bind_export, + }) class ZoneEditView(PermissionRequiredMixin, ObjectEditView): permission_required = 'dns.change_zone' @@ -94,9 +107,11 @@ class RecordListView(ObjectListView): def record(request, pk): record = get_object_or_404(Record.objects.all(), pk=pk) + bind_export = record.to_bind() return render(request, 'dns/record.html', { 'record': record, + 'bind_export': bind_export, }) class RecordEditView(PermissionRequiredMixin, ObjectEditView): diff --git a/netbox/templates/dns/record.html b/netbox/templates/dns/record.html index 1dbf25d30..95d35e15b 100644 --- a/netbox/templates/dns/record.html +++ b/netbox/templates/dns/record.html @@ -102,4 +102,36 @@ +
+
+
+
+ BIND Export + Select +
+ + + + +
{{ bind_export }}
+
+
+
+{% endblock %} +{% block javascript %} + {% endblock %} diff --git a/netbox/templates/dns/record_list.html b/netbox/templates/dns/record_list.html index d9cac2a2f..d642af2c0 100644 --- a/netbox/templates/dns/record_list.html +++ b/netbox/templates/dns/record_list.html @@ -31,7 +31,7 @@
- +
+ + + BIND Export + {% if perms.dns.change_zone %} @@ -139,4 +143,36 @@
+
+
+
+ + + + + +
{{ bind_export }}
+
+
+
+{% endblock %} +{% block javascript %} + {% endblock %}