diff --git a/netbox/dns/api/serializers.py b/netbox/dns/api/serializers.py index d99e6366b..00cd0f424 100644 --- a/netbox/dns/api/serializers.py +++ b/netbox/dns/api/serializers.py @@ -13,7 +13,7 @@ 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'] + fields = ['id', 'name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description'] def get_bind_export(self, obj): records = Record.objects.filter(zone=obj) @@ -39,7 +39,7 @@ class RecordSerializer(serializers.ModelSerializer): class Meta: model=Record - fields = ['id', 'name', 'record_type', 'priority', 'zone', 'address', 'value'] + fields = ['id', 'name', 'category', 'record_type', 'priority', 'zone', 'address', 'value', 'description'] def get_bind_export(self, obj): return { diff --git a/netbox/dns/filters.py b/netbox/dns/filters.py index 173320c0c..0f54af96e 100644 --- a/netbox/dns/filters.py +++ b/netbox/dns/filters.py @@ -6,13 +6,13 @@ from .models import ( Zone, Record, ) -from .forms import record_type_choices +from .forms import record_type_choices, record_category_choices class ZoneFilter(django_filters.FilterSet): name = django_filters.CharFilter( - name='name', - lookup_type='icontains', - label='Name', + name = 'name', + lookup_type = 'icontains', + label = 'Name', ) class Meta: @@ -21,29 +21,34 @@ class ZoneFilter(django_filters.FilterSet): 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)', + 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 = 'record_type', + label = 'Type', + choices = record_type_choices + ) + cateogry = django_filters.MultipleChoiceFilter( + name = 'category', + label = 'Category', + choices = record_category_choices ) name = django_filters.CharFilter( - name='name', - lookup_type='icontains', - label='Name', + name = 'name', + lookup_type = 'icontains', + label = 'Name', ) name_or_value = django_filters.MethodFilter( - name='name_or_value', + name = 'name_or_value', ) class Meta: model=Record - field = ['name','record_type','value'] + field = ['name', 'record_type', 'value', 'category'] def filter_name_or_value(self, queryset, value): if not value: diff --git a/netbox/dns/forms.py b/netbox/dns/forms.py index 5ba65ae34..0115fe4c9 100644 --- a/netbox/dns/forms.py +++ b/netbox/dns/forms.py @@ -19,7 +19,7 @@ class ZoneForm(forms.ModelForm, BootstrapMixin): class Meta: model=Zone - fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum'] + fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description'] labels = { 'soa_name': 'SOA Name', 'soa_contact': 'SOA Contact', @@ -28,6 +28,7 @@ class ZoneForm(forms.ModelForm, BootstrapMixin): 'soa_retry': 'SOA Retry', 'soa_expire': 'SOA Expire', 'soa_minimum': 'SOA Minimum', + 'description': 'Description', } help_texts = { 'ttl': "Time to live, in seconds", @@ -44,7 +45,7 @@ class ZoneFromCSVForm(forms.ModelForm): class Meta: model=Zone - fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum'] + fields = ['name', 'ttl', 'soa_name', 'soa_contact', 'soa_serial', 'soa_refresh', 'soa_retry', 'soa_expire', 'soa_minimum', 'description'] class ZoneImportForm(BulkImportForm, BootstrapMixin): csv = CSVDataField(csv_form=ZoneFromCSVForm) @@ -59,6 +60,7 @@ class ZoneBulkEditForm(forms.Form, BootstrapMixin): 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): @@ -75,13 +77,14 @@ class RecordForm(forms.ModelForm, BootstrapMixin): class Meta: model=Record - fields = ['name', 'record_type', 'priority', 'zone', 'address', 'value'] + fields = ['name', 'category', '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)', + 'category': 'Category (e.g. SLA, Server or Customer)', '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', @@ -95,7 +98,7 @@ class RecordFromCSVForm(forms.ModelForm): class Meta: model=Record - fields = ['zone', 'name', 'record_type', 'priority', 'address', 'value'] + fields = ['zone', 'name', 'category', 'record_type', 'priority', 'address', 'value', 'description'] class RecordImportForm(BulkImportForm, BootstrapMixin): csv = CSVDataField(csv_form=RecordFromCSVForm) @@ -103,6 +106,7 @@ class RecordImportForm(BulkImportForm, BootstrapMixin): 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') + category = forms.CharField(max_length=100, required=False, label='Category') 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) @@ -126,9 +130,22 @@ def record_type_choices(): type_choices[r.record_type]+=1 return [(t, '{} ({})'.format(t, count)) for t,count in type_choices.items()] +def record_category_choices(): + category_choices = {} + records = Record.objects.all() + for r in records: + if r.category: + if not r.category in category_choices: + category_choices[r.category]=1 + else: + category_choices[r.category]+=1 + return [(c, '{} ({})'.format(c, count)) for c,count in category_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})) + category = forms.MultipleChoiceField(required=False, choices=record_category_choices, label='Category', + widget=forms.SelectMultiple(attrs={'size': 8})) diff --git a/netbox/dns/migrations/0003_auto_20160721_1059.py b/netbox/dns/migrations/0003_auto_20160721_1059.py new file mode 100644 index 000000000..c060e6404 --- /dev/null +++ b/netbox/dns/migrations/0003_auto_20160721_1059.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-21 10:59 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dns', '0002_auto_20160719_1058'), + ] + + operations = [ + migrations.AlterModelOptions( + name='record', + options={'ordering': ['category']}, + ), + migrations.AddField( + model_name='record', + name='category', + field=models.CharField(blank=True, max_length=20), + ), + migrations.AddField( + model_name='record', + name='description', + field=models.CharField(blank=True, max_length=20), + ), + migrations.AddField( + model_name='zone', + name='description', + field=models.CharField(blank=True, max_length=100), + ), + ] diff --git a/netbox/dns/models.py b/netbox/dns/models.py index 4ca2aff37..a5857cabc 100644 --- a/netbox/dns/models.py +++ b/netbox/dns/models.py @@ -13,15 +13,16 @@ 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) - soa_serial=models.CharField(max_length=100) - soa_refresh=models.PositiveIntegerField() - soa_retry=models.PositiveIntegerField() - soa_expire=models.PositiveIntegerField() - soa_minimum=models.PositiveIntegerField() + 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=100) + 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'] @@ -43,6 +44,7 @@ class Zone(CreatedUpdatedModel): str(self.soa_retry), str(self.soa_expire), str(self.soa_minimum), + self.description, ]) def to_bind(self,records): @@ -50,6 +52,7 @@ class Zone(CreatedUpdatedModel): 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), @@ -73,15 +76,17 @@ 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.SET_NULL, blank=True, null=True) - value=models.CharField(max_length=100, blank=True) + 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.SET_NULL, blank=True, null=True) + value = models.CharField(max_length=100, blank=True) + category = models.CharField(max_length=20, blank=True) + description = models.CharField(max_length=20, blank=True) class Meta: - ordering = ['name'] + ordering = ['category'] def __unicode__(self): return self.name @@ -98,10 +103,12 @@ class Record(CreatedUpdatedModel): return ','.join([ self.zone.name, self.name, + self.category, self.record_type, str(self.priority) if self.priority else '', str(self.address) if self.address else '', - str(self.value) if self.value else '', + self.value, + self.description, ]) def to_bind(self): @@ -114,7 +121,7 @@ class Record(CreatedUpdatedModel): ' ', (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())+' ) ' + ' ; '+self.description+' ; gen by netbox ( '+time.strftime('%A %B %d %Y %H:%M:%S',time.localtime())+' ) ' ]) diff --git a/netbox/dns/tables.py b/netbox/dns/tables.py index 8d0177584..2b48706bc 100644 --- a/netbox/dns/tables.py +++ b/netbox/dns/tables.py @@ -30,6 +30,7 @@ class ZoneTable(BaseTable): class RecordTable(BaseTable): pk = ToggleColumn() name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name') + category = tables.Column(verbose_name='Category') 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') @@ -38,15 +39,16 @@ class RecordTable(BaseTable): class Meta(BaseTable.Meta): model=Record - fields = ('pk', 'name', 'record_type', 'priority', 'address', 'value') + fields = ('pk', 'name', 'category', 'record_type', 'priority', 'address', 'value') class RecordBriefTable(BaseTable): name = tables.LinkColumn('dns:record', args=[Accessor('pk')], verbose_name='Name') + category = tables.Column(verbose_name='Category') 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') + fields = ('name', 'category', 'record_type', 'priority', 'zone') \ No newline at end of file diff --git a/netbox/templates/dns/record.html b/netbox/templates/dns/record.html index 95d35e15b..00055d89c 100644 --- a/netbox/templates/dns/record.html +++ b/netbox/templates/dns/record.html @@ -56,6 +56,15 @@
foo.net,www,AAAA,,192.168.1.110/16,+
foo.net,www,Server,AAAA,,192.168.1.110/16,,Backend API server{% endblock %} diff --git a/netbox/templates/dns/zone.html b/netbox/templates/dns/zone.html index 58ec0ec45..4b76d5ea8 100644 --- a/netbox/templates/dns/zone.html +++ b/netbox/templates/dns/zone.html @@ -90,6 +90,16 @@
foo.net,10800,@,ns.foo.net. noc.foo.net.,2016070401,3600,3600,604800,1800+
foo.net,10800,@,ns.foo.net. noc.foo.net.,2016070401,3600,3600,604800,1800,Mail servers zone{% endblock %}