Refactors the views used to add and delete records.

Notable changes are:
* Refactored views, utilizing more of Djangos features, resulting in simpler
  code.
* URLs are now the same when initially filling out a form and when editing a
  submitted form which contained errors.
* Instead of a result page showing the response from the DNS server (which is
  now logged using Djangos "logging" functionality) the user is now redirected
  back to the record listing of the current zone when the action was successful
  or stays on the form page when an error occured. Proper success/error
  messages are shown in both cases by utilizing Djangos "messages"
  functionality.
This commit is contained in:
Daniel Roschka 2015-09-05 19:03:21 +02:00
parent 7b3a24364c
commit e13b42cd13
13 changed files with 257 additions and 274 deletions

View File

@ -17,7 +17,7 @@ class ZoneException(Exception):
class RecordException(Exception):
"""Thrown when there is an issue dealign with a Record.
"""Thrown when there is an issue dealing with a Record.
* Adding or deleting.
"""

View File

@ -17,7 +17,8 @@ class CustomUnicodeListField(forms.CharField):
try:
string_list = [str(cur_rr) for cur_rr in eval(value)]
except:
raise ValidationError("Error in converting Unicode list to list of Strings: %r" % value)
raise ValidationError("Error in converting Unicode list to list "
"of strings: %r" % value)
return string_list
@ -37,7 +38,8 @@ class CustomStringPeriodSuffix(forms.CharField):
if new_string[-1] != ".":
new_string += "."
except:
raise ValidationError("Unable to stick a period on the end of your input: %r" % value)
raise ValidationError("Unable to stick a period on the end of "
"your input: %r" % value)
return new_string
@ -50,13 +52,17 @@ class FormAddForwardRecord(forms.Form):
record_name = forms.RegexField(max_length=100,
regex="^[a-zA-Z0-9-_]+$",
required=False)
record_type = forms.ChoiceField(choices=settings.RECORD_TYPE_CHOICES)
record_type = forms.ChoiceField(choices=settings.RECORD_TYPE_CHOICES,
widget=forms.RadioSelect)
zone_name = forms.CharField(max_length=100)
record_data = forms.GenericIPAddressField()
ttl = forms.ChoiceField(choices=settings.TTL_CHOICES)
ttl = forms.ChoiceField(choices=settings.TTL_CHOICES,
widget=forms.RadioSelect)
create_reverse = forms.BooleanField(required=False)
key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False)
required=False,
widget=forms.RadioSelect,
empty_label=None)
class FormAddReverseRecord(forms.Form):
@ -66,12 +72,16 @@ class FormAddReverseRecord(forms.Form):
dns_server = forms.CharField(max_length=100)
record_name = forms.IntegerField(min_value=0, max_value=255)
record_type = forms.RegexField(regex=r"^PTR$",
error_messages={"invalid": "The only valid choice here is PTR."})
error_messages={
"invalid": "The only valid choice here "
"is PTR."})
zone_name = forms.CharField(max_length=100)
record_data = CustomStringPeriodSuffix(required=True)
ttl = forms.ChoiceField(choices=settings.TTL_CHOICES)
key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False)
required=False,
widget=forms.RadioSelect,
empty_label=None)
create_reverse = forms.BooleanField(required=False)
@ -83,9 +93,12 @@ class FormAddCnameRecord(forms.Form):
originating_record = forms.CharField(max_length=100)
cname = forms.RegexField(max_length=100, regex="^[a-zA-Z0-9-_]+$")
zone_name = forms.CharField(max_length=256)
ttl = forms.ChoiceField(choices=settings.TTL_CHOICES)
ttl = forms.ChoiceField(choices=settings.TTL_CHOICES,
widget=forms.RadioSelect)
key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False)
required=False,
widget=forms.RadioSelect,
empty_label=None)
class FormDeleteRecord(forms.Form):
@ -96,4 +109,6 @@ class FormDeleteRecord(forms.Form):
zone_name = forms.CharField(max_length=256)
rr_list = CustomUnicodeListField()
key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False)
required=False,
widget=forms.RadioSelect,
empty_label=None)

View File

@ -1,11 +1,13 @@
# Binder Helpers
# Standard Imports
import logging
import re
import socket
# 3rd Party
import dns.query
import dns.rcode
import dns.reversename
import dns.tsig
import dns.tsigkeyring
@ -13,6 +15,7 @@ import dns.update
# App Imports
from binder import models
from binder.exceptions import KeyringException, RecordException
def add_record(dns_server, zone_name, record_name, record_type, record_data,
@ -89,11 +92,13 @@ def delete_record(dns_server, rr_list, key_name):
"""Delete a list of DNS records passed as strings in rr_items."""
server = models.BindServer.objects.get(hostname=dns_server)
logger = logging.getLogger('binder.helpers')
try:
transfer_key = models.Key.objects.get(name=key_name)
except models.Key.DoesNotExist:
keyring = None
algorithm = None
except models.Key.DoesNotExist as exc:
logger.error(exc)
raise KeyringException("The specified TSIG key %s does not exist in "
"binders configuration." % key_name)
else:
keyring = transfer_key.create_keyring()
algorithm = transfer_key.algorithm
@ -107,13 +112,19 @@ def delete_record(dns_server, rr_list, key_name):
keyring=keyring,
keyalgorithm=algorithm)
dns_update.delete(record)
try:
output = send_dns_update(dns_update,
dns_server,
server.dns_port,
key_name)
delete_response.append({"description": "Delete Record: %s" % current_rr,
"output": output})
except (KeyringException, RecordException) as exc:
delete_response.append({"description": exc,
"record": current_rr,
"success": False})
else:
delete_response.append({"description": output,
"record": current_rr,
"success": True})
return delete_response
@ -123,11 +134,13 @@ def create_update(dns_server, zone_name, record_name, record_type, record_data,
"""Update/Create DNS record of name and type with passed data and ttl."""
server = models.BindServer.objects.get(hostname=dns_server)
logger = logging.getLogger('binder.helpers')
try:
transfer_key = models.Key.objects.get(name=key_name)
except models.Key.DoesNotExist:
keyring = None
algorithm = None
except models.Key.DoesNotExist as exc:
logger.error(exc)
raise KeyringException("The specified TSIG key %s does not exist in "
"binders configuration." % key_name)
else:
keyring = transfer_key.create_keyring()
algorithm = transfer_key.algorithm
@ -174,13 +187,21 @@ def send_dns_update(dns_message, dns_server, port, key_name):
Returns:
String output
"""
logger = logging.getLogger('binder.helpers')
try:
output = dns.query.tcp(dns_message, dns_server, port=port)
except dns.tsig.PeerBadKey:
output = ("DNS server %s is not configured for TSIG key: %s." %
except dns.tsig.PeerBadKey as exc:
logger.error(exc)
raise KeyringException("DNS server %s is not configured for TSIG key: %s." %
(dns_server, key_name))
except dns.tsig.PeerBadSignature:
output = ("DNS server %s did like the TSIG signature we sent. Check "
"key %s for correctness." % (dns_server, key_name))
except dns.tsig.PeerBadSignature as exc:
logger.error(exc)
raise KeyringException("DNS server %s didn't like the TSIG signature "
"we sent. Check key %s for correctness." %
(dns_server, key_name))
logger.debug(output)
return_code = output.rcode()
if return_code != dns.rcode.NOERROR:
raise RecordException('Error when requesting DNS server %s: %s' %
(dns_server, dns.rcode.to_text(return_code)))
return output

View File

@ -1,5 +1,6 @@
# Django settings for binder project.
import os
from django.contrib.messages import constants as messages
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
DEBUG = True
@ -88,6 +89,38 @@ INSTALLED_APPS = (
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt' : "%d/%b/%Y %H:%M:%S"
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
},
'loggers': {
'django': {
'handlers': ['console'],
'propagate': True,
'level': 'INFO'
},
'binder': {
'handlers': ['console'],
'level': 'DEBUG'
}
}
}
MESSAGE_TAGS = {
messages.ERROR: 'danger'
}
TTL_CHOICES = ((300, "5 minutes"),
(1800, "30 minutes"),
(3600, "1 hour"),

View File

@ -10,7 +10,6 @@
<script src="{% static "sorttable.js" %}"></script>
</head>
{% endblock header %}
<body>
<script src="{% static "jquery-2.1.3.min.js" %}"></script>
<script src="{% static "bootstrap/js/bootstrap.min.js" %}"></script>
@ -36,6 +35,8 @@
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>{% block pageheader %}{% endblock pageheader %}</h2>
@ -44,23 +45,17 @@
</div>
<div class="row">
<div class="col-md-12">
{% block errors %}
{% if errors %}
<div class="alert alert-error">
Errors were encountered:
<br />
{{ errors }}
</div>
{% if messages %}
<ul id="messages" class="list-unstyled text-center" style="margin-bottom: 2em;">
{% for message in messages %}
<li role="alert" class="alert alert-{{ message.tags }} alert-dismissible"><button aria-label="Close" data-dismiss="alert" class="close" type="button"><span aria-hidden="true">×</span></button>{{ message.message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock errors %}
{% block body %}
{% endblock body %}
{% block body %}{% endblock body %}
</div>
</div>
</div>
{% block footer %}{% endblock footer %}
</body>
{% block footer %}
{% endblock footer %}
</html>

View File

@ -1,9 +1,9 @@
{% extends "base.html" %}
{% block pageheader %}Add CNAME record for {{ originating_record }}{% endblock pageheader %}
{% block pageheader %}Add CNAME record for {{ form.originating_record.value }}.{{ form.zone_name.value }}{% endblock pageheader %}
{% block body %}
<form class="form-horizontal" action="{% url "add_cname_result" %}" method="post">{% csrf_token %}
<form class="form-horizontal" action="{% url "add_cname" dns_server=dns_server zone_name=form.zone_name.value record_name=originating_record %}" method="post">{% csrf_token %}
<legend>Create CNAME record</legend>
<div class="form-group{% if form.dns_server.errors %} has-error{% endif %}">
@ -24,7 +24,7 @@
<div class="form-group{% if form.originating_record.errors %} has-error{% endif %}">
<label for="originating_record" class="col-sm-3 control-label">Originating Record: </label>
<div class="col-sm-5 col-md-4">
<input type="text" id="originating_record" name="originating_record" class="form-control" value="{{originating_record}}" readonly="readonly"/>
<input type="text" id="originating_record" name="originating_record" class="form-control" value="{{ form.originating_record.value }}" readonly="readonly"/>
</div>
{% if form.originating_record.errors %}
<div class="col-sm-4 col-md-5">
@ -41,8 +41,8 @@
<div class="col-sm-5 col-md-4">
<div class="input-group">
<input id="cname" name="cname" type="text" class="form-control"{% if form.cname.value %} value="{{ form.cname.value }}"{% endif %}/>
<span class="input-group-addon">.{{zone_name}}</span>
<input type="hidden" name="zone_name" value="{{zone_name}}"/>
<span class="input-group-addon">.{{ form.zone_name.value }}</span>
<input type="hidden" name="zone_name" value="{{ form.zone_name.value }}"/>
</div>
</div>
{% if form.cname.errors %}
@ -58,10 +58,8 @@
<label for="ttl" class="col-sm-3 control-label">TTL: </label>
<div class="col-sm-5 col-md-4">
<select id="ttl" name="ttl" class="form-control">
{% for ttl, description in ttl_choices %}
<option value="{{ttl}}">
{{ttl}} ({{description}})
</option>
{% for choice in form.ttl %}
<option value="{{ choice.choice_value }}">{{ choice.choice_value }} ({{ choice.choice_label }})</option>
{% endfor %}
</select>
</div>
@ -79,8 +77,8 @@
<label for="key_name" class="col-sm-3 control-label">TSIG Key:</label>
<div class="col-sm-5 col-md-4">
<select id="key_name" name="key_name" class="form-control">
{% for key in tsig_keys %}
<option value="{{key.id}}"{% if key == dns_server.default_transfer_key %} selected="selected"{% endif %}>{{key}}</option>
{% for key in form.key_name %}
<option value="{{ key.choice_value }}"{% if key.choice_value|add:0 == dns_server.default_transfer_key.id %} selected="selected"{% endif %}>{{ key.choice_label }}</option>
{% empty %}
<option selected="selected" value="" />
{% endfor %}
@ -100,7 +98,7 @@
<div class="col-sm-3"></div>
<div class="col-sm-5 col-md-4">
<button type="submit" class="btn btn-default">Save Changes</button>
<a href="{% url "zone_list" dns_server=dns_server zone_name=zone_name %}" class="btn btn-warning">Cancel</a>
<a href="{% url "zone_list" dns_server=dns_server zone_name=form.zone_name.value %}" class="btn btn-warning">Cancel</a>
</div>
</div>
</form>

View File

@ -1,9 +1,9 @@
{% extends "base.html" %}
{% block pageheader %}Add record in {{ zone_name }}{% endblock pageheader %}
{% block pageheader %}Add record in {{ form.zone_name.value }}{% endblock pageheader %}
{% block body %}
<form class="form-horizontal" action="{% url "add_record_result" %}" method="POST">{% csrf_token %}
<form class="form-horizontal" action="{% url "add_record" dns_server=dns_server zone_name=form.zone_name.value %}" method="POST">{% csrf_token %}
<legend>Create Record</legend>
<div class="form-group{% if form.dns_server.errors %} has-error{% endif %}">
@ -26,8 +26,8 @@
<div class="col-sm-5 col-md-4">
<div class="input-group">
<input id="record_name" name="record_name" type="text" class="form-control"{% if form.record_name.value %} value="{{ form.record_name.value }}"{% endif %} />
<span class="input-group-addon">.{{zone_name}}</span>
<input type="hidden" name="zone_name" value="{{zone_name}}" />
<span class="input-group-addon">.{{ form.zone_name.value }}</span>
<input type="hidden" name="zone_name" value="{{ form.zone_name.value }}" />
</div>
</div>
{% if form.record_name.errors %}
@ -43,9 +43,9 @@
<label for="record_type" class="col-sm-3 control-label">Record Type:</label>
<div class="col-sm-5 col-md-4">
<select id="record_type" name="record_type" class="form-control">
{% if "in-addr.arpa" not in zone_name and "ip6.arpa" not in zone_name %}
{% for type, name in record_type_choices %}
<option value="{{name}}">{{name}}</option>
{% if "in-addr.arpa" not in form.zone_name.value and "ip6.arpa" not in form.zone_name.value %}
{% for choice in form.record_type %}
<option value="{{ choice.choice_value }}">{{ choice.choice_label }}</option>
{% endfor %}
{% else %}
<option value="PTR">PTR</option>
@ -80,10 +80,8 @@
<label for="ttl" class="col-sm-3 control-label">TTL: </label>
<div class="col-sm-5 col-md-4">
<select id="ttl" name="ttl" class="form-control">
{% for ttl, description in ttl_choices %}
<option value="{{ttl}}">
{{ttl}} ({{description}})
</option>
{% for choice in form.ttl %}
<option value="{{ choice.choice_value }}">{{ choice.choice_value }} ({{ choice.choice_label }})</option>
{% endfor %}
</select>
</div>
@ -97,7 +95,7 @@
{% endif %}
</div>
{% if "in-addr.arpa" not in zone_name and "ip.arpa" not in zone_name %}
{% if "in-addr.arpa" not in form.zone_name.value and "ip.arpa" not in form.zone_name.value %}
<div class="form-group">
<label for="create_reverse" class="col-sm-3 control-label checkbox">Create Reverse Record (PTR):</label>
<div class="col-sm-5 col-md-4">
@ -110,8 +108,8 @@
<label for="key_name" class="col-sm-3 control-label">TSIG Key:</label>
<div class="col-sm-5 col-md-4">
<select id="key_name" name="key_name" class="form-control">
{% for key in tsig_keys %}
<option value="{{key.id}}"{% if key == dns_server.default_transfer_key %} selected="selected"{% endif %}>{{key}}</option>
{% for key in form.key_name %}
<option value="{{ key.choice_value }}"{% if key.choice_value|add:0 == dns_server.default_transfer_key.id %} selected="selected"{% endif %}>{{ key.choice_label }}</option>
{% empty %}
<option selected="selected" value="" />
{% endfor %}
@ -131,7 +129,7 @@
<div class="col-sm-3"></div>
<div class="col-sm-5 col-md-4">
<button type="submit" class="btn btn-default">Save Changes</button>
<a href="{% url "zone_list" dns_server=dns_server zone_name=zone_name %}" class="btn btn-warning">Cancel</a>
<a href="{% url "zone_list" dns_server=dns_server zone_name=form.zone_name.value %}" class="btn btn-warning">Cancel</a>
</div>
</div>
</form>

View File

@ -3,7 +3,7 @@
{% block pageheader %}Delete record(s) in {{ zone_name }}{% endblock pageheader %}
{% block body %}
<form class="form-horizontal" action="{% url "delete_record_result" %}" method="POST">{% csrf_token %}
<form class="form-horizontal" action="{% url "delete_record" dns_server=dns_server zone_name=zone_name %}" method="POST">{% csrf_token %}
<legend>Delete Record</legend>
<div class="row">
@ -39,8 +39,8 @@
<label for="key_name" class="col-sm-3 control-label">TSIG Key:</label>
<div class="col-sm-5 col-md-4">
<select id="key_name" name="key_name" class="form-control">
{% for key in tsig_keys %}
<option value="{{key.id}}"{% if key == dns_server.default_transfer_key %} selected="selected"{% endif %}>{{key}}</option>
{% for key in form.key_name %}
<option value="{{ key.choice_value }}"{% if key.choice_value|add:0 == dns_server.default_transfer_key.id %} selected="selected"{% endif %}>{{ key.choice_label }}</option>
{% empty %}
<option selected="selected" value="" />
{% endfor %}

View File

@ -3,13 +3,9 @@
{% block pageheader %}Zone listing for {{ zone_name }} on {{ dns_server.hostname }}{% endblock pageheader %}
{% block body %}
{% if not errors %}
<a href="{% url "add_record" dns_server=dns_server zone_name=zone_name %}" class="btn btn-default">Add Record</a>
<p><a href="{% url "add_record" dns_server=dns_server zone_name=zone_name %}" class="btn btn-default">Add Record</a></p>
<form action="{% url "delete_record" %}" method="post">{% csrf_token %}
<input type="hidden" name="dns_server" value="{{ dns_server.hostname }}">
<input type="hidden" name="zone_name" value="{{ zone_name }}">
<form action="{% url "delete_record" dns_server=dns_server zone_name=zone_name %}" method="post">{% csrf_token %}
<table class="sortable table table-condensed table-hover">
<tr>
@ -48,7 +44,6 @@
{% endfor %}
</table>
<button class="btn btn-danger" type="submit">Delete Selected</button>
<p><button class="btn btn-danger" type="submit">Delete Selected</button></p>
</form>
{% endif %}
{% endblock body %}

View File

@ -1,18 +0,0 @@
{% extends "base.html" %}
{% block pageheader %}Record Result{% endblock pageheader %}
{% block body %}
<table class="table">
{% for current_response in response %}
<tr>
<th>Record</th>
<th>Output</th>
</tr>
<tr>
<td>{{ current_response.description }}</td>
<td><pre>{{ current_response.output }}</pre></td>
</tr>
{% endfor %}
</table>
{% endblock body %}

View File

@ -27,18 +27,6 @@ class GetTests(TestCase):
response = self.client.get(reverse("server_list"))
self.assertEqual(response.status_code, 200)
def test_GetResultRedirects(self):
"""GETing a /result/ URL should always redirect to /."""
response = self.client.get(reverse("add_record_result"), follow=True)
self.assertRedirects(response, reverse("index"))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse("delete_record_result"), follow=True)
self.assertRedirects(response, reverse("index"))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse("add_cname_result"), follow=True)
self.assertRedirects(response, reverse("index"))
self.assertEqual(response.status_code, 200)
def test_GetInvalidServer(self):
"""Get a zone list for a server not in the database."""
server_name = "unconfigured.server.net"
@ -64,20 +52,18 @@ class PostTests(TestCase):
def test_DeleteRecordInitial_Empty(self):
"""Ensure the initial deletion form works as expected with no RR list."""
dns_server = "testserver.test.net"
zone_name = "testzone1.test.net"
response = self.client.post(reverse("delete_record"),
{"dns_server": "testserver.test.net",
"zone_name": "testzone1.test.net",
"rr_list": []})
self.assertContains(response,
'<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />',
html=True)
self.assertContains(response,
'<input type="hidden" id="rr_list" name="rr_list" value="[]" />',
html=True)
self.assertContains(response,
'<input type="hidden" id="dns_server" name="dns_server" value="testserver.test.net" />',
html=True)
{"dns_server": dns_server,
"zone_name": zone_name,
"rr_list": []}, follow=True)
self.assertRedirects(response,
reverse("zone_list",
kwargs={'dns_server': dns_server,
'zone_name': zone_name}))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Select at least one record for deletion.")
def test_DeleteRecordInitial(self):
@ -86,6 +72,8 @@ class PostTests(TestCase):
"zone_name": "testzone1.test.net",
"rr_list": ["testrecord1.testzone1.test.net",
"testrecord2.testzone1.test.net"]})
self.assertEqual(response.status_code, 200)
self.assertContains(response,
'<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', html=True)
self.assertContains(response,

View File

@ -15,11 +15,6 @@ urlpatterns = patterns('',
url(r'^info/(?P<dns_server>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/$', 'binder.views.view_zone_records', name="zone_list"),
url(r'^add_record/(?P<dns_server>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/$', 'binder.views.view_add_record', name="add_record"),
url(r'^add_record/result/$', 'binder.views.view_add_record_result', name="add_record_result"),
url(r'^delete_record/$', 'binder.views.view_delete_record', name="delete_record"),
url(r'^delete_record/result/$', 'binder.views.view_delete_result', name="delete_record_result"),
url(r'^add_cname/(?P<dns_server>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/(?P<record_name>.*?)/$', 'binder.views.view_add_cname_record', name="add_cname"),
url(r'^add_cname_record/result/$', 'binder.views.view_add_cname_result', name="add_cname_result"),
url(r'^delete_record/(?P<dns_server>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/$', 'binder.views.view_delete_record', name="delete_record"),
)

View File

@ -1,12 +1,12 @@
# Binder VIews
# 3rd Party
from django.conf import settings
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect, render
# App Imports
from binder import exceptions, forms, helpers, models
from binder import forms, helpers, models
from binder.exceptions import KeyringException, RecordException, TransferException, ZoneException
def home_index(request):
"""List the main index page for Binder."""
@ -27,75 +27,49 @@ def view_server_list(request):
def view_server_zones(request, dns_server):
"""Display the list of DNS zones a particular DNS host provides."""
errors = ""
zone_array = {}
this_server = get_object_or_404(models.BindServer, hostname=dns_server)
try:
zone_array = this_server.list_zones()
except exceptions.ZoneException, err:
errors = "Unable to list server zones. Error: %s" % err
except ZoneException as exc:
messages.error(request, "Unable to list server zones. Error: %s" % exc)
return render(request, "bcommon/list_server_zones.html",
{"errors": errors,
"dns_server": this_server,
{"dns_server": this_server,
"zone_array": zone_array})
def view_zone_records(request, dns_server, zone_name):
"""Display the list of records for a particular zone."""
errors = ""
zone_array = {}
this_server = get_object_or_404(models.BindServer, hostname=dns_server)
try:
zone_array = this_server.list_zone_records(zone_name)
except exceptions.TransferException, err:
except TransferException as exc:
return render(request, "bcommon/list_zone.html",
{"errors": err,
"zone_name": zone_name,
{"zone_name": zone_name,
"dns_server": this_server})
return render(request, "bcommon/list_zone.html",
{"zone_array": zone_array,
"dns_server": this_server,
"zone_name": zone_name,
"errors": errors})
"zone_name": zone_name})
def view_add_record(request, dns_server, zone_name):
"""View to provide form to add a DNS record."""
"""View to allow to add A records."""
this_server = get_object_or_404(models.BindServer, hostname=dns_server)
return render(request, "bcommon/add_record_form.html",
{"dns_server": this_server,
"zone_name": zone_name,
"tsig_keys": models.Key.objects.all(),
"ttl_choices": settings.TTL_CHOICES,
"record_type_choices": settings.RECORD_TYPE_CHOICES})
def view_add_record_result(request):
"""Process the input given to add a DNS record."""
errors = ""
if request.method == "GET":
return redirect("/")
if "HTTP_REFERER" in request.META:
incoming_zone = request.META["HTTP_REFERER"].split("/")[-2]
if ("in-addr.arpa" in incoming_zone) or ("ip6.arpa" in incoming_zone):
form = forms.FormAddReverseRecord(request.POST)
else:
if request.method == 'POST':
form = forms.FormAddForwardRecord(request.POST)
else:
form = forms.FormAddForwardRecord(request.POST)
if form.is_valid():
form_cleaned = form.cleaned_data
try:
response = helpers.add_record(form_cleaned["dns_server"],
helpers.add_record(form_cleaned["dns_server"],
str(form_cleaned["zone_name"]),
str(form_cleaned["record_name"]),
str(form_cleaned["record_type"]),
@ -103,108 +77,97 @@ def view_add_record_result(request):
form_cleaned["ttl"],
form_cleaned["key_name"],
form_cleaned["create_reverse"])
except exceptions.RecordException, err:
# TODO: Start using this exception.
# What would cause this?
errors = err
return render(request, "bcommon/response_result.html",
{"errors": errors,
"response": response})
dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"])
except (KeyringException, RecordException) as exc:
messages.error(request, "Adding %s.%s failed: %s" %
(form_cleaned["record_name"], zone_name, exc))
else:
messages.success(request, "%s.%s was added successfully." %
(form_cleaned["record_name"], zone_name))
return redirect('zone_list',
dns_server=dns_server,
zone_name=zone_name)
else:
form = forms.FormAddForwardRecord(initial={'zone_name': zone_name})
return render(request, "bcommon/add_record_form.html",
{"dns_server": dns_server,
"zone_name": request.POST["zone_name"],
"tsig_keys": models.Key.objects.all(),
"ttl_choices": settings.TTL_CHOICES,
"record_type_choices": settings.RECORD_TYPE_CHOICES,
{"dns_server": this_server,
"form": form})
def view_add_cname_record(request, dns_server, zone_name, record_name):
"""Process given input to add a CNAME pointer."""
"""View to allow to add CNAME records."""
this_server = get_object_or_404(models.BindServer, hostname=dns_server)
return render(request, "bcommon/add_cname_record_form.html",
{"dns_server": this_server,
"originating_record": "%s.%s" % (record_name, zone_name),
"zone_name": zone_name,
"ttl_choices": settings.TTL_CHOICES,
"tsig_keys": models.Key.objects.all()})
def view_add_cname_result(request):
"""Process input on the CNAME form and provide a response."""
if request.method == "GET":
return redirect("/")
errors = ""
add_cname_response = ""
if request.method == 'POST':
form = forms.FormAddCnameRecord(request.POST)
if form.is_valid():
form_cleaned = form.cleaned_data
try:
add_cname_response = helpers.add_cname_record(
form_cleaned["dns_server"],
form_cleaned["zone_name"],
form_cleaned["cname"],
str(form_cleaned["originating_record"]),
helpers.add_cname_record(form_cleaned["dns_server"],
str(form_cleaned["zone_name"]),
str(form_cleaned["cname"]),
'%s.%s' % (str(form_cleaned["originating_record"]),
str(form_cleaned["zone_name"])),
form_cleaned["ttl"],
form_cleaned["key_name"])
except exceptions.RecordException, err:
errors = err
return render(request, "bcommon/response_result.html",
{"response": add_cname_response,
"errors": errors})
dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"])
except (KeyringException, RecordException) as exc:
messages.error(request, "Adding %s.%s failed: %s" %
(form_cleaned["record_name"], zone_name, exc))
else:
messages.success(request, "%s.%s was added successfully." %
(form_cleaned["record_name"], zone_name))
return redirect('zone_list',
dns_server=dns_server,
zone_name=zone_name)
else:
form = forms.FormAddCnameRecord(initial={'originating_record': record_name,
'zone_name': zone_name})
return render(request, "bcommon/add_cname_record_form.html",
{"dns_server": dns_server,
"zone_name": request.POST["zone_name"],
"record_name": request.POST["cname"],
"originating_record": request.POST["originating_record"],
"ttl_choices": settings.TTL_CHOICES,
"tsig_keys": models.Key.objects.all(),
{"dns_server": this_server,
"form": form})
def view_delete_record(request):
"""Provide the initial form for deleting records."""
if request.method == "GET":
return redirect("/")
dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"])
zone_name = request.POST["zone_name"]
def view_delete_record(request, dns_server, zone_name):
"""View to handle the deletion of records."""
dns_server = models.BindServer.objects.get(hostname=dns_server)
rr_list = request.POST.getlist("rr_list")
return render(request, "bcommon/delete_record_initial.html",
if len(rr_list) == 0:
messages.error(request, "Select at least one record for deletion.")
return redirect('zone_list',
dns_server=dns_server,
zone_name=zone_name)
if request.method == 'POST':
form = forms.FormDeleteRecord(request.POST)
if form.is_valid():
form_cleaned = form.cleaned_data
rr_list = form_cleaned["rr_list"]
try:
response = helpers.delete_record(form_cleaned["dns_server"],
rr_list,
form_cleaned["key_name"])
except KeyringException as exc:
for record in rr_list:
messages.error(request, "Deleting %s.%s failed: %s" %
(record, zone_name, exc))
else:
for record in response:
if record['success'] == True:
messages.success(request, "%s.%s was removed successfully." %
(record['record'], zone_name))
else:
messages.error(request, "Deleting %s.%s failed: %s" %
(record['record'], zone_name, record['description']))
return redirect('zone_list',
dns_server=dns_server,
zone_name=zone_name)
else:
form = forms.FormDeleteRecord(initial={'zone_name': zone_name})
return render(request, "bcommon/delete_record.html",
{"dns_server": dns_server,
"zone_name": zone_name,
"rr_list": rr_list,
"tsig_keys": models.Key.objects.all()})
def view_delete_result(request):
"""View that deletes records and returns the response."""
if request.method == "GET":
return redirect("/")
form = forms.FormDeleteRecord(request.POST)
if form.is_valid():
clean_form = form.cleaned_data
else:
# TODO: What situations would cause this form
# not to validate?
print "in view_delete_result, form errors: %r" % form.errors
delete_result = helpers.delete_record(clean_form["dns_server"],
clean_form["rr_list"],
clean_form["key_name"])
return render(request, "bcommon/response_result.html",
{"response": delete_result})
"form": form})