diff --git a/conftest.py b/conftest.py index eb7859b..83b9ce9 100644 --- a/conftest.py +++ b/conftest.py @@ -80,6 +80,7 @@ def db_init(db): # note: db is a predefined fixture and required here to have t nameserver_update_algorithm=NAMESERVER_UPDATE_ALGORITHM, nameserver_update_secret=NAMESERVER_UPDATE_SECRET, public=NAMESERVER_PUBLIC, + available=True, created_by=u, ) # this is for querying: @@ -90,6 +91,7 @@ def db_init(db): # note: db is a predefined fixture and required here to have t nameserver_update_algorithm=NAMESERVER_UPDATE_ALGORITHM, nameserver_update_secret='invalid=', # we don't send updates there (and the real key is really secret) public=NAMESERVER_PUBLIC, + available=True, created_by=u2, ) # a Host for api / session update tests diff --git a/nsupdate/main/dnstools.py b/nsupdate/main/dnstools.py index 6447ab4..f2f9069 100644 --- a/nsupdate/main/dnstools.py +++ b/nsupdate/main/dnstools.py @@ -32,6 +32,7 @@ import dns.query import dns.update import dns.tsig import dns.tsigkeyring +import dns.exception from django.utils.timezone import now @@ -98,6 +99,31 @@ def check_ip(ipaddr, keys=('ipv4', 'ipv6')): return keys[af == dns.inet.AF_INET6] +def check_domain(domain): + fqdn = FQDN(host="connectivity-test", domain=domain) + + from .models import Domain + d = Domain.objects.get(name=domain) + # temporarily set domain to available + domain_available_state = d.available + d.available = True + d.save() + + try: + # add to primary + add(fqdn, "8.8.8.8") + # delete on primary + delete(fqdn) + + except (dns.exception.DNSException, ) as e: + raise NameServerNotAvailable(str(e)) + + finally: + # reset domain available + d.available = domain_available_state + d.save() + + def add(fqdn, ipaddr, ttl=60): """ intelligent dns adder - first does a lookup on the master server to find diff --git a/nsupdate/main/forms.py b/nsupdate/main/forms.py index 420c1a2..b50a3d5 100644 --- a/nsupdate/main/forms.py +++ b/nsupdate/main/forms.py @@ -4,8 +4,10 @@ form definitions (which fields are available, order, autofocus, ...) """ from django import forms +from django.utils.translation import ugettext_lazy as _ from .models import Host, RelatedHost, Domain, ServiceUpdaterHostConfig +from .dnstools import check_domain, NameServerNotAvailable class CreateHostForm(forms.ModelForm): @@ -44,14 +46,33 @@ class EditRelatedHostForm(forms.ModelForm): class CreateDomainForm(forms.ModelForm): class Meta(object): model = Domain - fields = ['name', 'nameserver_ip', 'nameserver2_ip', 'nameserver_update_algorithm', - 'public', 'available', 'comment'] + fields = ['name', 'nameserver_ip', 'nameserver2_ip', 'nameserver_update_algorithm', 'comment'] widgets = { 'name': forms.widgets.TextInput(attrs=dict(autofocus=None)), } class EditDomainForm(forms.ModelForm): + def clean(self): + cleaned_data = super(EditDomainForm, self).clean() + + if self.cleaned_data['available']: + try: + check_domain(self.instance.name) + + except (NameServerNotAvailable, ): + raise forms.ValidationError( + _("Failed to add/delete a test host on %(domain)s, check your DNS server configuration. " + "This is a requirement for setting the available flag."), + code='invalid', + params={'domain': self.instance.name} + ) + + if cleaned_data['public'] and not cleaned_data['available']: + raise forms.ValidationError( + _("Domain must be available to be public"), + code='invalid') + class Meta(object): model = Domain fields = ['comment', 'nameserver_ip', 'nameserver2_ip', 'public', 'available', diff --git a/nsupdate/main/migrations/0008_auto_20151229_1255.py b/nsupdate/main/migrations/0008_auto_20151229_1255.py new file mode 100644 index 0000000..a17875d --- /dev/null +++ b/nsupdate/main/migrations/0008_auto_20151229_1255.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0007_auto_20150425_1741'), + ] + + operations = [ + migrations.AlterField( + model_name='domain', + name='available', + field=models.BooleanField(default=False, help_text="Check if nameserver is available/reachable - if not checked, we'll pause querying/updating this nameserver for a while", verbose_name='available'), + ), + ] diff --git a/nsupdate/main/migrations/0009_merge.py b/nsupdate/main/migrations/0009_merge.py new file mode 100644 index 0000000..ff86ee9 --- /dev/null +++ b/nsupdate/main/migrations/0009_merge.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0008_auto_20151228_1342'), + ('main', '0008_auto_20151229_1255'), + ] + + operations = [ + ] diff --git a/nsupdate/main/models.py b/nsupdate/main/models.py index dc325dc..8414f72 100644 --- a/nsupdate/main/models.py +++ b/nsupdate/main/models.py @@ -115,7 +115,7 @@ class Domain(models.Model): # gets set to False if we have trouble reaching the nameserver available = models.BooleanField( _("available"), - default=True, + default=False, help_text=_("Check if nameserver is available/reachable - " "if not checked, we'll pause querying/updating this nameserver for a while")) comment = models.CharField( diff --git a/nsupdate/management/commands/hosts.py b/nsupdate/management/commands/hosts.py index 6955f6b..de1fd45 100644 --- a/nsupdate/management/commands/hosts.py +++ b/nsupdate/management/commands/hosts.py @@ -153,7 +153,7 @@ class Command(BaseCommand): with transaction.atomic(): for h in Host.objects.all(): if stale_check: - host = h.name + "." + h.domain + host = h.name + "." + h.domain.name comment = h.comment creator = h.created_by staleness, email_msg, log_msg = check_staleness(h)