Merge branch 'Dunedan-refactored-views'

This commit is contained in:
Jeffrey Forman 2015-12-26 15:15:56 -05:00
commit 8b34e7e4ae
13 changed files with 264 additions and 276 deletions

View File

@ -17,7 +17,7 @@ class ZoneException(Exception):
class RecordException(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. * Adding or deleting.
""" """

View File

@ -17,7 +17,8 @@ class CustomUnicodeListField(forms.CharField):
try: try:
string_list = [str(cur_rr) for cur_rr in eval(value)] string_list = [str(cur_rr) for cur_rr in eval(value)]
except: 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 return string_list
@ -37,7 +38,8 @@ class CustomStringPeriodSuffix(forms.CharField):
if new_string[-1] != ".": if new_string[-1] != ".":
new_string += "." new_string += "."
except: 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 return new_string
@ -50,13 +52,17 @@ class FormAddForwardRecord(forms.Form):
record_name = forms.RegexField(max_length=100, record_name = forms.RegexField(max_length=100,
regex="^[a-zA-Z0-9-_]+$", regex="^[a-zA-Z0-9-_]+$",
required=False) 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) zone_name = forms.CharField(max_length=100)
record_data = forms.GenericIPAddressField() 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) create_reverse = forms.BooleanField(required=False)
key_name = forms.ModelChoiceField(queryset=Key.objects.all(), key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False) required=False,
widget=forms.RadioSelect,
empty_label=None)
class FormAddReverseRecord(forms.Form): class FormAddReverseRecord(forms.Form):
@ -66,12 +72,17 @@ class FormAddReverseRecord(forms.Form):
dns_server = forms.CharField(max_length=100) dns_server = forms.CharField(max_length=100)
record_name = forms.IntegerField(min_value=0, max_value=255) record_name = forms.IntegerField(min_value=0, max_value=255)
record_type = forms.RegexField(regex=r"^PTR$", 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) zone_name = forms.CharField(max_length=100)
record_data = CustomStringPeriodSuffix(required=True) record_data = CustomStringPeriodSuffix(required=True)
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(), key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False) required=False,
widget=forms.RadioSelect,
empty_label=None)
create_reverse = forms.BooleanField(required=False) create_reverse = forms.BooleanField(required=False)
@ -83,9 +94,12 @@ class FormAddCnameRecord(forms.Form):
originating_record = forms.CharField(max_length=100) originating_record = forms.CharField(max_length=100)
cname = forms.RegexField(max_length=100, regex="^[a-zA-Z0-9-_]+$") cname = forms.RegexField(max_length=100, regex="^[a-zA-Z0-9-_]+$")
zone_name = forms.CharField(max_length=256) 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(), key_name = forms.ModelChoiceField(queryset=Key.objects.all(),
required=False) required=False,
widget=forms.RadioSelect,
empty_label=None)
class FormDeleteRecord(forms.Form): class FormDeleteRecord(forms.Form):
@ -96,4 +110,6 @@ class FormDeleteRecord(forms.Form):
zone_name = forms.CharField(max_length=256) zone_name = forms.CharField(max_length=256)
rr_list = CustomUnicodeListField() rr_list = CustomUnicodeListField()
key_name = forms.ModelChoiceField(queryset=Key.objects.all(), 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 # Binder Helpers
# Standard Imports # Standard Imports
import logging
import re import re
import socket import socket
# 3rd Party # 3rd Party
import dns.query import dns.query
import dns.rcode
import dns.reversename import dns.reversename
import dns.tsig import dns.tsig
import dns.tsigkeyring import dns.tsigkeyring
@ -13,6 +15,7 @@ import dns.update
# App Imports # App Imports
from binder import models from binder import models
from binder.exceptions import KeyringException, RecordException
def add_record(dns_server, zone_name, record_name, record_type, record_data, 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.""" """Delete a list of DNS records passed as strings in rr_items."""
server = models.BindServer.objects.get(hostname=dns_server) server = models.BindServer.objects.get(hostname=dns_server)
logger = logging.getLogger('binder.helpers')
try: try:
transfer_key = models.Key.objects.get(name=key_name) transfer_key = models.Key.objects.get(name=key_name)
except models.Key.DoesNotExist: except models.Key.DoesNotExist as exc:
keyring = None logger.error(exc)
algorithm = None raise KeyringException("The specified TSIG key %s does not exist in "
"binders configuration." % key_name)
else: else:
keyring = transfer_key.create_keyring() keyring = transfer_key.create_keyring()
algorithm = transfer_key.algorithm algorithm = transfer_key.algorithm
@ -107,13 +112,19 @@ def delete_record(dns_server, rr_list, key_name):
keyring=keyring, keyring=keyring,
keyalgorithm=algorithm) keyalgorithm=algorithm)
dns_update.delete(record) dns_update.delete(record)
try:
output = send_dns_update(dns_update, output = send_dns_update(dns_update,
dns_server, dns_server,
server.dns_port, server.dns_port,
key_name) key_name)
except (KeyringException, RecordException) as exc:
delete_response.append({"description": "Delete Record: %s" % current_rr, delete_response.append({"description": exc,
"output": output}) "record": current_rr,
"success": False})
else:
delete_response.append({"description": output,
"record": current_rr,
"success": True})
return delete_response 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.""" """Update/Create DNS record of name and type with passed data and ttl."""
server = models.BindServer.objects.get(hostname=dns_server) server = models.BindServer.objects.get(hostname=dns_server)
logger = logging.getLogger('binder.helpers')
try: try:
transfer_key = models.Key.objects.get(name=key_name) transfer_key = models.Key.objects.get(name=key_name)
except models.Key.DoesNotExist: except models.Key.DoesNotExist as exc:
keyring = None logger.error(exc)
algorithm = None raise KeyringException("The specified TSIG key %s does not exist in "
"binders configuration." % key_name)
else: else:
keyring = transfer_key.create_keyring() keyring = transfer_key.create_keyring()
algorithm = transfer_key.algorithm algorithm = transfer_key.algorithm
@ -174,13 +187,21 @@ def send_dns_update(dns_message, dns_server, port, key_name):
Returns: Returns:
String output String output
""" """
logger = logging.getLogger('binder.helpers')
try: try:
output = dns.query.tcp(dns_message, dns_server, port=port) output = dns.query.tcp(dns_message, dns_server, port=port)
except dns.tsig.PeerBadKey: except dns.tsig.PeerBadKey as exc:
output = ("DNS server %s is not configured for TSIG key: %s." % logger.error(exc)
raise KeyringException("DNS server %s is not configured for TSIG key: %s." %
(dns_server, key_name)) (dns_server, key_name))
except dns.tsig.PeerBadSignature: except dns.tsig.PeerBadSignature as exc:
output = ("DNS server %s did like the TSIG signature we sent. Check " logger.error(exc)
"key %s for correctness." % (dns_server, key_name)) 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 return output

View File

@ -1,5 +1,6 @@
# Django settings for binder project. # Django settings for binder project.
import os import os
from django.contrib.messages import constants as messages
SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
DEBUG = True DEBUG = True
@ -88,6 +89,38 @@ INSTALLED_APPS = (
TEST_RUNNER = 'django.test.runner.DiscoverRunner' 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"), TTL_CHOICES = ((300, "5 minutes"),
(1800, "30 minutes"), (1800, "30 minutes"),
(3600, "1 hour"), (3600, "1 hour"),

View File

@ -10,7 +10,6 @@
<script src="{% static "sorttable.js" %}"></script> <script src="{% static "sorttable.js" %}"></script>
</head> </head>
{% endblock header %} {% endblock header %}
<body> <body>
<script src="{% static "jquery-2.1.3.min.js" %}"></script> <script src="{% static "jquery-2.1.3.min.js" %}"></script>
<script src="{% static "bootstrap/js/bootstrap.min.js" %}"></script> <script src="{% static "bootstrap/js/bootstrap.min.js" %}"></script>
@ -46,23 +45,17 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
{% block errors %} {% if messages %}
{% if errors %} <ul id="messages" class="list-unstyled text-center" style="margin-bottom: 2em;">
<div class="alert alert-error"> {% for message in messages %}
Errors were encountered: <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>
<br /> {% endfor %}
{{ errors }} </ul>
</div>
{% endif %} {% endif %}
{% endblock errors %} {% block body %}{% endblock body %}
{% block body %}
{% endblock body %}
</div> </div>
</div> </div>
</div> </div>
{% block footer %}{% endblock footer %}
</body> </body>
{% block footer %}
{% endblock footer %}
</html> </html>

View File

@ -1,9 +1,9 @@
{% extends "base.html" %} {% 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 %} {% 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> <legend>Create CNAME record</legend>
<div class="form-group{% if form.dns_server.errors %} has-error{% endif %}"> <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 %}"> <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> <label for="originating_record" class="col-sm-3 control-label">Originating Record: </label>
<div class="col-sm-5 col-md-4"> <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> </div>
{% if form.originating_record.errors %} {% if form.originating_record.errors %}
<div class="col-sm-4 col-md-5"> <div class="col-sm-4 col-md-5">
@ -41,8 +41,8 @@
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<div class="input-group"> <div class="input-group">
<input id="cname" name="cname" type="text" class="form-control"{% if form.cname.value %} value="{{ form.cname.value }}"{% endif %}/> <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> <span class="input-group-addon">.{{ form.zone_name.value }}</span>
<input type="hidden" name="zone_name" value="{{zone_name}}"/> <input type="hidden" name="zone_name" value="{{ form.zone_name.value }}"/>
</div> </div>
</div> </div>
{% if form.cname.errors %} {% if form.cname.errors %}
@ -58,10 +58,8 @@
<label for="ttl" class="col-sm-3 control-label">TTL: </label> <label for="ttl" class="col-sm-3 control-label">TTL: </label>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<select id="ttl" name="ttl" class="form-control"> <select id="ttl" name="ttl" class="form-control">
{% for ttl, description in ttl_choices %} {% for choice in form.ttl %}
<option value="{{ttl}}"> <option value="{{ choice.choice_value }}">{{ choice.choice_value }} ({{ choice.choice_label }})</option>
{{ttl}} ({{description}})
</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -79,8 +77,8 @@
<label for="key_name" class="col-sm-3 control-label">TSIG Key:</label> <label for="key_name" class="col-sm-3 control-label">TSIG Key:</label>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<select id="key_name" name="key_name" class="form-control"> <select id="key_name" name="key_name" class="form-control">
{% for key in tsig_keys %} {% for key in form.key_name %}
<option value="{{key.id}}"{% if key == dns_server.default_transfer_key %} selected="selected"{% endif %}>{{key}}</option> <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 %} {% empty %}
<option selected="selected" value="" /> <option selected="selected" value="" />
{% endfor %} {% endfor %}
@ -100,7 +98,7 @@
<div class="col-sm-3"></div> <div class="col-sm-3"></div>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<button type="submit" class="btn btn-default">Save Changes</button> <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>
</div> </div>
</form> </form>

View File

@ -1,9 +1,9 @@
{% extends "base.html" %} {% 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 %} {% 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> <legend>Create Record</legend>
<div class="form-group{% if form.dns_server.errors %} has-error{% endif %}"> <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="col-sm-5 col-md-4">
<div class="input-group"> <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 %} /> <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> <span class="input-group-addon">.{{ form.zone_name.value }}</span>
<input type="hidden" name="zone_name" value="{{zone_name}}" /> <input type="hidden" name="zone_name" value="{{ form.zone_name.value }}" />
</div> </div>
</div> </div>
{% if form.record_name.errors %} {% if form.record_name.errors %}
@ -43,9 +43,9 @@
<label for="record_type" class="col-sm-3 control-label">Record Type:</label> <label for="record_type" class="col-sm-3 control-label">Record Type:</label>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<select id="record_type" name="record_type" class="form-control"> <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 %} {% if "in-addr.arpa" not in form.zone_name.value and "ip6.arpa" not in form.zone_name.value %}
{% for type, name in record_type_choices %} {% for choice in form.record_type %}
<option value="{{name}}">{{name}}</option> <option value="{{ choice.choice_value }}">{{ choice.choice_label }}</option>
{% endfor %} {% endfor %}
{% else %} {% else %}
<option value="PTR">PTR</option> <option value="PTR">PTR</option>
@ -80,10 +80,8 @@
<label for="ttl" class="col-sm-3 control-label">TTL: </label> <label for="ttl" class="col-sm-3 control-label">TTL: </label>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<select id="ttl" name="ttl" class="form-control"> <select id="ttl" name="ttl" class="form-control">
{% for ttl, description in ttl_choices %} {% for choice in form.ttl %}
<option value="{{ttl}}"> <option value="{{ choice.choice_value }}">{{ choice.choice_value }} ({{ choice.choice_label }})</option>
{{ttl}} ({{description}})
</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -97,7 +95,7 @@
{% endif %} {% endif %}
</div> </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"> <div class="form-group">
<label for="create_reverse" class="col-sm-3 control-label checkbox">Create Reverse Record (PTR):</label> <label for="create_reverse" class="col-sm-3 control-label checkbox">Create Reverse Record (PTR):</label>
<div class="col-sm-5 col-md-4"> <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> <label for="key_name" class="col-sm-3 control-label">TSIG Key:</label>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<select id="key_name" name="key_name" class="form-control"> <select id="key_name" name="key_name" class="form-control">
{% for key in tsig_keys %} {% for key in form.key_name %}
<option value="{{key.id}}"{% if key == dns_server.default_transfer_key %} selected="selected"{% endif %}>{{key}}</option> <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 %} {% empty %}
<option selected="selected" value="" /> <option selected="selected" value="" />
{% endfor %} {% endfor %}
@ -131,7 +129,7 @@
<div class="col-sm-3"></div> <div class="col-sm-3"></div>
<div class="col-sm-5 col-md-4"> <div class="col-sm-5 col-md-4">
<button type="submit" class="btn btn-default">Save Changes</button> <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>
</div> </div>
</form> </form>

