Skip to content

Commit

Permalink
Merge branch 'master' into py3-port
Browse files Browse the repository at this point in the history
Conflicts:
	nsupdate/main/_tests/test_main.py
  • Loading branch information
ThomasWaldmann committed Dec 24, 2013
2 parents 711aba2 + c96246d commit ba97719
Show file tree
Hide file tree
Showing 35 changed files with 373 additions and 85 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ omit =
*/migrations/*
*/_tests/*
nsupdate/wsgi.py
nsupdate/settings/*

[report]
# Regexes for lines to exclude from consideration
Expand Down
24 changes: 20 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
ChangeLog
=========

Release <TBD>
Release 0.6.0
-------------

Important notes:

* importing from nsupdate.settings does not work any more (nor
does the nsupdate.local_settings hack work any more).
in your local_settings.py, please do your imports like this::

from nsupdate.settings.dev import * # for development
# alternatively:
from nsupdate.settings.prod import * # for production
# after that, override whatever you need to override.

* if you run Django 1.6.x, you manually need to apply a patch for
django-registration (until that package is fixed for django 1.6
compatibility), see the django-registration-dj16-fix.diff in the toplevel
directory of the repo.

New Features:

* browser/javascript-based update client (the URL you need is shown in the
"browser" help panel after you add a host or generate a new secret).

Other changes:

* remove .local_settings import from settings.py, improve docs about a sane
settings setup
* cleaned up how settings work, improved docs about a sane settings setup
* document postgreSQL setup
* also support Python 2.6.x
* for debugging, add django-debug-toolbar
* also support Django 1.6.x
* for debugging, added django-debug-toolbar


Release 0.5.0
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
include README.rst CHANGES.rst LICENSE AUTHORS
include setup.cfg setup.py
include conftest.py
include django-registration-dj16-fix.diff
recursive-include docs *
recursive-exclude docs *.pyc
recursive-exclude docs *.pyo
Expand Down
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
configuration for the tests
configuration for the (py.test based) tests
"""

import pytest
Expand Down
39 changes: 39 additions & 0 deletions django-registration-dj16-fix.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Django 1.6.x compatibility fix for django-registration (which is, as of 1.0,
not compatible with Django 1.6.x).

taken from https://bitbucket.org/kubaz93/django-registration/branch/django1.6
(merged cs 2251209 and 6e1776d)


diff --git a/registration/auth_urls.py b/registration/auth_urls.py
--- a/registration/auth_urls.py
+++ b/registration/auth_urls.py
@@ -26,6 +26,7 @@
from django.conf.urls import include
from django.conf.urls import patterns
from django.conf.urls import url
+from django.core.urlresolvers import reverse_lazy

from django.contrib.auth import views as auth_views

@@ -41,15 +42,18 @@
name='auth_logout'),
url(r'^password/change/$',
auth_views.password_change,
+ {'post_change_redirect': reverse_lazy('auth_password_change_done')},
name='auth_password_change'),
url(r'^password/change/done/$',
auth_views.password_change_done,
name='auth_password_change_done'),
url(r'^password/reset/$',
auth_views.password_reset,
+ {'post_reset_redirect': reverse_lazy('auth_password_reset_done')},
name='auth_password_reset'),
- url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
+ url(r'^password/reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
auth_views.password_reset_confirm,
+ {'post_reset_redirect': reverse_lazy('auth_password_reset_complete')},
name='auth_password_reset_confirm'),
url(r'^password/reset/complete/$',
auth_views.password_reset_complete,

66 changes: 55 additions & 11 deletions docs/admin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,25 @@ Configuration
nsupdate.info Service
---------------------

Use a local_settings.py (do not modify the nsupdate/settings.py file directly)::
Use a local_settings.py (do not modify the nsupdate/settings/*.py files directly)::

from nsupdate.settings import *
# override whatever you need to override here (read nsupdate/settings.py
from nsupdate.settings.prod import *
# override whatever you need to override here (read nsupdate/settings/*.py
# to get an overview over what you might need to customize):
SECRET_KEY='S3CR3T'

IMPORTANT: you usually need to tell django what settings you want to use.

We won't document this for every single command in this documentation, but
we'll assume that you either set DJANGO_SETTINGS_MODULE environment variable
so it points to your settings module or that you give the --settings parameter
additionally with all commands that need it::

DJANGO_SETTINGS_MODULE=local_settings # this is YOUR settings file
or
django-admin.py --settings=local_settings ...
python manage.py --settings=local_settings ...


Initialize the database
-----------------------
Expand Down Expand Up @@ -67,9 +79,39 @@ see the "Domains" section in the "user" part of the manual.
Installation (for production)
=============================

You usually will use a production webserver like apache or nginx (not the
builtin "runserver"). Please consult the webserver docs how to configure it
and how to run django apps (wsgi apps) with it.
You usually will use a production webserver like apache or nginx (not Django's
builtin "runserver").

WSGI
----

Module nsupdate.wsgi contains the wsgi "application" object.

Please consult the webserver / django docs how to configure it and how to run
django apps (wsgi apps) with the webserver you use.

Django has nice generic documentation about this, see there:

https://docs.djangoproject.com/en/1.6/howto/deployment/

Even if you do not follow or fully read the deployment guide, make sure that
you at least read the checklist:

https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/


HTTP Basic Auth
---------------

Additionally, you need to make sure that the "authorization" http header needed
for HTTP Basic Auth gets through to the nsupdate.info wsgi application. Some
web servers may need special settings for this::

WSGIPassAuthorization On # use this for apache2/mod-wsgi


Static Files
------------

As soon as you switch off DEBUG, Django won't serve static files any more,
thus you need to arrange /static/ file serving by your web server.
Expand All @@ -94,10 +136,6 @@ to the outside world.

Make sure your static files really work.

Since version 1.6, Django has a nice deployment checklist (make sure stuff
applies to the django version YOU use):

https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/

PostgreSQL
----------
Expand All @@ -106,7 +144,7 @@ PostgreSQL than SQLite database. Django stores its sessions into the
database, so if you get a lot of accesses, sqlite will run into "database
is locked" issues.

Here are some notes I made when installing it using ubuntu 12.04:
Here are some notes I made when installing PostgreSQL using Ubuntu 12.04:

First installing and preparing PostgreSQL::

Expand Down Expand Up @@ -208,8 +246,14 @@ Only give Django admin access ("staff" group membership) to highly trusted admin
Software updates / upgrades
---------------------------

Please read the changelog before doing any upgrades, it might contain
important hints.

After upgrading the code, you'll usually need to run::

python manage.py migrate

This fixes your database schema so it is compatible with the new code.

Of course, you'll also need to restart the django/wsgi processes, so the new
code gets loaded.
2 changes: 1 addition & 1 deletion docs/examples/nginx_gunicorn/gunicorn_start
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ PIDFILE=/srv/nsupdate/run/gunicorn.pid
USER=www-data # the user to run as
GROUP=www-data # the group to run as
NUM_WORKERS=3 # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=nsupdate.settings # which settings file should Django use
DJANGO_SETTINGS_MODULE=nsupdate.settings.dev # which settings file should Django use
DJANGO_WSGI_MODULE=nsupdate.wsgi # WSGI module name

echo "Starting $NAME"
Expand Down
1 change: 1 addition & 0 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ Introduction
============

.. include:: ../README.rst
.. include:: ../CHANGES.rst
2 changes: 1 addition & 1 deletion manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@


if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nsupdate.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nsupdate.settings.dev")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
2 changes: 1 addition & 1 deletion nsupdate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ def __str__(self):
return version_str


version = Version(0, 5, 0)
version = Version(0, 6, 0)
1 change: 0 additions & 1 deletion nsupdate/accounts/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.conf.urls import patterns, url
from django.contrib.auth.views import password_change

from .views import UserProfileView

Expand Down
1 change: 1 addition & 0 deletions nsupdate/accounts/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-

from django.views.generic import UpdateView
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
Expand Down
13 changes: 11 additions & 2 deletions nsupdate/api/_tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
Tests for api package.
"""

import pytest

from django.core.urlresolvers import reverse

from nsupdate.main.dnstools import query_ns
from nsupdate.main.models import Domain


TEST_HOST = "test.nsupdate.info"
Expand Down Expand Up @@ -83,6 +82,16 @@ def test_nic_update_authorized(client):
assert content.startswith('good ') or content.startswith('nochg ')


def test_nic_update_authorized_ns_unavailable(client):
d = Domain.objects.get(domain=TEST_HOST)
d.available = False # simulate DNS unavailability
d.save()
response = client.get(reverse('nic_update'),
HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
assert response.status_code == 200
assert response.content == 'dnserr'


def test_nic_update_authorized_myip(client):
response = client.get(reverse('nic_update') + '?myip=4.3.2.1',
HTTP_AUTHORIZATION=make_basic_auth_header(TEST_HOST, TEST_SECRET))
Expand Down
24 changes: 19 additions & 5 deletions nsupdate/api/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# -*- coding: utf-8 -*-
"""
views for the (usually non-interactive, automated) web api
"""

import logging
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -218,7 +221,7 @@ def get(self, request, logger=None):
if ipaddr is None:
ipaddr = request.META.get('REMOTE_ADDR')
ssl = request.is_secure()
return _update(host, hostname, ipaddr, agent, ssl, logger=logger)
return _update(host, hostname, ipaddr, ssl, logger=logger)


class AuthorizedNicUpdateView(View):
Expand Down Expand Up @@ -248,15 +251,26 @@ def get(self, request, logger=None):
logger.warning('%s - is not owned by user: %s' % (hostname, request.user.username, ))
return Response('nohost')
logger.info("authenticated by session as user %s, creator of host %s" % (request.user.username, hostname))
# note: we do not check the user agent here as this is interactive
# and logged-in usage - thus misbehaved user agents are no problem.
ipaddr = request.GET.get('myip')
if not ipaddr: # None or empty string
ipaddr = request.META.get('REMOTE_ADDR')
ssl = request.is_secure()
agent = request.META.get('HTTP_USER_AGENT', 'unknown')
return _update(host, hostname, ipaddr, agent, ssl, logger=logger)
return _update(host, hostname, ipaddr, ssl, logger=logger)


def _update(host, hostname, ipaddr, agent='unknown', ssl=False, logger=None):
def _update(host, hostname, ipaddr, ssl=False, logger=None):
"""
common code shared by the 2 update views
:param host: host object
:param hostname: hostname (fqdn)
:param ipaddr: new ip addr (v4 or v6)
:param ssl: True if we use SSL/https
:param logger: a logger object
:return: Response object with dyndns2 response
"""
# we are doing abuse / available checks rather late, so the client might
# get more specific responses (like 'badagent' or 'notfqdn') by earlier
# checks. it also avoids some code duplication if done here:
Expand Down Expand Up @@ -299,4 +313,4 @@ def _update(host, hostname, ipaddr, agent='unknown', ssl=False, logger=None):
logger.error('%s - received update that resulted in a dns error [%s], ip: %s ssl: %r' % (
hostname, msg, ipaddr, ssl))
host.register_server_fault()
return Response('dnserr %s' % msg)
return Response('dnserr')
4 changes: 4 additions & 0 deletions nsupdate/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# -*- coding: utf-8 -*-
"""
context processors for injecting some settings into the template context and
also for keeping the IP addrs in the session fresh.
"""

import logging
logger = logging.getLogger(__name__)
Expand Down
6 changes: 6 additions & 0 deletions nsupdate/main/_tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def test_views_anon(client):
('generate_ns_secret_view', dict(pk=1), 302),
('delete_host', dict(pk=1), 302),
('delete_domain', dict(pk=1), 302),
('updater_hostconfig_overview', dict(pk=1), 302),
('updater_hostconfig', dict(pk=1), 302),
('delete_updater_hostconfig', dict(pk=1), 302),
# interactive updater shows http basic auth popup
('update', dict(), 401),
]:
Expand All @@ -53,6 +56,9 @@ def test_views_logged_in(client):
('generate_ns_secret_view', dict(pk=1), 200),
('delete_host', dict(pk=1), 200),
('delete_domain', dict(pk=1), 200),
('updater_hostconfig_overview', dict(pk=1), 200),
('updater_hostconfig', dict(pk=1), 200),
('delete_updater_hostconfig', dict(pk=1), 200),
('update', dict(), 401),
]:
print("%s, %s, %s" % (view, kwargs, status_code))
Expand Down
4 changes: 4 additions & 0 deletions nsupdate/main/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
register our models for Django's admin
"""

from django.contrib import admin

from .models import Host, Domain, BlacklistedDomain, ServiceUpdater, ServiceUpdaterHostConfig
Expand Down
Loading

0 comments on commit ba97719

Please sign in to comment.