mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-27 10:58:37 -06:00
Fix to pass PEP8 check and tests
This commit is contained in:
parent
50dc519a42
commit
f873848e29
@ -1,17 +1,18 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import (
|
||||
Zone, Record,
|
||||
Zone, Record,
|
||||
)
|
||||
|
||||
|
||||
@admin.register(Zone)
|
||||
class ZoneAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial']
|
||||
prepopulated_fields = {
|
||||
'soa_name': ['name'],
|
||||
}
|
||||
list_display = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial']
|
||||
prepopulated_fields = {
|
||||
'soa_name': ['name'],
|
||||
}
|
||||
|
||||
|
||||
@admin.register(Record)
|
||||
class RecordAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'zone', 'record_type', 'priority', 'address', 'value']
|
||||
list_display = ['name', 'zone', 'record_type', 'priority', 'address', 'value']
|
||||
|
@ -7,32 +7,36 @@ from dns.models import Zone, Record
|
||||
# Zones
|
||||
#
|
||||
|
||||
|
||||
class ZoneSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model=Zone
|
||||
fields = ['id', 'name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description']
|
||||
class Meta:
|
||||
model = Zone
|
||||
fields = ['id', 'name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description']
|
||||
|
||||
|
||||
class ZoneNestedSerializer(ZoneSerializer):
|
||||
|
||||
class Meta(ZoneSerializer.Meta):
|
||||
fields = ['id', 'name']
|
||||
class Meta(ZoneSerializer.Meta):
|
||||
fields = ['id', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Records
|
||||
#
|
||||
|
||||
|
||||
class RecordSerializer(serializers.ModelSerializer):
|
||||
|
||||
zone = ZoneNestedSerializer()
|
||||
address = IPAddressNestedSerializer()
|
||||
zone = ZoneNestedSerializer()
|
||||
address = IPAddressNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Record
|
||||
fields = ['id', 'name', 'record_type', 'priority', 'zone', 'address', 'value', 'description']
|
||||
|
||||
class Meta:
|
||||
model=Record
|
||||
fields = ['id', 'name', 'record_type', 'priority', 'zone', 'address', 'value', 'description']
|
||||
|
||||
class RecordNestedSerializer(RecordSerializer):
|
||||
|
||||
class Meta(RecordSerializer.Meta):
|
||||
fields = ['id', 'name', 'record_type', 'zone']
|
||||
class Meta(RecordSerializer.Meta):
|
||||
fields = ['id', 'name', 'record_type', 'zone']
|
||||
|
@ -4,16 +4,16 @@ from .views import *
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
# Zones
|
||||
url(r'^zones/$', ZoneListView.as_view(), name='zone_list'),
|
||||
url(r'^zones/(?P<pk>\d+)/$', ZoneDetailView.as_view(), name='zone_detail'),
|
||||
# Zones
|
||||
url(r'^zones/$', ZoneListView.as_view(), name='zone_list'),
|
||||
url(r'^zones/(?P<pk>\d+)/$', ZoneDetailView.as_view(), name='zone_detail'),
|
||||
|
||||
# Records
|
||||
url(r'^records/$', RecordListView.as_view(), name='record_list'),
|
||||
url(r'^records/(?P<pk>\d+)/$', RecordDetailView.as_view(), name='record_detail'),
|
||||
# Records
|
||||
url(r'^records/$', RecordListView.as_view(), name='record_list'),
|
||||
url(r'^records/(?P<pk>\d+)/$', RecordDetailView.as_view(), name='record_detail'),
|
||||
|
||||
# BIND Exports
|
||||
url(r'^bind/forward/$', bind_forward, name='bind_forward'),
|
||||
url(r'^bind/reverse/$', bind_reverse, name='bind_reverse'),
|
||||
# BIND Exports
|
||||
url(r'^bind/forward/$', bind_forward, name='bind_forward'),
|
||||
url(r'^bind/reverse/$', bind_reverse, name='bind_reverse'),
|
||||
|
||||
]
|
||||
|
@ -14,56 +14,63 @@ from . import serializers
|
||||
# Zones
|
||||
#
|
||||
|
||||
|
||||
class ZoneListView(generics.ListAPIView):
|
||||
"""
|
||||
List all zones
|
||||
"""
|
||||
queryset = Zone.objects.all()
|
||||
serializer_class = serializers.ZoneSerializer
|
||||
filter_class = filters.ZoneFilter
|
||||
"""
|
||||
List all zones
|
||||
"""
|
||||
queryset = Zone.objects.all()
|
||||
serializer_class = serializers.ZoneSerializer
|
||||
filter_class = filters.ZoneFilter
|
||||
|
||||
|
||||
class ZoneDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single zone
|
||||
"""
|
||||
queryset = Zone.objects.all()
|
||||
serializer_class = serializers.ZoneSerializer
|
||||
"""
|
||||
Retrieve a single zone
|
||||
"""
|
||||
queryset = Zone.objects.all()
|
||||
serializer_class = serializers.ZoneSerializer
|
||||
|
||||
|
||||
#
|
||||
# Records
|
||||
#
|
||||
|
||||
|
||||
class RecordListView(generics.ListAPIView):
|
||||
"""
|
||||
List all records
|
||||
"""
|
||||
queryset = Record.objects.all()
|
||||
serializer_class = serializers.RecordSerializer
|
||||
"""
|
||||
List all records
|
||||
"""
|
||||
queryset = Record.objects.all()
|
||||
serializer_class = serializers.RecordSerializer
|
||||
|
||||
|
||||
class RecordDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single record
|
||||
"""
|
||||
queryset = Record.objects.all()
|
||||
serializer_class = serializers.RecordSerializer
|
||||
"""
|
||||
Retrieve a single record
|
||||
"""
|
||||
queryset = Record.objects.all()
|
||||
serializer_class = serializers.RecordSerializer
|
||||
|
||||
|
||||
#
|
||||
# BIND Exports
|
||||
#
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
def bind_forward(request):
|
||||
"""
|
||||
Full export of forward zones in BIND format
|
||||
"""
|
||||
zones_list = export_bind_forward()
|
||||
return Response(zones_list)
|
||||
"""
|
||||
Full export of forward zones in BIND format
|
||||
"""
|
||||
zones_list = export_bind_forward()
|
||||
return Response(zones_list)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
def bind_reverse(request):
|
||||
"""
|
||||
Full export of reverse zones in BIND format
|
||||
"""
|
||||
zones_list = export_bind_reverse()
|
||||
return Response(zones_list)
|
||||
|
||||
"""
|
||||
Full export of reverse zones in BIND format
|
||||
"""
|
||||
zones_list = export_bind_reverse()
|
||||
return Response(zones_list)
|
||||
|
@ -3,4 +3,4 @@ from django.apps import AppConfig
|
||||
|
||||
class DNSConfig(AppConfig):
|
||||
name = 'dns'
|
||||
verbose_name='DNS'
|
||||
verbose_name = 'DNS'
|
||||
|
@ -3,49 +3,51 @@ from django.db.models import Q
|
||||
|
||||
from ipam.models import IPAddress
|
||||
from .models import (
|
||||
Zone,
|
||||
Record,
|
||||
Zone,
|
||||
Record,
|
||||
)
|
||||
from .forms import record_type_choices
|
||||
|
||||
class ZoneFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(
|
||||
name = 'name',
|
||||
lookup_type = 'icontains',
|
||||
label = 'Name',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Zone
|
||||
fields = ['name']
|
||||
class ZoneFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(
|
||||
name='name',
|
||||
lookup_type='icontains',
|
||||
label='Name',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Zone
|
||||
fields = ['name']
|
||||
|
||||
|
||||
class RecordFilter(django_filters.FilterSet):
|
||||
zone__name = django_filters.ModelMultipleChoiceFilter(
|
||||
name = 'zone__name',
|
||||
to_field_name = 'name',
|
||||
lookup_type = 'icontains',
|
||||
queryset = Zone.objects.all(),
|
||||
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_or_ip = django_filters.MethodFilter(
|
||||
name = 'name_or_value_or_ip',
|
||||
)
|
||||
zone__name = django_filters.ModelMultipleChoiceFilter(
|
||||
name='zone__name',
|
||||
to_field_name='name',
|
||||
lookup_type='icontains',
|
||||
queryset=Zone.objects.all(),
|
||||
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_or_ip = django_filters.MethodFilter(
|
||||
name='name_or_value_or_ip',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model=Record
|
||||
field = ['name', 'record_type', 'value']
|
||||
class Meta:
|
||||
model = Record
|
||||
field = ['name', 'record_type', 'value']
|
||||
|
||||
def filter_name_or_value_or_ip(self, queryset, value):
|
||||
if not value:
|
||||
return queryset
|
||||
return queryset.filter(Q(name__icontains=value) | Q(value__icontains=value) | Q(address__address__icontains=value))
|
||||
def filter_name_or_value_or_ip(self, queryset, value):
|
||||
if not value:
|
||||
return queryset
|
||||
return queryset.filter(Q(name__icontains=value) | Q(value__icontains=value) | Q(address__address__icontains=value))
|
||||
|
@ -12,30 +12,28 @@ from ipam.models import IPAddress, Prefix
|
||||
#
|
||||
|
||||
class AddressFormField(forms.Field):
|
||||
default_error_messages = {
|
||||
'invalid': "Enter a valid IPv4 or IPv6 address (with CIDR mask).",
|
||||
}
|
||||
default_error_messages = {
|
||||
'invalid': "Enter a valid IPv4 or IPv6 address (with CIDR mask).",
|
||||
}
|
||||
|
||||
def to_python(self, value):
|
||||
if not value:
|
||||
return None
|
||||
def to_python(self, value):
|
||||
if not value:
|
||||
return None
|
||||
|
||||
# Ensure that a subnet mask has been specified. This prevents IPs from defaulting to a /32 or /128.
|
||||
if len(value.split('/')) != 2:
|
||||
raise ValidationError('CIDR mask (e.g. /24) is required.')
|
||||
|
||||
try:
|
||||
net = IPNetwork(value)
|
||||
except AddrFormatError:
|
||||
raise ValidationError("Please specify a valid IPv4 or IPv6 address.")
|
||||
|
||||
ip = IPAddress.objects.filter(address=value)
|
||||
if not ip:
|
||||
net = IPNetwork(value)
|
||||
obj = IPAddress(address=net)
|
||||
obj.save()
|
||||
return obj
|
||||
else:
|
||||
return ip[0]
|
||||
# Ensure that a subnet mask has been specified. This prevents IPs from defaulting to a /32 or /128.
|
||||
if len(value.split('/')) != 2:
|
||||
raise ValidationError('CIDR mask (e.g. /24) is required.')
|
||||
|
||||
try:
|
||||
net = IPNetwork(value)
|
||||
except AddrFormatError:
|
||||
raise ValidationError("Please specify a valid IPv4 or IPv6 address.")
|
||||
|
||||
ip = IPAddress.objects.filter(address=value)
|
||||
if not ip:
|
||||
net = IPNetwork(value)
|
||||
obj = IPAddress(address=net)
|
||||
obj.save()
|
||||
return obj
|
||||
else:
|
||||
return ip[0]
|
||||
|
@ -3,12 +3,12 @@ from django.db.models import Count
|
||||
|
||||
from ipam.models import IPAddress
|
||||
from utilities.forms import (
|
||||
BootstrapMixin, ConfirmationForm, APISelect, Livesearch, CSVDataField, BulkImportForm,
|
||||
BootstrapMixin, ConfirmationForm, APISelect, Livesearch, CSVDataField, BulkImportForm,
|
||||
)
|
||||
|
||||
from .models import (
|
||||
Zone,
|
||||
Record,
|
||||
Zone,
|
||||
Record,
|
||||
)
|
||||
|
||||
from .formfields import AddressFormField
|
||||
@ -17,131 +17,134 @@ from .formfields import AddressFormField
|
||||
# Zones
|
||||
#
|
||||
|
||||
|
||||
class ZoneForm(forms.ModelForm, BootstrapMixin):
|
||||
|
||||
class Meta:
|
||||
model=Zone
|
||||
fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description']
|
||||
labels = {
|
||||
'soa_name': 'SOA Name',
|
||||
'soa_contact': 'SOA Contact',
|
||||
'soa_refresh': 'SOA Refresh',
|
||||
'soa_retry': 'SOA Retry',
|
||||
'soa_expire': 'SOA Expire',
|
||||
'soa_minimum': 'SOA Minimum',
|
||||
'description': 'Description',
|
||||
}
|
||||
help_texts = {
|
||||
'ttl': "Time to live, in seconds",
|
||||
'soa_name': "The primary name server for the domain, @ for origin",
|
||||
'soa_contact': "The responsible party for the domain (e.g. ns.foo.net. noc.foo.net.)",
|
||||
'soa_refresh': "Refresh time, in seconds",
|
||||
'soa_retry': "Retry time, in seconds",
|
||||
'soa_expire': "Expire time, in seconds",
|
||||
'soa_minimum': "Negative result TTL, in seconds",
|
||||
}
|
||||
class Meta:
|
||||
model = Zone
|
||||
fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description']
|
||||
labels = {
|
||||
'soa_name': 'SOA Name',
|
||||
'soa_contact': 'SOA Contact',
|
||||
'soa_refresh': 'SOA Refresh',
|
||||
'soa_retry': 'SOA Retry',
|
||||
'soa_expire': 'SOA Expire',
|
||||
'soa_minimum': 'SOA Minimum',
|
||||
'description': 'Description',
|
||||
}
|
||||
help_texts = {
|
||||
'ttl': "Time to live, in seconds",
|
||||
'soa_name': "The primary name server for the domain, @ for origin",
|
||||
'soa_contact': "The responsible party for the domain (e.g. ns.foo.net. noc.foo.net.)",
|
||||
'soa_refresh': "Refresh time, in seconds",
|
||||
'soa_retry': "Retry time, in seconds",
|
||||
'soa_expire': "Expire time, in seconds",
|
||||
'soa_minimum': "Negative result TTL, in seconds",
|
||||
}
|
||||
|
||||
|
||||
class ZoneFromCSVForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model=Zone
|
||||
fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description']
|
||||
class Meta:
|
||||
model = Zone
|
||||
fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description']
|
||||
|
||||
|
||||
class ZoneImportForm(BulkImportForm, BootstrapMixin):
|
||||
csv = CSVDataField(csv_form=ZoneFromCSVForm)
|
||||
csv = CSVDataField(csv_form=ZoneFromCSVForm)
|
||||
|
||||
|
||||
class ZoneBulkEditForm(forms.Form, BootstrapMixin):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Zone.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
name = forms.CharField(max_length=100, required=False, label='Name')
|
||||
ttl = forms.IntegerField(required=False, label='TTL')
|
||||
soa_name = forms.CharField(max_length=100, required=False, label='SOA Name')
|
||||
soa_contact = forms.CharField(max_length=100, required=False, label='SOA Contact')
|
||||
soa_refresh = forms.IntegerField(required=False, label='SOA Refresh')
|
||||
soa_retry = forms.IntegerField(required=False, label='SOA Retry')
|
||||
soa_expire = forms.IntegerField(required=False, label='SOA Expire')
|
||||
soa_minimum = forms.IntegerField(required=False, label='SOA Minimum')
|
||||
description = forms.CharField(max_length=100, required=False, label='Description')
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Zone.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
name = forms.CharField(max_length=100, required=False, label='Name')
|
||||
ttl = forms.IntegerField(required=False, label='TTL')
|
||||
soa_name = forms.CharField(max_length=100, required=False, label='SOA Name')
|
||||
soa_contact = forms.CharField(max_length=100, required=False, label='SOA Contact')
|
||||
soa_refresh = forms.IntegerField(required=False, label='SOA Refresh')
|
||||
soa_retry = forms.IntegerField(required=False, label='SOA Retry')
|
||||
soa_expire = forms.IntegerField(required=False, label='SOA Expire')
|
||||
soa_minimum = forms.IntegerField(required=False, label='SOA Minimum')
|
||||
description = forms.CharField(max_length=100, required=False, label='Description')
|
||||
|
||||
|
||||
class ZoneBulkDeleteForm(ConfirmationForm):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Zone.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Zone.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
|
||||
|
||||
class ZoneFilterForm(forms.Form, BootstrapMixin):
|
||||
pass
|
||||
pass
|
||||
|
||||
#
|
||||
# Records
|
||||
#
|
||||
|
||||
|
||||
class RecordForm(forms.ModelForm, BootstrapMixin):
|
||||
|
||||
address = AddressFormField(required=False)
|
||||
address = AddressFormField(required=False)
|
||||
|
||||
class Meta:
|
||||
model=Record
|
||||
fields = ['name', 'record_type', 'priority', 'zone', 'address', 'value', 'description']
|
||||
labels = {
|
||||
'record_type': 'Type',
|
||||
}
|
||||
help_texts = {
|
||||
'name': 'Host name, @ for origin (e.g. www)',
|
||||
'record_type': 'Record type (e.g. MX or AAAA)',
|
||||
'priority': 'Priority level (e.g. 10)',
|
||||
'zone': 'Zone the record belongs to',
|
||||
'address': 'IP address if value is an IP address, in AAAA records for instance',
|
||||
'value': 'Text value else, in CNAME records for instance'
|
||||
}
|
||||
class Meta:
|
||||
model = Record
|
||||
fields = ['name', 'record_type', 'priority', 'zone', 'address', 'value', 'description']
|
||||
labels = {
|
||||
'record_type': 'Type',
|
||||
}
|
||||
help_texts = {
|
||||
'name': 'Host name, @ for origin (e.g. www)',
|
||||
'record_type': 'Record type (e.g. MX or AAAA)',
|
||||
'priority': 'Priority level (e.g. 10)',
|
||||
'zone': 'Zone the record belongs to',
|
||||
'address': 'IP address if value is an IP address, in AAAA records for instance',
|
||||
'value': 'Text value else, in CNAME records for instance'
|
||||
}
|
||||
|
||||
|
||||
class RecordFromCSVForm(forms.ModelForm):
|
||||
|
||||
zone = forms.ModelChoiceField(queryset=Zone.objects.all(), to_field_name='name', error_messages={'invalid_choice': 'Zone not found.'})
|
||||
address = AddressFormField(required=False)
|
||||
zone = forms.ModelChoiceField(queryset=Zone.objects.all(), to_field_name='name', error_messages={'invalid_choice': 'Zone not found.'})
|
||||
address = AddressFormField(required=False)
|
||||
|
||||
class Meta:
|
||||
model=Record
|
||||
fields = ['zone', 'name', 'record_type', 'priority', 'address', 'value', 'description']
|
||||
class Meta:
|
||||
model = Record
|
||||
fields = ['zone', 'name', 'record_type', 'priority', 'address', 'value', 'description']
|
||||
|
||||
# class RecordBINDImportForm(forms.Form, BootstrapMixin):
|
||||
# bind = BINDDataField()
|
||||
# zone_name = CharField(max_length=100, label='Zone')
|
||||
# slash_v4 = IntegerField()
|
||||
|
||||
# def clean(self):
|
||||
# self.cleaned_data
|
||||
|
||||
class RecordImportForm(BulkImportForm, BootstrapMixin):
|
||||
csv = CSVDataField(csv_form=RecordFromCSVForm)
|
||||
csv = CSVDataField(csv_form=RecordFromCSVForm)
|
||||
|
||||
|
||||
class RecordBulkEditForm(forms.Form, BootstrapMixin):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Record.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
name = forms.CharField(max_length=100, required=False, label='Name')
|
||||
record_type = forms.CharField(max_length=100, required=False, label='Type')
|
||||
priority = forms.IntegerField(required=False)
|
||||
zone = forms.ModelChoiceField(queryset=Zone.objects.all(), required=False)
|
||||
address = AddressFormField(required=False)
|
||||
value = forms.CharField(max_length=100, required=False)
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Record.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
name = forms.CharField(max_length=100, required=False, label='Name')
|
||||
record_type = forms.CharField(max_length=100, required=False, label='Type')
|
||||
priority = forms.IntegerField(required=False)
|
||||
zone = forms.ModelChoiceField(queryset=Zone.objects.all(), required=False)
|
||||
address = AddressFormField(required=False)
|
||||
value = forms.CharField(max_length=100, required=False)
|
||||
|
||||
|
||||
class RecordBulkDeleteForm(ConfirmationForm):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Record.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Record.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
|
||||
|
||||
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]
|
||||
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_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()]
|
||||
type_choices = {}
|
||||
records = Record.objects.all()
|
||||
for r in records:
|
||||
if r.record_type not 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}))
|
||||
record_type = forms.MultipleChoiceField(required=False, choices=record_type_choices, label='Type',
|
||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||
|
||||
zone__name = forms.MultipleChoiceField(required=False, choices=record_zone_choices, label='Zone',
|
||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||
record_type = forms.MultipleChoiceField(required=False, choices=record_type_choices, label='Type',
|
||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||
|
@ -4,7 +4,6 @@ from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
|
||||
#from ipam.models import IPAddress
|
||||
from utilities.models import CreatedUpdatedModel
|
||||
|
||||
import time
|
||||
@ -14,201 +13,202 @@ from django.dispatch import receiver
|
||||
|
||||
import ipam.models
|
||||
|
||||
|
||||
class Zone(CreatedUpdatedModel):
|
||||
"""
|
||||
A Zone represents a DNS zone. It contains SOA data but no records, records are represented as Record objects.
|
||||
"""
|
||||
name = models.CharField(max_length=100)
|
||||
ttl = models.PositiveIntegerField()
|
||||
soa_name = models.CharField(max_length=100)
|
||||
soa_contact = models.CharField(max_length=100)
|
||||
"""
|
||||
A Zone represents a DNS zone. It contains SOA data but no records, records are represented as Record objects.
|
||||
"""
|
||||
name = models.CharField(max_length=100)
|
||||
ttl = models.PositiveIntegerField()
|
||||
soa_name = models.CharField(max_length=100)
|
||||
soa_contact = models.CharField(max_length=100)
|
||||
|
||||
soa_serial = models.CharField(max_length=10)
|
||||
bind_changed = models.BooleanField(default=True)
|
||||
soa_serial = models.CharField(max_length=10)
|
||||
bind_changed = models.BooleanField(default=True)
|
||||
|
||||
soa_refresh = models.PositiveIntegerField()
|
||||
soa_retry = models.PositiveIntegerField()
|
||||
soa_expire = models.PositiveIntegerField()
|
||||
soa_minimum = models.PositiveIntegerField()
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
soa_refresh = models.PositiveIntegerField()
|
||||
soa_retry = models.PositiveIntegerField()
|
||||
soa_expire = models.PositiveIntegerField()
|
||||
soa_minimum = models.PositiveIntegerField()
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dns:zone', args=[self.pk])
|
||||
def get_absolute_url(self):
|
||||
return reverse('dns:zone', args=[self.pk])
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.bind_changed = True
|
||||
super(Zone, self).save(*args, **kwargs)
|
||||
def save(self, *args, **kwargs):
|
||||
self.bind_changed = True
|
||||
super(Zone, self).save(*args, **kwargs)
|
||||
|
||||
def set_bind_changed(self, value):
|
||||
self.bind_changed = value
|
||||
super(Zone, self).save()
|
||||
def set_bind_changed(self, value):
|
||||
self.bind_changed = value
|
||||
super(Zone, self).save()
|
||||
|
||||
def update_serial(self):
|
||||
"""
|
||||
Each time a record or the zone is modified, the serial is incremented.
|
||||
"""
|
||||
current_date = time.strftime('%Y%m%d',time.localtime())
|
||||
if not self.soa_serial:
|
||||
self.soa_serial = current_date+'01'
|
||||
else:
|
||||
serial_date = self.soa_serial[:8]
|
||||
serial_num = self.soa_serial[8:]
|
||||
|
||||
if serial_date!=current_date:
|
||||
self.soa_serial = current_date+'01'
|
||||
else:
|
||||
serial_num = int(serial_num)
|
||||
serial_num += 1
|
||||
if serial_num<10:
|
||||
self.soa_serial = current_date + '0' + str(serial_num)
|
||||
else:
|
||||
self.soa_serial = current_date + str(serial_num)
|
||||
self.set_bind_changed(False)
|
||||
def update_serial(self):
|
||||
"""
|
||||
Each time a record or the zone is modified, the serial is incremented.
|
||||
"""
|
||||
current_date = time.strftime('%Y%m%d', time.localtime())
|
||||
if not self.soa_serial:
|
||||
self.soa_serial = current_date + '01'
|
||||
else:
|
||||
serial_date = self.soa_serial[:8]
|
||||
serial_num = self.soa_serial[8:]
|
||||
|
||||
if serial_date != current_date:
|
||||
self.soa_serial = current_date + '01'
|
||||
else:
|
||||
serial_num = int(serial_num)
|
||||
serial_num += 1
|
||||
if serial_num < 10:
|
||||
self.soa_serial = current_date + '0' + str(serial_num)
|
||||
else:
|
||||
self.soa_serial = current_date + str(serial_num)
|
||||
self.set_bind_changed(False)
|
||||
|
||||
def to_csv(self):
|
||||
return ','.join([
|
||||
self.name,
|
||||
str(self.ttl),
|
||||
self.soa_name,
|
||||
self.soa_contact,
|
||||
self.soa_serial,
|
||||
str(self.soa_refresh),
|
||||
str(self.soa_retry),
|
||||
str(self.soa_expire),
|
||||
str(self.soa_minimum),
|
||||
self.description,
|
||||
])
|
||||
|
||||
def to_bind(self,records):
|
||||
if self.bind_changed:
|
||||
self.update_serial()
|
||||
bind_records = ''
|
||||
for r in records:
|
||||
bind_records += r.to_bind()+'\n'
|
||||
bind_export = '\n'.join([
|
||||
'; '+self.name+((' ('+self.description+')') if self.description else ''),
|
||||
'; 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
|
||||
def to_csv(self):
|
||||
return ','.join([
|
||||
self.name,
|
||||
str(self.ttl),
|
||||
self.soa_name,
|
||||
self.soa_contact,
|
||||
self.soa_serial,
|
||||
str(self.soa_refresh),
|
||||
str(self.soa_retry),
|
||||
str(self.soa_expire),
|
||||
str(self.soa_minimum),
|
||||
self.description,
|
||||
])
|
||||
|
||||
def to_bind(self, records):
|
||||
if self.bind_changed:
|
||||
self.update_serial()
|
||||
bind_records = ''
|
||||
for r in records:
|
||||
bind_records += r.to_bind() + '\n'
|
||||
bind_export = '\n'.join([
|
||||
'; ' + self.name + ((' (' + self.description + ')') if self.description else ''),
|
||||
'; 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):
|
||||
"""
|
||||
A Record represents a DNS record, i.e. a row in a DNS zone.
|
||||
"""
|
||||
name = models.CharField(max_length=100)
|
||||
record_type = models.CharField(max_length=10)
|
||||
priority = models.PositiveIntegerField(blank=True, null=True)
|
||||
zone = models.ForeignKey('Zone', related_name='records', on_delete=models.CASCADE)
|
||||
address = models.ForeignKey('ipam.IPAddress', related_name='records', on_delete=models.PROTECT, blank=True, null=True)
|
||||
value = models.CharField(max_length=100, blank=True)
|
||||
description = models.CharField(max_length=20, blank=True)
|
||||
"""
|
||||
A Record represents a DNS record, i.e. a row in a DNS zone.
|
||||
"""
|
||||
name = models.CharField(max_length=100)
|
||||
record_type = models.CharField(max_length=10)
|
||||
priority = models.PositiveIntegerField(blank=True, null=True)
|
||||
zone = models.ForeignKey('Zone', related_name='records', on_delete=models.CASCADE)
|
||||
address = models.ForeignKey('ipam.IPAddress', related_name='records', on_delete=models.PROTECT, blank=True, null=True)
|
||||
value = models.CharField(max_length=100, blank=True)
|
||||
description = models.CharField(max_length=20, blank=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dns:record', args=[self.pk])
|
||||
def get_absolute_url(self):
|
||||
return reverse('dns:record', args=[self.pk])
|
||||
|
||||
def clean(self):
|
||||
self.record_type = self.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")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.zone.save() # in order to update serial.
|
||||
super(Record, self).save(*args, **kwargs)
|
||||
def clean(self):
|
||||
self.record_type = self.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")
|
||||
|
||||
def to_csv(self):
|
||||
return ','.join([
|
||||
self.zone.name,
|
||||
self.name,
|
||||
self.record_type,
|
||||
str(self.priority) if self.priority else '',
|
||||
str(self.address) if self.address else '',
|
||||
self.value,
|
||||
self.description,
|
||||
])
|
||||
def save(self, *args, **kwargs):
|
||||
self.zone.save() # in order to update serial.
|
||||
super(Record, self).save(*args, **kwargs)
|
||||
|
||||
def to_csv(self):
|
||||
return ','.join([
|
||||
self.zone.name,
|
||||
self.name,
|
||||
self.record_type,
|
||||
str(self.priority) if self.priority else '',
|
||||
str(self.address) if self.address else '',
|
||||
self.value,
|
||||
self.description,
|
||||
])
|
||||
|
||||
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),
|
||||
' ',
|
||||
' ; ' + self.description + ' ; gen by netbox ( ' + time.strftime('%A %B %d %Y %H:%M:%S', time.localtime()) + ' ) '
|
||||
])
|
||||
|
||||
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),
|
||||
' ',
|
||||
' ; '+self.description+' ; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) '
|
||||
])
|
||||
|
||||
@receiver(pre_delete, sender=Record)
|
||||
def on_record_delete(sender, **kwargs):
|
||||
kwargs['instance'].zone.save()
|
||||
kwargs['instance'].zone.save()
|
||||
|
||||
|
||||
#
|
||||
# BIND Exports
|
||||
#
|
||||
|
||||
|
||||
def export_bind_forward():
|
||||
zones = Zone.objects.all()
|
||||
zones = Zone.objects.all()
|
||||
|
||||
zones_list = []
|
||||
for z in zones:
|
||||
records = Record.objects.filter(zone=z)
|
||||
zones_list.append({
|
||||
'num': len(zones_list),
|
||||
'id': z.name,
|
||||
'content': z.to_bind(records)
|
||||
})
|
||||
zones_list = []
|
||||
for z in zones:
|
||||
records = Record.objects.filter(zone=z)
|
||||
zones_list.append({
|
||||
'num': len(zones_list),
|
||||
'id': z.name,
|
||||
'content': z.to_bind(records)
|
||||
})
|
||||
|
||||
return zones_list
|
||||
|
||||
return zones_list
|
||||
|
||||
def export_bind_reverse():
|
||||
zones = {}
|
||||
zones = {}
|
||||
|
||||
prefixes = ipam.models.Prefix.objects.all()
|
||||
prefixes = ipam.models.Prefix.objects.all()
|
||||
|
||||
for p in prefixes:
|
||||
child_ip = ipam.models.IPAddress.objects.filter(address__net_contained_or_equal=str(p.prefix))
|
||||
z = p.to_bind(child_ip)
|
||||
for zz in z:
|
||||
if not zz['id'] in zones:
|
||||
zones[zz['id']] = zz['content']
|
||||
|
||||
zones_list = []
|
||||
for zid,zc in zones.items():
|
||||
zones_list.append({
|
||||
'num': len(zones_list),
|
||||
'id': zid,
|
||||
'content': zc,
|
||||
})
|
||||
|
||||
return zones_list
|
||||
for p in prefixes:
|
||||
child_ip = ipam.models.IPAddress.objects.filter(address__net_contained_or_equal=str(p.prefix))
|
||||
z = p.to_bind(child_ip)
|
||||
for zz in z:
|
||||
if not zz['id'] in zones:
|
||||
zones[zz['id']] = zz['content']
|
||||
|
||||
zones_list = []
|
||||
for zid, zc in zones.items():
|
||||
zones_list.append({
|
||||
'num': len(zones_list),
|
||||
'id': zid,
|
||||
'content': zc,
|
||||
})
|
||||
|
||||
return zones_list
|
||||
|
@ -10,54 +10,58 @@ from .models import Zone, Record
|
||||
# Zones
|
||||
#
|
||||
|
||||
class ZoneTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn('dns:zone', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_count = tables.Column(verbose_name='Records')
|
||||
ttl = tables.Column(verbose_name='TTL')
|
||||
soa_name = tables.Column(verbose_name='SOA Name')
|
||||
soa_contact = tables.Column(verbose_name='SOA Contact')
|
||||
soa_serial = tables.Column(verbose_name='SOA Serial')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Zone
|
||||
fields = ('pk', 'name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial')
|
||||
class ZoneTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn('dns:zone', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_count = tables.Column(verbose_name='Records')
|
||||
ttl = tables.Column(verbose_name='TTL')
|
||||
soa_name = tables.Column(verbose_name='SOA Name')
|
||||
soa_contact = tables.Column(verbose_name='SOA Contact')
|
||||
soa_serial = tables.Column(verbose_name='SOA Serial')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Zone
|
||||
fields = ('pk', 'name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial')
|
||||
|
||||
|
||||
#
|
||||
# Records
|
||||
#
|
||||
|
||||
class RecordTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_type = tables.Column(verbose_name='Type')
|
||||
priority = tables.Column(verbose_name='Priority')
|
||||
address = tables.LinkColumn('ipam:ipaddress', args=[Accessor('address.pk')], verbose_name='IP Address')
|
||||
value = tables.Column(verbose_name='Text Value')
|
||||
zone = tables.LinkColumn('dns:zone', args=[Accessor('zone.pk')], verbose_name='Zone')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model=Record
|
||||
fields = ('pk', 'name', 'record_type', 'priority', 'address', 'value')
|
||||
class RecordTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_type = tables.Column(verbose_name='Type')
|
||||
priority = tables.Column(verbose_name='Priority')
|
||||
address = tables.LinkColumn('ipam:ipaddress', args=[Accessor('address.pk')], verbose_name='IP Address')
|
||||
value = tables.Column(verbose_name='Text Value')
|
||||
zone = tables.LinkColumn('dns:zone', args=[Accessor('zone.pk')], verbose_name='Zone')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Record
|
||||
fields = ('pk', 'name', 'record_type', 'priority', 'address', 'value')
|
||||
|
||||
|
||||
class RecordBriefTable(BaseTable):
|
||||
name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_type = tables.Column(verbose_name='Type')
|
||||
priority = tables.Column(verbose_name='Priority')
|
||||
zone = tables.LinkColumn('dns:zone', args=[Accessor('zone.pk')], verbose_name='Zone')
|
||||
name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_type = tables.Column(verbose_name='Type')
|
||||
priority = tables.Column(verbose_name='Priority')
|
||||
zone = tables.LinkColumn('dns:zone', args=[Accessor('zone.pk')], verbose_name='Zone')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Record
|
||||
fields = ('name', 'record_type', 'priority', 'zone')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model=Record
|
||||
fields = ('name', 'record_type', 'priority', 'zone')
|
||||
|
||||
class RecordZoneTable(BaseTable):
|
||||
name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_type = tables.Column(verbose_name='Type')
|
||||
priority = tables.Column(verbose_name='Priority')
|
||||
address = tables.LinkColumn('ipam:ipaddress', args=[Accessor('address.pk')], verbose_name='IP Address')
|
||||
value = tables.Column(verbose_name='Value')
|
||||
name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name')
|
||||
record_type = tables.Column(verbose_name='Type')
|
||||
priority = tables.Column(verbose_name='Priority')
|
||||
address = tables.LinkColumn('ipam:ipaddress', args=[Accessor('address.pk')], verbose_name='IP Address')
|
||||
value = tables.Column(verbose_name='Value')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model=Record
|
||||
fields = ('name', 'record_type', 'priority', 'address', 'value')
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Record
|
||||
fields = ('name', 'record_type', 'priority', 'address', 'value')
|
||||
|
@ -4,28 +4,28 @@ from . import views
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
# Zones
|
||||
url(r'^zones/$', views.ZoneListView.as_view(), name='zone_list'),
|
||||
url(r'^zones/add/$', views.ZoneEditView.as_view(), name='zone_add'),
|
||||
url(r'^zones/import/$', views.ZoneBulkImportView.as_view(), name='zone_import'),
|
||||
url(r'^zones/edit/$', views.ZoneBulkEditView.as_view(), name='zone_bulk_edit'),
|
||||
url(r'^zones/delete/$', views.ZoneBulkDeleteView.as_view(), name='zone_bulk_delete'),
|
||||
url(r'^zones/(?P<pk>\d+)/$', views.zone, name='zone'),
|
||||
url(r'^zones/(?P<pk>\d+)/edit/$', views.ZoneEditView.as_view(), name='zone_edit'),
|
||||
url(r'^zones/(?P<pk>\d+)/delete/$', views.ZoneDeleteView.as_view(), name='zone_delete'),
|
||||
# Zones
|
||||
url(r'^zones/$', views.ZoneListView.as_view(), name='zone_list'),
|
||||
url(r'^zones/add/$', views.ZoneEditView.as_view(), name='zone_add'),
|
||||
url(r'^zones/import/$', views.ZoneBulkImportView.as_view(), name='zone_import'),
|
||||
url(r'^zones/edit/$', views.ZoneBulkEditView.as_view(), name='zone_bulk_edit'),
|
||||
url(r'^zones/delete/$', views.ZoneBulkDeleteView.as_view(), name='zone_bulk_delete'),
|
||||
url(r'^zones/(?P<pk>\d+)/$', views.zone, name='zone'),
|
||||
url(r'^zones/(?P<pk>\d+)/edit/$', views.ZoneEditView.as_view(), name='zone_edit'),
|
||||
url(r'^zones/(?P<pk>\d+)/delete/$', views.ZoneDeleteView.as_view(), name='zone_delete'),
|
||||
|
||||
# Records
|
||||
url(r'^records/$', views.RecordListView.as_view(), name='record_list'),
|
||||
url(r'^records/add/$', views.RecordEditView.as_view(), name='record_add'),
|
||||
url(r'^records/import/$', views.RecordBulkImportView.as_view(), name='record_import'),
|
||||
url(r'^records/edit/$', views.RecordBulkEditView.as_view(), name='record_bulk_edit'),
|
||||
url(r'^records/delete/$', views.RecordBulkDeleteView.as_view(), name='record_bulk_delete'),
|
||||
url(r'^records/(?P<pk>\d+)/$', views.record, name='record'),
|
||||
url(r'^records/(?P<pk>\d+)/edit/$', views.RecordEditView.as_view(), name='record_edit'),
|
||||
url(r'^records/(?P<pk>\d+)/delete/$', views.RecordDeleteView.as_view(), name='record_delete'),
|
||||
# Records
|
||||
url(r'^records/$', views.RecordListView.as_view(), name='record_list'),
|
||||
url(r'^records/add/$', views.RecordEditView.as_view(), name='record_add'),
|
||||
url(r'^records/import/$', views.RecordBulkImportView.as_view(), name='record_import'),
|
||||
url(r'^records/edit/$', views.RecordBulkEditView.as_view(), name='record_bulk_edit'),
|
||||
url(r'^records/delete/$', views.RecordBulkDeleteView.as_view(), name='record_bulk_delete'),
|
||||
url(r'^records/(?P<pk>\d+)/$', views.record, name='record'),
|
||||
url(r'^records/(?P<pk>\d+)/edit/$', views.RecordEditView.as_view(), name='record_edit'),
|
||||
url(r'^records/(?P<pk>\d+)/delete/$', views.RecordDeleteView.as_view(), name='record_delete'),
|
||||
|
||||
# BIND Exports
|
||||
url(r'^bind/forward/$', views.full_forward, name='full_forward'),
|
||||
url(r'^bind/reverse/$', views.full_reverse, name='full_reverse'),
|
||||
# BIND Exports
|
||||
url(r'^bind/forward/$', views.full_forward, name='full_forward'),
|
||||
url(r'^bind/reverse/$', views.full_reverse, name='full_reverse'),
|
||||
|
||||
]
|
||||
|
@ -8,81 +8,88 @@ from django.http import HttpResponse
|
||||
from ipam.models import IPAddress, Prefix
|
||||
from utilities.paginator import EnhancedPaginator
|
||||
from utilities.views import (
|
||||
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||
)
|
||||
|
||||
from . import filters, forms, tables
|
||||
from .models import Zone, Record, export_bind_forward, export_bind_reverse
|
||||
from .tables import RecordZoneTable
|
||||
|
||||
import StringIO, zipfile, time
|
||||
import StringIO
|
||||
import zipfile
|
||||
import time
|
||||
|
||||
#
|
||||
# Zones
|
||||
#
|
||||
|
||||
|
||||
class ZoneListView(ObjectListView):
|
||||
queryset = Zone.objects.annotate(record_count=Count('records'))
|
||||
filter = filters.ZoneFilter
|
||||
filter_form = forms.ZoneFilterForm
|
||||
table = tables.ZoneTable
|
||||
edit_permissions = ['dns.change_zone', 'dns.delete_zone']
|
||||
template_name = 'dns/zone_list.html'
|
||||
queryset = Zone.objects.annotate(record_count=Count('records'))
|
||||
filter = filters.ZoneFilter
|
||||
filter_form = forms.ZoneFilterForm
|
||||
table = tables.ZoneTable
|
||||
edit_permissions = ['dns.change_zone', 'dns.delete_zone']
|
||||
template_name = 'dns/zone_list.html'
|
||||
|
||||
|
||||
def zone(request, pk):
|
||||
|
||||
zone = get_object_or_404(Zone.objects.all(), pk=pk)
|
||||
records = Record.objects.filter(zone=zone)
|
||||
record_count = len(records)
|
||||
zone = get_object_or_404(Zone.objects.all(), pk=pk)
|
||||
records = Record.objects.filter(zone=zone)
|
||||
record_count = len(records)
|
||||
|
||||
# DNS records
|
||||
dns_records = Record.objects.filter(zone=zone)
|
||||
dns_records_table = RecordZoneTable(dns_records)
|
||||
# DNS records
|
||||
dns_records = Record.objects.filter(zone=zone)
|
||||
dns_records_table = RecordZoneTable(dns_records)
|
||||
|
||||
return render(request, 'dns/zone.html', {
|
||||
'zone': zone,
|
||||
'records': records,
|
||||
'record_count': record_count,
|
||||
'dns_records_table': dns_records_table,
|
||||
})
|
||||
|
||||
return render(request, 'dns/zone.html', {
|
||||
'zone': zone,
|
||||
'records': records,
|
||||
'record_count': record_count,
|
||||
'dns_records_table': dns_records_table,
|
||||
})
|
||||
|
||||
class ZoneEditView(PermissionRequiredMixin, ObjectEditView):
|
||||
permission_required = 'dns.change_zone'
|
||||
model = Zone
|
||||
form_class = forms.ZoneForm
|
||||
cancel_url = 'dns:zone_list'
|
||||
permission_required = 'dns.change_zone'
|
||||
model = Zone
|
||||
form_class = forms.ZoneForm
|
||||
cancel_url = 'dns:zone_list'
|
||||
|
||||
|
||||
class ZoneDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||
permission_required = 'dns.delete_zone'
|
||||
model = Zone
|
||||
redirect_url = 'dns:zone_list'
|
||||
permission_required = 'dns.delete_zone'
|
||||
model = Zone
|
||||
redirect_url = 'dns:zone_list'
|
||||
|
||||
|
||||
class ZoneBulkImportView(PermissionRequiredMixin, BulkImportView):
|
||||
permission_required = 'dns.add_zone'
|
||||
form = forms.ZoneImportForm
|
||||
table = tables.ZoneTable
|
||||
template_name = 'dns/zone_import.html'
|
||||
obj_list_url = 'dns:zone_list'
|
||||
permission_required = 'dns.add_zone'
|
||||
form = forms.ZoneImportForm
|
||||
table = tables.ZoneTable
|
||||
template_name = 'dns/zone_import.html'
|
||||
obj_list_url = 'dns:zone_list'
|
||||
|
||||
|
||||
class ZoneBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
permission_required = 'dns.change_zone'
|
||||
cls = Zone
|
||||
form = forms.ZoneBulkEditForm
|
||||
template_name = 'dns/zone_bulk_edit.html'
|
||||
default_redirect_url = 'dns:zone_list'
|
||||
permission_required = 'dns.change_zone'
|
||||
cls = Zone
|
||||
form = forms.ZoneBulkEditForm
|
||||
template_name = 'dns/zone_bulk_edit.html'
|
||||
default_redirect_url = 'dns:zone_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
fields_to_update = {}
|
||||
for field in ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
zlist = self.cls.objects.filter(pk__in=pk_list)
|
||||
for z in zlist:
|
||||
z.set_bind_changed(True)
|
||||
return zlist.update(**fields_to_update)
|
||||
zlist = self.cls.objects.filter(pk__in=pk_list)
|
||||
for z in zlist:
|
||||
z.set_bind_changed(True)
|
||||
return zlist.update(**fields_to_update)
|
||||
|
||||
|
||||
class ZoneBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
@ -91,111 +98,122 @@ class ZoneBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
form = forms.ZoneBulkDeleteForm
|
||||
default_redirect_url = 'dns:zone_list'
|
||||
|
||||
|
||||
#
|
||||
# Records
|
||||
#
|
||||
|
||||
|
||||
class RecordListView(ObjectListView):
|
||||
queryset = Record.objects.all()
|
||||
filter = filters.RecordFilter
|
||||
filter_form = forms.RecordFilterForm
|
||||
table = tables.RecordTable
|
||||
edit_permissions = ['dns.change_record', 'dns.delete_record']
|
||||
template_name = 'dns/record_list.html'
|
||||
queryset = Record.objects.all()
|
||||
filter = filters.RecordFilter
|
||||
filter_form = forms.RecordFilterForm
|
||||
table = tables.RecordTable
|
||||
edit_permissions = ['dns.change_record', 'dns.delete_record']
|
||||
template_name = 'dns/record_list.html'
|
||||
|
||||
|
||||
def record(request, pk):
|
||||
|
||||
record = get_object_or_404(Record.objects.all(), pk=pk)
|
||||
bind_export = record.to_bind()
|
||||
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,
|
||||
})
|
||||
|
||||
return render(request, 'dns/record.html', {
|
||||
'record': record,
|
||||
'bind_export': bind_export,
|
||||
})
|
||||
|
||||
class RecordEditView(PermissionRequiredMixin, ObjectEditView):
|
||||
permission_required = 'dns.change_record'
|
||||
model = Record
|
||||
form_class = forms.RecordForm
|
||||
cancel_url = 'dns:record_list'
|
||||
permission_required = 'dns.change_record'
|
||||
model = Record
|
||||
form_class = forms.RecordForm
|
||||
cancel_url = 'dns:record_list'
|
||||
|
||||
|
||||
class RecordDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||
permission_required = 'dns.delete_record'
|
||||
model = Record
|
||||
redirect_url = 'dns:record_list'
|
||||
permission_required = 'dns.delete_record'
|
||||
model = Record
|
||||
redirect_url = 'dns:record_list'
|
||||
|
||||
|
||||
class RecordBulkImportView(PermissionRequiredMixin, BulkImportView):
|
||||
permission_required = 'dns.add_record'
|
||||
form = forms.RecordImportForm
|
||||
table = tables.RecordTable
|
||||
template_name = 'dns/record_import.html'
|
||||
obj_list_url = 'dns:record_list'
|
||||
permission_required = 'dns.add_record'
|
||||
form = forms.RecordImportForm
|
||||
table = tables.RecordTable
|
||||
template_name = 'dns/record_import.html'
|
||||
obj_list_url = 'dns:record_list'
|
||||
|
||||
|
||||
class RecordBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
permission_required = 'dns.change_record'
|
||||
cls = Record
|
||||
form = forms.RecordBulkEditForm
|
||||
template_name = 'dns/record_bulk_edit.html'
|
||||
default_redirect_url = 'dns:record_list'
|
||||
permission_required = 'dns.change_record'
|
||||
cls = Record
|
||||
form = forms.RecordBulkEditForm
|
||||
template_name = 'dns/record_bulk_edit.html'
|
||||
default_redirect_url = 'dns:record_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['name', 'record_type', 'priority', 'zone', 'address', 'value']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
fields_to_update = {}
|
||||
for field in ['name', 'record_type', 'priority', 'zone', 'address', 'value']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
rlist = self.cls.objects.filter(pk__in=pk_list)
|
||||
if rlist:
|
||||
rlist[0].save()
|
||||
return rlist.update(**fields_to_update)
|
||||
|
||||
rlist = self.cls.objects.filter(pk__in=pk_list)
|
||||
if rlist:
|
||||
rlist[0].save()
|
||||
return rlist.update(**fields_to_update)
|
||||
|
||||
class RecordBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'dns.delete_record'
|
||||
cls = Record
|
||||
form = forms.RecordBulkEditForm
|
||||
default_redirect_url = 'dns:record_list'
|
||||
permission_required = 'dns.delete_record'
|
||||
cls = Record
|
||||
form = forms.RecordBulkEditForm
|
||||
default_redirect_url = 'dns:record_list'
|
||||
|
||||
|
||||
#
|
||||
# BIND Exports
|
||||
#
|
||||
|
||||
def bind_export(request, zones_list, context):
|
||||
download = request.GET.get('download')
|
||||
if download:
|
||||
if download == 'all':
|
||||
zbuf = StringIO.StringIO()
|
||||
zfile = zipfile.ZipFile(zbuf, mode='w')
|
||||
temp = []
|
||||
for z in zones_list:
|
||||
temp.append(StringIO.StringIO())
|
||||
temp[len(temp)-1].write(z['content'])
|
||||
zfile.writestr(z['id'],str(temp[len(temp)-1].getvalue()))
|
||||
zfile.close()
|
||||
response = HttpResponse(
|
||||
zbuf.getvalue(),
|
||||
content_type = 'application/zip'
|
||||
)
|
||||
response['Content-Disposition'] = 'attachment; filename="netbox_dns_{}_{}.zip"'.format(context, str(int(time.time())))
|
||||
return response
|
||||
else:
|
||||
response = HttpResponse(
|
||||
zones_list[int(download)]['content'],
|
||||
content_type='text/plain'
|
||||
)
|
||||
response['Content-Disposition'] = 'attachment; filename="{}"'.format(zones_list[int(download)]['id'])
|
||||
return response
|
||||
|
||||
else:
|
||||
return render(request, 'dns/bind_export.html', {
|
||||
'context': context[0].upper() + context[1:],
|
||||
'zones': zones_list,
|
||||
'bind_export_count': len(zones_list),
|
||||
})
|
||||
def bind_export(request, zones_list, context):
|
||||
download = request.GET.get('download')
|
||||
if download:
|
||||
if download == 'all':
|
||||
zbuf = StringIO.StringIO()
|
||||
zfile = zipfile.ZipFile(zbuf, mode='w')
|
||||
temp = []
|
||||
for z in zones_list:
|
||||
temp.append(StringIO.StringIO())
|
||||
temp[len(temp) - 1].write(z['content'])
|
||||
zfile.writestr(z['id'], str(temp[len(temp) - 1].getvalue()))
|
||||
zfile.close()
|
||||
response = HttpResponse(
|
||||
zbuf.getvalue(),
|
||||
content_type='application/zip'
|
||||
)
|
||||
response['Content-Disposition'] = 'attachment; filename="netbox_dns_{}_{}.zip"'.format(context, str(int(time.time())))
|
||||
return response
|
||||
else:
|
||||
response = HttpResponse(
|
||||
zones_list[int(download)]['content'],
|
||||
content_type='text/plain'
|
||||
)
|
||||
response['Content-Disposition'] = 'attachment; filename="{}"'.format(zones_list[int(download)]['id'])
|
||||
return response
|
||||
|
||||
else:
|
||||
return render(request, 'dns/bind_export.html', {
|
||||
'context': context[0].upper() + context[1:],
|
||||
'zones': zones_list,
|
||||
'bind_export_count': len(zones_list),
|
||||
})
|
||||
|
||||
|
||||
def full_forward(request):
|
||||
return bind_export(request, export_bind_forward(), 'forward')
|
||||
return bind_export(request, export_bind_forward(), 'forward')
|
||||
|
||||
|
||||
def full_reverse(request):
|
||||
return bind_export(request, export_bind_reverse(), 'reverse')
|
||||
|
||||
return bind_export(request, export_bind_reverse(), 'reverse')
|
||||
|
@ -71,10 +71,10 @@
|
||||
"soa_name": "",
|
||||
"soa_contact": "",
|
||||
"soa_serial": "",
|
||||
"soa_refresh": "",
|
||||
"soa_retry": "",
|
||||
"soa_expire": "",
|
||||
"soa_minimum": ""
|
||||
"soa_refresh": null,
|
||||
"soa_retry": null,
|
||||
"soa_expire": null,
|
||||
"soa_minimum": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -411,7 +411,6 @@ class IPAddressFromCSVForm(forms.ModelForm):
|
||||
model = IPAddress
|
||||
fields = ['address', 'vrf', 'tenant', 'ptr', 'device', 'interface_name', 'is_primary', 'description']
|
||||
|
||||
|
||||
def clean(self):
|
||||
|
||||
device = self.cleaned_data.get('device')
|
||||
@ -461,7 +460,6 @@ class IPAddressBulkEditForm(forms.Form, BootstrapMixin):
|
||||
description = forms.CharField(max_length=100, required=False)
|
||||
|
||||
|
||||
|
||||
def ipaddress_family_choices():
|
||||
return [('', 'All'), (4, 'IPv4'), (6, 'IPv6')]
|
||||
|
||||
|
@ -13,7 +13,8 @@ import dns.models
|
||||
|
||||
from .fields import IPNetworkField, IPAddressField
|
||||
|
||||
import time, ipaddress
|
||||
import time
|
||||
import ipaddress
|
||||
import netaddr
|
||||
|
||||
|
||||
@ -245,7 +246,7 @@ class Prefix(CreatedUpdatedModel):
|
||||
|
||||
objects = PrefixQuerySet.as_manager()
|
||||
|
||||
#Reverse DNS
|
||||
# Reverse DNS
|
||||
ttl = models.PositiveIntegerField(blank=True, null=True)
|
||||
soa_name = models.CharField(max_length=100, blank=True)
|
||||
soa_contact = models.CharField(max_length=100, blank=True)
|
||||
@ -296,15 +297,15 @@ class Prefix(CreatedUpdatedModel):
|
||||
"""
|
||||
Each time a record or the zone is modified, the serial is incremented.
|
||||
"""
|
||||
current_date = time.strftime('%Y%m%d',time.localtime())
|
||||
current_date = time.strftime('%Y%m%d', time.localtime())
|
||||
if not self.soa_serial:
|
||||
self.soa_serial = current_date+'01'
|
||||
self.soa_serial = current_date + '01'
|
||||
else:
|
||||
serial_date = self.soa_serial[:8]
|
||||
serial_num = self.soa_serial[8:]
|
||||
|
||||
if serial_date!=current_date:
|
||||
self.soa_serial = current_date+'01'
|
||||
|
||||
if serial_date != current_date:
|
||||
self.soa_serial = current_date + '01'
|
||||
else:
|
||||
serial_num = int(serial_num)
|
||||
serial_num += 1
|
||||
@ -346,51 +347,51 @@ class Prefix(CreatedUpdatedModel):
|
||||
def get_status_class(self):
|
||||
return STATUS_CHOICE_CLASSES[self.status]
|
||||
|
||||
def to_bind(self,ipaddresses):
|
||||
def to_bind(self, ipaddresses):
|
||||
if self.bind_changed:
|
||||
self.update_serial()
|
||||
|
||||
zones = {}
|
||||
|
||||
def header (zone_id): return '\n'.join([
|
||||
'; '+zone_id,
|
||||
'; gen from prefix '+str(self.prefix)+' ('+(self.description if self.description else '')+') 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',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'$ORIGIN '+zone_id,
|
||||
'',
|
||||
'',
|
||||
])
|
||||
def header(zone_id):
|
||||
return '\n'.join([
|
||||
'; ' + zone_id,
|
||||
'; gen from prefix ' + str(self.prefix) + ' (' + (self.description if self.description else '') + ') 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',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'$ORIGIN ' + zone_id,
|
||||
'',
|
||||
'',
|
||||
])
|
||||
|
||||
if self.prefix.version == 4:
|
||||
pbytes = str(self.prefix).split('/')[0].split('.')
|
||||
pslash = int(str(self.prefix).split('/')[1])
|
||||
|
||||
if pslash > 16:
|
||||
pbytes[3]='0'
|
||||
pbytes[3] = '0'
|
||||
zslash = 24
|
||||
largerPrefix = Prefix.objects.filter(family=4, prefix__net_contains_or_equals=pbytes[0]+'.'+pbytes[1]+'.0.0/16')
|
||||
largerPrefix = Prefix.objects.filter(family=4, prefix__net_contains_or_equals=pbytes[0] + '.' + pbytes[1] + '.0.0/16')
|
||||
if largerPrefix:
|
||||
pbytes[2]='0'
|
||||
pbytes[2] = '0'
|
||||
zslash = 16
|
||||
else:
|
||||
pbytes[2]='0'
|
||||
pbytes[2] = '0'
|
||||
zslash = 16
|
||||
|
||||
|
||||
if pslash > zslash:
|
||||
pslash = zslash
|
||||
|
||||
p = IPNetwork(unicode('.'.join(pbytes)+'/'+str(pslash)))
|
||||
p = IPNetwork(unicode('.'.join(pbytes) + '/' + str(pslash)))
|
||||
|
||||
ipaddresses = IPAddress.objects.filter(family=4)
|
||||
for ip in ipaddresses:
|
||||
@ -402,57 +403,53 @@ class Prefix(CreatedUpdatedModel):
|
||||
if i in p:
|
||||
if zslash == 24:
|
||||
zone_id = ibytes[2] + '.' + ibytes[1] + '.' + ibytes[0] + '.in-addr.arpa.'
|
||||
if not zone_id in zones:
|
||||
if zone_id not in zones:
|
||||
zones[zone_id] = header(zone_id)
|
||||
zones[zone_id] += ibytes[3].ljust(3) + ' IN PTR ' + ip.ptr.ljust(40) + ' ; ' + ip.description.ljust(20) + ' ; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) \n'
|
||||
zones[zone_id] += ibytes[3].ljust(3) + ' IN PTR ' + ip.ptr.ljust(40) + ' ; ' + ip.description.ljust(20) + ' ; gen by netbox ( ' + time.strftime('%A %B %d %Y %H:%M:%S', time.localtime()) + ' ) \n'
|
||||
else:
|
||||
zone_id = ibytes[1]+'.'+ibytes[0]+'.in-addr.arpa.'
|
||||
if not zone_id in zones:
|
||||
zone_id = ibytes[1] + '.' + ibytes[0] + '.in-addr.arpa.'
|
||||
if zone_id not in zones:
|
||||
zones[zone_id] = header(zone_id)
|
||||
zones[zone_id] += (ibytes[3]+'.'+ibytes[2]).ljust(7) + ' IN PTR ' + ip.ptr.ljust(40) + ' ; ' + ip.description.ljust(20) + ' ; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) \n'
|
||||
|
||||
|
||||
zones[zone_id] += (ibytes[3] + '.' + ibytes[2]).ljust(7) + ' IN PTR ' + ip.ptr.ljust(40) + ' ; ' + ip.description.ljust(20) + ' ; gen by netbox ( ' + time.strftime('%A %B %d %Y %H:%M:%S', time.localtime()) + ' ) \n'
|
||||
|
||||
else:
|
||||
pfull = str(ipaddress.IPv6Address(unicode(str(self.prefix).split('/')[0])).exploded)
|
||||
pnibbles = pfull.split(':')
|
||||
pdigits = pfull.replace(':','')
|
||||
pdigits = pfull.replace(':', '')
|
||||
pslash = int(str(self.prefix).split('/')[1])
|
||||
|
||||
zslash = pslash if pslash % 16 == 0 else pslash/16+16
|
||||
pnibbles = pnibbles[:zslash/16] + ['0000'] * (8 - zslash/16)
|
||||
zslash = pslash if pslash % 16 == 0 else pslash / 16 + 16
|
||||
pnibbles = pnibbles[:zslash / 16] + ['0000'] * (8 - zslash / 16)
|
||||
|
||||
largerPrefix = Prefix.objects.filter(family=6, prefix__net_contains_or_equals=':'.join(pnibbles)+'/'+str(zslash))
|
||||
largerPrefix = Prefix.objects.filter(family=6, prefix__net_contains_or_equals=':'.join(pnibbles) + '/' + str(zslash))
|
||||
if largerPrefix:
|
||||
#choper le plus grand
|
||||
minSlash = 128
|
||||
for pp in largerPrefix:
|
||||
ppslash = int(str(pp.prefix).split('/')[1])
|
||||
if ppslash < minSlash:
|
||||
minSlash = ppslash
|
||||
zslash = minSlash
|
||||
pnibbles = pnibbles[:zslash/16] + ['0000'] * (8 - zslash/16)
|
||||
pnibbles = pnibbles[:zslash / 16] + ['0000'] * (8 - zslash / 16)
|
||||
|
||||
for ip in ipaddresses:
|
||||
if ip.ptr:
|
||||
ifull = str(ipaddress.IPv6Address(unicode(str(ip.address).split('/')[0])).exploded)
|
||||
inibbles = ifull.split(':')
|
||||
idigits = ifull.replace(':','')[::-1]
|
||||
idigits = ifull.replace(':', '')[::-1]
|
||||
islash = int(str(ip.address).split('/')[1])
|
||||
|
||||
pdigitszone = pdigits[:zslash/4][::-1]
|
||||
zone_id = '.'.join(pdigitszone)+'.ip6.arpa.'
|
||||
if not zone_id in zones:
|
||||
pdigitszone = pdigits[:zslash / 4][::-1]
|
||||
zone_id = '.'.join(pdigitszone) + '.ip6.arpa.'
|
||||
if zone_id not in zones:
|
||||
zones[zone_id] = header(zone_id)
|
||||
|
||||
zones[zone_id] += ('.'.join(idigits[:32-zslash/4])).ljust(30)+' IN PTR ' + ip.ptr.ljust(40) + ' ; ' + ip.description.ljust(20) + ' ; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) \n'
|
||||
|
||||
zones[zone_id] += ('.'.join(idigits[:32 - zslash / 4])).ljust(30) + ' IN PTR ' + ip.ptr.ljust(40) + ' ; ' + ip.description.ljust(20) + ' ; gen by netbox ( ' + time.strftime('%A %B %d %Y %H:%M:%S', time.localtime()) + ' ) \n'
|
||||
|
||||
for z in zones:
|
||||
z += '\n\n; end '
|
||||
|
||||
ret = []
|
||||
for zid,zc in zones.items():
|
||||
for zid, zc in zones.items():
|
||||
ret.append({
|
||||
'num': len(ret),
|
||||
'id': zid,
|
||||
@ -536,14 +533,14 @@ class IPAddress(CreatedUpdatedModel):
|
||||
record_name = self.ptr[:-len(zone_name)]
|
||||
if record_name.endswith('.'):
|
||||
record_name = record_name[:-1]
|
||||
record_type = 'A' if self.family==4 else 'AAAA'
|
||||
record_type = 'A' if self.family == 4 else 'AAAA'
|
||||
|
||||
dns.models.Record.objects.get_or_create(
|
||||
name = record_name,
|
||||
record_type = record_type,
|
||||
zone = which_zone,
|
||||
address = self
|
||||
)
|
||||
name=record_name,
|
||||
record_type=record_type,
|
||||
zone=which_zone,
|
||||
address=self
|
||||
)
|
||||
|
||||
def to_csv(self):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user