View File

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

View File

@ -3,13 +3,9 @@
{% block pageheader %}Zone listing for {{ zone_name }} on {{ dns_server.hostname }}{% endblock pageheader %} {% block pageheader %}Zone listing for {{ zone_name }} on {{ dns_server.hostname }}{% endblock pageheader %}
{% block body %} {% block body %}
{% if not errors %} <p><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>
<form action="{% url "delete_record" %}" method="post">{% csrf_token %} <form action="{% url "delete_record" dns_server=dns_server zone_name=zone_name %}" method="post">{% csrf_token %}
<input type="hidden" name="dns_server" value="{{ dns_server.hostname }}">
<input type="hidden" name="zone_name" value="{{ zone_name }}">
<table class="sortable table table-condensed table-hover"> <table class="sortable table table-condensed table-hover">
<tr> <tr>
@ -48,7 +44,6 @@
{% endfor %} {% endfor %}
</table> </table>
<button class="btn btn-danger" type="submit">Delete Selected</button> <p><button class="btn btn-danger" type="submit">Delete Selected</button></p>
</form> </form>
{% endif %}
{% endblock body %} {% 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")) response = self.client.get(reverse("server_list"))
self.assertEqual(response.status_code, 200) 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): def test_GetInvalidServer(self):
"""Get a zone list for a server not in the database.""" """Get a zone list for a server not in the database."""
server_name = "unconfigured.server.net" server_name = "unconfigured.server.net"
@ -64,28 +52,31 @@ class PostTests(TestCase):
def test_DeleteRecordInitial_Empty(self): def test_DeleteRecordInitial_Empty(self):
"""Ensure the initial deletion form works as expected with no RR list.""" """Ensure the initial deletion form works as expected with no RR list."""
response = self.client.post(reverse("delete_record"), dns_server = "testserver.test.net"
{"dns_server": "testserver.test.net", zone_name = "testzone1.test.net"
"zone_name": "testzone1.test.net", response = self.client.post(reverse("delete_record",
"rr_list": []}) kwargs={'dns_server': dns_server,
'zone_name': zone_name}),
self.assertContains(response, {"rr_list": []}, follow=True)
'<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', self.assertRedirects(response,
html=True) reverse("zone_list",
self.assertContains(response, kwargs={'dns_server': dns_server,
'<input type="hidden" id="rr_list" name="rr_list" value="[]" />', 'zone_name': zone_name}))
html=True) self.assertEqual(response.status_code, 200)
self.assertContains(response, self.assertContains(response, "Select at least one record for deletion.")
'<input type="hidden" id="dns_server" name="dns_server" value="testserver.test.net" />',
html=True)
def test_DeleteRecordInitial(self): def test_DeleteRecordInitial(self):
"""Ensure the initial deletion form works as expected with RRs mentioned.""" """Ensure the initial deletion form works as expected with RRs mentioned."""
response = self.client.post(reverse("delete_record"), {"dns_server": "testserver.test.net", dns_server = "testserver.test.net"
"zone_name": "testzone1.test.net", zone_name = "testzone1.test.net"
"rr_list": ["testrecord1.testzone1.test.net", response = self.client.post(reverse("delete_record",
kwargs={'dns_server': dns_server,
'zone_name': zone_name}),
{"rr_list": ["testrecord1.testzone1.test.net",
"testrecord2.testzone1.test.net"]}) "testrecord2.testzone1.test.net"]})
self.assertEqual(response.status_code, 200)
self.assertContains(response, self.assertContains(response,
'<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', html=True) '<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', html=True)
self.assertContains(response, 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'^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/(?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/(?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 # Binder VIews
# 3rd Party # 3rd Party
from django.conf import settings from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
# App Imports # 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): def home_index(request):
"""List the main index page for Binder.""" """List the main index page for Binder."""
@ -27,75 +27,52 @@ def view_server_list(request):
def view_server_zones(request, dns_server): def view_server_zones(request, dns_server):
"""Display the list of DNS zones a particular DNS host provides.""" """Display the list of DNS zones a particular DNS host provides."""
errors = ""
zone_array = {} zone_array = {}
this_server = get_object_or_404(models.BindServer, hostname=dns_server) this_server = get_object_or_404(models.BindServer, hostname=dns_server)
try: try:
zone_array = this_server.list_zones() zone_array = this_server.list_zones()
except exceptions.ZoneException, err: except ZoneException as exc:
errors = "Unable to list server zones. Error: %s" % err messages.error(request, "Unable to list server zones. Error: %s" % exc)
return render(request, "bcommon/list_server_zones.html", return render(request, "bcommon/list_server_zones.html",
{"errors": errors, {"dns_server": this_server,
"dns_server": this_server,
"zone_array": zone_array}) "zone_array": zone_array})
def view_zone_records(request, dns_server, zone_name): def view_zone_records(request, dns_server, zone_name):
"""Display the list of records for a particular zone.""" """Display the list of records for a particular zone."""
errors = ""
zone_array = {} zone_array = {}
this_server = get_object_or_404(models.BindServer, hostname=dns_server) this_server = get_object_or_404(models.BindServer, hostname=dns_server)
try: try:
zone_array = this_server.list_zone_records(zone_name) zone_array = this_server.list_zone_records(zone_name)
except exceptions.TransferException, err: except TransferException as exc:
return render(request, "bcommon/list_zone.html", return render(request, "bcommon/list_zone.html",
{"errors": err, {"zone_name": zone_name,
"zone_name": zone_name,
"dns_server": this_server}) "dns_server": this_server})
return render(request, "bcommon/list_zone.html", return render(request, "bcommon/list_zone.html",
{"zone_array": zone_array, {"zone_array": zone_array,
"dns_server": this_server, "dns_server": this_server,
"zone_name": zone_name, "zone_name": zone_name})
"errors": errors})
def view_add_record(request, dns_server, 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) this_server = get_object_or_404(models.BindServer, hostname=dns_server)
return render(request, "bcommon/add_record_form.html", if request.method == 'POST':
{"dns_server": this_server, if "in-addr.arpa" in zone_name or "ip6.arpa" in zone_name:
"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) form = forms.FormAddReverseRecord(request.POST)
else: else:
form = forms.FormAddForwardRecord(request.POST) form = forms.FormAddForwardRecord(request.POST)
else:
form = forms.FormAddForwardRecord(request.POST)
if form.is_valid(): if form.is_valid():
form_cleaned = form.cleaned_data form_cleaned = form.cleaned_data
try: try:
response = helpers.add_record(form_cleaned["dns_server"], helpers.add_record(form_cleaned["dns_server"],
str(form_cleaned["zone_name"]), str(form_cleaned["zone_name"]),
str(form_cleaned["record_name"]), str(form_cleaned["record_name"]),
str(form_cleaned["record_type"]), str(form_cleaned["record_type"]),
@ -103,108 +80,97 @@ def view_add_record_result(request):
form_cleaned["ttl"], form_cleaned["ttl"],
form_cleaned["key_name"], form_cleaned["key_name"],
form_cleaned["create_reverse"]) form_cleaned["create_reverse"])
except exceptions.RecordException, err: except (KeyringException, RecordException) as exc:
# TODO: Start using this exception. messages.error(request, "Adding %s.%s failed: %s" %
# What would cause this? (form_cleaned["record_name"], zone_name, exc))
errors = err else:
messages.success(request, "%s.%s was added successfully." %
return render(request, "bcommon/response_result.html", (form_cleaned["record_name"], zone_name))
{"errors": errors, return redirect('zone_list',
"response": response}) dns_server=dns_server,
zone_name=zone_name)
dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"]) else:
form = forms.FormAddForwardRecord(initial={'zone_name': zone_name})
return render(request, "bcommon/add_record_form.html", return render(request, "bcommon/add_record_form.html",
{"dns_server": dns_server, {"dns_server": this_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,
"form": form}) "form": form})
def view_add_cname_record(request, dns_server, zone_name, record_name): 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) this_server = get_object_or_404(models.BindServer, hostname=dns_server)
return render(request, "bcommon/add_cname_record_form.html", if request.method == 'POST':
{"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 = ""
form = forms.FormAddCnameRecord(request.POST) form = forms.FormAddCnameRecord(request.POST)
if form.is_valid(): if form.is_valid():
form_cleaned = form.cleaned_data form_cleaned = form.cleaned_data
try: try:
add_cname_response = helpers.add_cname_record( helpers.add_cname_record(form_cleaned["dns_server"],
form_cleaned["dns_server"], str(form_cleaned["zone_name"]),
form_cleaned["zone_name"], str(form_cleaned["cname"]),
form_cleaned["cname"], '%s.%s' % (str(form_cleaned["originating_record"]),
str(form_cleaned["originating_record"]), str(form_cleaned["zone_name"])),
form_cleaned["ttl"], form_cleaned["ttl"],
form_cleaned["key_name"]) form_cleaned["key_name"])
except exceptions.RecordException, err: except (KeyringException, RecordException) as exc:
errors = err messages.error(request, "Adding %s.%s failed: %s" %
(form_cleaned["cname"], zone_name, exc))
return render(request, "bcommon/response_result.html", else:
{"response": add_cname_response, messages.success(request, "%s.%s was added successfully." %
"errors": errors}) (form_cleaned["cname"], zone_name))
return redirect('zone_list',
dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"]) 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", return render(request, "bcommon/add_cname_record_form.html",
{"dns_server": dns_server, {"dns_server": this_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(),
"form": form}) "form": form})
def view_delete_record(request): def view_delete_record(request, dns_server, zone_name):
"""Provide the initial form for deleting records.""" """View to handle the deletion of records."""
if request.method == "GET": dns_server = models.BindServer.objects.get(hostname=dns_server)
return redirect("/")
dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"])
zone_name = request.POST["zone_name"]
rr_list = request.POST.getlist("rr_list") 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, {"dns_server": dns_server,
"zone_name": zone_name, "zone_name": zone_name,
"rr_list": rr_list, "rr_list": rr_list,
"tsig_keys": models.Key.objects.all()}) "form": form})
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})