diff --git a/api/serializers.py b/api/serializers.py index 10d73349..bff1bd9c 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -191,6 +191,13 @@ class MxSerializer(NamespacedHMSerializer): fields = ('zone', 'priority', 'name', 'api_url') +class DNameSerializer(NamespacedHMSerializer): + """Serialize `machines.models.DName` objects. + """ + class Meta: + model = machines.DName + fields = ('zone', 'alias', 'api_url') + class NsSerializer(NamespacedHMSerializer): """Serialize `machines.models.Ns` objects. """ diff --git a/api/urls.py b/api/urls.py index 374436dc..2947850e 100644 --- a/api/urls.py +++ b/api/urls.py @@ -52,6 +52,7 @@ router.register_viewset(r'machines/extension', views.ExtensionViewSet) router.register_viewset(r'machines/mx', views.MxViewSet) router.register_viewset(r'machines/ns', views.NsViewSet) router.register_viewset(r'machines/txt', views.TxtViewSet) +router.register_viewset(r'machines/dname', views.DNameViewSet) router.register_viewset(r'machines/srv', views.SrvViewSet) router.register_viewset(r'machines/interface', views.InterfaceViewSet) router.register_viewset(r'machines/ipv6list', views.Ipv6ListViewSet) diff --git a/api/views.py b/api/views.py index 4b1b1246..45e083cc 100644 --- a/api/views.py +++ b/api/views.py @@ -163,6 +163,12 @@ class TxtViewSet(viewsets.ReadOnlyModelViewSet): queryset = machines.Txt.objects.all() serializer_class = serializers.TxtSerializer +class DNameViewSet(viewsets.ReadOnlyModelViewSet): + """Exposes list and details of `machines.models.DName` objects. + """ + queryset = machines.DName.objects.all() + serializer_class = serializers.DNameSerializer + class SrvViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Srv` objects. diff --git a/machines/admin.py b/machines/admin.py index 0f85007c..eb765748 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -37,6 +37,7 @@ from .models import ( Ns, Vlan, Txt, + DName, Srv, Nas, Service, @@ -95,6 +96,10 @@ class TxtAdmin(VersionAdmin): """ Admin view of a TXT object """ pass +class DNameAdmin(VersionAdmin): + """ Admin view of a DName object """ + pass + class SrvAdmin(VersionAdmin): """ Admin view of a SRV object """ @@ -144,6 +149,7 @@ admin.site.register(SOA, SOAAdmin) admin.site.register(Mx, MxAdmin) admin.site.register(Ns, NsAdmin) admin.site.register(Txt, TxtAdmin) +admin.site.register(DName, DNameAdmin) admin.site.register(Srv, SrvAdmin) admin.site.register(IpList, IpListAdmin) admin.site.register(Interface, InterfaceAdmin) diff --git a/machines/forms.py b/machines/forms.py index 91df33d4..36cd64f8 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -51,6 +51,7 @@ from .models import ( SOA, Mx, Txt, + DName, Ns, Service, Vlan, @@ -410,6 +411,34 @@ class DelTxtForm(FormRevMixin, Form): self.fields['txt'].queryset = Txt.objects.all() +class DNameForm(FormRevMixin, ModelForm): + """Add a DNAME entry for a zone""" + class Meta: + model = DName + fields = '__all__' + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(DNameForm, self).__init__(*args, prefix=prefix, **kwargs) + + +class DelDNameForm(FormRevMixin, Form): + """Delete a set of DNAME entries""" + dnames = forms.ModelMultipleChoiceField( + queryset=Txt.objects.none(), + label="Existing DNAME entries", + widget=forms.CheckboxSelectMultiple + ) + + def __init__(self, *args, **kwargs): + instances = kwargs.pop('instances', None) + super(DelDNameForm, self).__init__(*args, **kwargs) + if instances: + self.fields['dnames'].queryset = instances + else: + self.fields['dnames'].queryset = DName.objects.all() + + class SrvForm(FormRevMixin, ModelForm): """Ajout d'un srv pour une zone""" class Meta: diff --git a/machines/migrations/0088_dname.py b/machines/migrations/0088_dname.py new file mode 100644 index 00000000..4cbeb492 --- /dev/null +++ b/machines/migrations/0088_dname.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-06-25 14:33 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import re2o.mixins + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0083_remove_duplicate_rights'), + ] + + operations = [ + migrations.CreateModel( + name='DName', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('alias', models.CharField(max_length=255)), + ('zone', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Extension')), + ], + options={ + 'permissions': (('view_dname', 'Can see a dname object'),), + 'verbose_name': 'DNAME entry', + 'verbose_name_plural': 'DNAME entries' + }, + bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), + ), + ] diff --git a/machines/models.py b/machines/models.py index fd4999d6..590e3997 100644 --- a/machines/models.py +++ b/machines/models.py @@ -3,9 +3,10 @@ # se veut agnostique au réseau considéré, de manière à être installable en # quelques clics. # -# Copyright © 2017 Gabriel Détraz +# Copyright © 2016-2018 Gabriel Détraz # Copyright © 2017 Goulven Kermarec # Copyright © 2017 Augustin Lemesle +# Copyright © 2018 Charlie Jacomme # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -670,6 +671,27 @@ class Txt(RevMixin, AclMixin, models.Model): return str(self.field1).ljust(15) + " IN TXT " + str(self.field2) +class DName(RevMixin, AclMixin, models.Model): + """A DNAME entry for the DNS.""" + zone = models.ForeignKey('Extension', on_delete=models.PROTECT) + alias = models.CharField(max_length=255) + + class Meta: + permissions = ( + ("view_dname", "Can see a dname object"), + ) + verbose_name = "DNAME entry" + verbose_name_plural = "DNAME entries" + + def __str__(self): + return str(self.zone) + " : " + str(self.alias) + + @cached_property + def dns_entry(self): + """Returns the DNAME record for the DNS zone file.""" + return str(self.alias).ljust(15) + " IN DNAME " + str(self.zone) + + class Srv(RevMixin, AclMixin, models.Model): """ A SRV record """ PRETTY_NAME = "Enregistrement Srv" @@ -1687,6 +1709,18 @@ def text_post_delete(**_kwargs): regen('dns') +@receiver(post_save, sender=DName) +def dname_post_save(**_kwargs): + """Updates the DNS regen after modification of a DName object.""" + regen('dns') + + +@receiver(post_delete, sender=DName) +def dname_post_delete(**_kwargs): + """Updates the DNS regen after deletion of a DName object.""" + regen('dns') + + @receiver(post_save, sender=Srv) def srv_post_save(**_kwargs): """Regeneration dns après modification d'un SRV""" diff --git a/machines/templates/machines/aff_dname.html b/machines/templates/machines/aff_dname.html new file mode 100644 index 00000000..8ee3280e --- /dev/null +++ b/machines/templates/machines/aff_dname.html @@ -0,0 +1,47 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2018 Charlie Jacomme + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} + +
Target zone | +Record | ++ |
---|---|---|
{{ dname.zone }} | +{{ dname.dns_entry }} | ++ {% can_edit dname %} + {% include 'buttons/edit.html' with href='machines:edit-dname' id=dname.id %} + {% acl_end %} + {% include 'buttons/history.html' with href='machines:history' name='dname' id=dname.id %} + | +