Merge branch 'Dunedan-refactored-views'
This commit is contained in:
commit
8b34e7e4ae
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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,17 @@ 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)
|
||||
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)
|
||||
create_reverse = forms.BooleanField(required=False)
|
||||
|
||||
|
||||
|
@ -83,9 +94,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 +110,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)
|
||||
|
|
|
@ -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)
|
||||
output = send_dns_update(dns_update,
|
||||
dns_server,
|
||||
server.dns_port,
|
||||
key_name)
|
||||
|
||||
delete_response.append({"description": "Delete Record: %s" % current_rr,
|
||||
"output": output})
|
||||
try:
|
||||
output = send_dns_update(dns_update,
|
||||
dns_server,
|
||||
server.dns_port,
|
||||
key_name)
|
||||
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." %
|
||||
(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.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 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
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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>
|
||||
|
@ -46,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>
|
||||
{% endif %}
|
||||
{% endblock errors %}
|
||||
|
||||
{% block body %}
|
||||
{% endblock body %}
|
||||
{% 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 %}
|
||||
{% block body %}{% endblock body %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block footer %}{% endblock footer %}
|
||||
</body>
|
||||
|
||||
{% block footer %}
|
||||
{% endblock footer %}
|
||||
</html>
|
||||
|
|
|
@ -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,10 +77,10 @@
|
|||
<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=""/>
|
||||
<option selected="selected" value="" />
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -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>
|
||||
|
|
|
@ -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,10 +108,10 @@
|
|||
<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=""/>
|
||||
<option selected="selected" value="" />
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -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>
|
||||
|
|
|
@ -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,10 +39,10 @@
|
|||
<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=""/>
|
||||
<option selected="selected" value="" />
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
|
@ -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,28 +52,31 @@ class PostTests(TestCase):
|
|||
|
||||
def test_DeleteRecordInitial_Empty(self):
|
||||
"""Ensure the initial deletion form works as expected with no RR list."""
|
||||
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 = "testserver.test.net"
|
||||
zone_name = "testzone1.test.net"
|
||||
response = self.client.post(reverse("delete_record",
|
||||
kwargs={'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):
|
||||
"""Ensure the initial deletion form works as expected with RRs mentioned."""
|
||||
response = self.client.post(reverse("delete_record"), {"dns_server": "testserver.test.net",
|
||||
"zone_name": "testzone1.test.net",
|
||||
"rr_list": ["testrecord1.testzone1.test.net",
|
||||
"testrecord2.testzone1.test.net"]})
|
||||
dns_server = "testserver.test.net"
|
||||
zone_name = "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"]})
|
||||
|
||||
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,
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
|
|
232
binder/views.py
232
binder/views.py
|
@ -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,184 +27,150 @@ 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):
|
||||
if request.method == 'POST':
|
||||
if "in-addr.arpa" in zone_name or "ip6.arpa" in zone_name:
|
||||
form = forms.FormAddReverseRecord(request.POST)
|
||||
else:
|
||||
form = forms.FormAddForwardRecord(request.POST)
|
||||
if form.is_valid():
|
||||
form_cleaned = form.cleaned_data
|
||||
try:
|
||||
helpers.add_record(form_cleaned["dns_server"],
|
||||
str(form_cleaned["zone_name"]),
|
||||
str(form_cleaned["record_name"]),
|
||||
str(form_cleaned["record_type"]),
|
||||
str(form_cleaned["record_data"]),
|
||||
form_cleaned["ttl"],
|
||||
form_cleaned["key_name"],
|
||||
form_cleaned["create_reverse"])
|
||||
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(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
form_cleaned = form.cleaned_data
|
||||
try:
|
||||
response = helpers.add_record(form_cleaned["dns_server"],
|
||||
str(form_cleaned["zone_name"]),
|
||||
str(form_cleaned["record_name"]),
|
||||
str(form_cleaned["record_type"]),
|
||||
str(form_cleaned["record_data"]),
|
||||
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"])
|
||||
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)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = forms.FormAddCnameRecord(request.POST)
|
||||
if form.is_valid():
|
||||
form_cleaned = form.cleaned_data
|
||||
try:
|
||||
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 (KeyringException, RecordException) as exc:
|
||||
messages.error(request, "Adding %s.%s failed: %s" %
|
||||
(form_cleaned["cname"], zone_name, exc))
|
||||
else:
|
||||
messages.success(request, "%s.%s was added successfully." %
|
||||
(form_cleaned["cname"], 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": 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)
|
||||
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"]),
|
||||
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"])
|
||||
|
||||
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(),
|
||||
"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})
|
||||
"rr_list": rr_list,
|
||||
"form": form})
|
||||
|
|
Loading…
Reference in New Issue