From b736d5c04116957efee2490454650089de406a90 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 30 May 2014 00:17:21 +0200 Subject: [PATCH 01/18] add celery and sqlparse requirements --- requirements/base.txt | 1 + requirements/local.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/requirements/base.txt b/requirements/base.txt index a6a6fbf..b1247b0 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,3 +5,4 @@ django-braces==1.4.0 django-model-utils==2.0.3 logutils==0.3.3 South==0.8.4 +celery==3.1.11 diff --git a/requirements/local.txt b/requirements/local.txt index 644abf3..5f597de 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -3,3 +3,4 @@ coverage==3.7.1 django-debug-toolbar==1.2.1 Sphinx==1.2.2 +sqlparse==0.1.11 From 3babbc5b3fdd47b9435d277af3fdc7700b6bce5a Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 30 May 2014 01:07:25 +0200 Subject: [PATCH 02/18] implement LDAP group and user classes - add app ldapentities - add new settings GROUP_BASE_DN and USER_BASE_DN - implement ldapentities.models.LdapUser and ldapentities.models.LdapGroup - implement ldapentities.admin.LdapUserAdmin and ldapentities.models.LdapGroupAdmin --- gvaldap/gvaldap/settings/base.py | 7 +++++ gvaldap/ldapentities/__init__.py | 0 gvaldap/ldapentities/admin.py | 22 ++++++++++++++ gvaldap/ldapentities/models.py | 50 ++++++++++++++++++++++++++++++++ gvaldap/ldapentities/tests.py | 3 ++ 5 files changed, 82 insertions(+) create mode 100644 gvaldap/ldapentities/__init__.py create mode 100644 gvaldap/ldapentities/admin.py create mode 100644 gvaldap/ldapentities/models.py create mode 100644 gvaldap/ldapentities/tests.py diff --git a/gvaldap/gvaldap/settings/base.py b/gvaldap/gvaldap/settings/base.py index 6a5573d..17ddf14 100644 --- a/gvaldap/gvaldap/settings/base.py +++ b/gvaldap/gvaldap/settings/base.py @@ -216,6 +216,7 @@ DJANGO_APPS = ( # Apps specific for this project go here. LOCAL_APPS = ( + 'ldapentities', ) # See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps @@ -262,6 +263,12 @@ WSGI_APPLICATION = '%s.wsgi.application' % SITE_NAME ########## END WSGI CONFIGURATION +########## LDAP SETTINGS +GROUP_BASE_DN = get_env_setting('GVALDAP_BASEDN_GROUP') +USER_BASE_DN = get_env_setting('GVALDAP_BASEDN_USER') +########## END LDAP SETTINGS + + ########## SOUTH CONFIGURATION # See: http://south.readthedocs.org/en/latest/installation.html#configuring-your-django-installation INSTALLED_APPS += ( diff --git a/gvaldap/ldapentities/__init__.py b/gvaldap/ldapentities/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gvaldap/ldapentities/admin.py b/gvaldap/ldapentities/admin.py new file mode 100644 index 0000000..8d46d8a --- /dev/null +++ b/gvaldap/ldapentities/admin.py @@ -0,0 +1,22 @@ +from django.contrib import admin + +from .models import ( + LdapGroup, + LdapUser, +) + + +class LdapGroupAdmin(admin.ModelAdmin): + exclude = ['dn', 'members'] + list_display = ['name', 'gid'] + search_fields = ['name'] + + +class LdapUserAdmin(admin.ModelAdmin): + exclude = ['dn', 'password'] + list_display = ['username', 'uid'] + search_fields = ['username'] + + +admin.site.register(LdapGroup, LdapGroupAdmin) +admin.site.register(LdapUser, LdapUserAdmin) diff --git a/gvaldap/ldapentities/models.py b/gvaldap/ldapentities/models.py new file mode 100644 index 0000000..21867b1 --- /dev/null +++ b/gvaldap/ldapentities/models.py @@ -0,0 +1,50 @@ +from django.conf import settings +from django.utils.encoding import python_2_unicode_compatible +from ldapdb.models.fields import ( + CharField, + IntegerField, + ListField, +) +import ldapdb.models as ldapmodels + + +@python_2_unicode_compatible +class LdapGroup(ldapmodels.Model): + """ + Class for representing an LDAP group entity. + + """ + # LDAP meta-data + base_dn = settings.GROUP_BASE_DN + object_classes = ['posixGroup'] + + # posixGroup attributes + gid = IntegerField(db_column='gidNumber', unique=True) + name = CharField(db_column='cn', max_length=200, primary_key=True) + members = ListField(db_column='memberUid', blank=True) + + def __str__(self): + return self.name + + +@python_2_unicode_compatible +class LdapUser(ldapmodels.Model): + """ + Class for representing an LDAP user entity. + + """ + base_dn = settings.USER_BASE_DN + object_classes = ['account', 'posixAccount'] + + # posixAccount + uid = IntegerField(db_column='uidNumber', unique=True) + group = IntegerField(db_column='gidNumber') + gecos = CharField(db_column='gecos') + home_directory = CharField(db_column='homeDirectory') + login_shell = CharField(db_column='loginShell', default='/bin/bash') + username = CharField(db_column='uid', primary_key=True) + password = CharField(db_column='userPassword') + common_name = CharField(db_column='cn') + + def __str__(self): + return self.username diff --git a/gvaldap/ldapentities/tests.py b/gvaldap/ldapentities/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/gvaldap/ldapentities/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. From 72f5d78c10df4b4230b2dcd8f9c970963cd6a216 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 30 May 2014 01:13:41 +0200 Subject: [PATCH 03/18] implement LDAP password hashing - add passlib to requirements/base.txt - implement ldapentities.models.LdapUser.set_password --- gvaldap/ldapentities/models.py | 5 +++++ requirements/base.txt | 1 + 2 files changed, 6 insertions(+) diff --git a/gvaldap/ldapentities/models.py b/gvaldap/ldapentities/models.py index 21867b1..f4ee071 100644 --- a/gvaldap/ldapentities/models.py +++ b/gvaldap/ldapentities/models.py @@ -7,6 +7,8 @@ from ldapdb.models.fields import ( ) import ldapdb.models as ldapmodels +from passlib.hash import ldap_salted_sha1 + @python_2_unicode_compatible class LdapGroup(ldapmodels.Model): @@ -48,3 +50,6 @@ class LdapUser(ldapmodels.Model): def __str__(self): return self.username + + def set_password(self, password): + self.password = ldap_salted_sha1.encrypt(password) diff --git a/requirements/base.txt b/requirements/base.txt index b1247b0..f3ed2c7 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -6,3 +6,4 @@ django-model-utils==2.0.3 logutils==0.3.3 South==0.8.4 celery==3.1.11 +passlib==1.6.2 From 1575725bcb04990e77d0d42ce902daec7b3d4ae3 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 30 May 2014 12:12:21 +0200 Subject: [PATCH 04/18] add celery tasks - add celery application code in gvaldap.celery - add osusers app to mimic the osusers code in the main gnuviechadmin code - add celery configuration settings to gvaldap.settings.base - add osusers.models.Group and osusers.models.User - add osusers.tasks.create_ldap_group and osusers.tasks.create_ldap_user - add billiard, kombu and pytz to requirements/base.txt --- gvaldap/gvaldap/celery.py | 21 ++++++++++++++++ gvaldap/gvaldap/settings/base.py | 10 ++++++++ gvaldap/osusers/__init__.py | 0 gvaldap/osusers/admin.py | 3 +++ gvaldap/osusers/models.py | 42 ++++++++++++++++++++++++++++++++ gvaldap/osusers/tasks.py | 28 +++++++++++++++++++++ gvaldap/osusers/tests.py | 3 +++ requirements/base.txt | 3 +++ 8 files changed, 110 insertions(+) create mode 100644 gvaldap/gvaldap/celery.py create mode 100644 gvaldap/osusers/__init__.py create mode 100644 gvaldap/osusers/admin.py create mode 100644 gvaldap/osusers/models.py create mode 100644 gvaldap/osusers/tasks.py create mode 100644 gvaldap/osusers/tests.py diff --git a/gvaldap/gvaldap/celery.py b/gvaldap/gvaldap/celery.py new file mode 100644 index 0000000..fd9a616 --- /dev/null +++ b/gvaldap/gvaldap/celery.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import + +import os + +from celery import Celery + +from django.conf import settings + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', + 'gvaldap.settings.production') + + +app = Celery('gvaldap') + +app.config_from_object('django.conf:settings') +app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) + + +@app.task(bind=True) +def debug_task(self): + print('Request: {0!r}'.format(self.request)) diff --git a/gvaldap/gvaldap/settings/base.py b/gvaldap/gvaldap/settings/base.py index 17ddf14..525fd78 100644 --- a/gvaldap/gvaldap/settings/base.py +++ b/gvaldap/gvaldap/settings/base.py @@ -217,6 +217,7 @@ DJANGO_APPS = ( # Apps specific for this project go here. LOCAL_APPS = ( 'ldapentities', + 'osusers', ) # See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps @@ -278,3 +279,12 @@ INSTALLED_APPS += ( # Don't need to use South when setting up a test database. SOUTH_TESTS_MIGRATE = False ########## END SOUTH CONFIGURATION + + +########## CELERY CONFIGURATION +BROKER_URL = get_env_setting('GVALDAP_BROKER_URL') +CELERY_RESULT_BACKEND = 'amqp' +CELERY_RESULT_PERSISTENT = True +CELERY_TASK_RESULT_EXPIRES = None +CELERY_ACCEPT_CONTENT = ['pickle'] +########## END CELERY CONFIGURATION diff --git a/gvaldap/osusers/__init__.py b/gvaldap/osusers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gvaldap/osusers/admin.py b/gvaldap/osusers/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/gvaldap/osusers/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/gvaldap/osusers/models.py b/gvaldap/osusers/models.py new file mode 100644 index 0000000..e1c641f --- /dev/null +++ b/gvaldap/osusers/models.py @@ -0,0 +1,42 @@ +from django.db import models +from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext as _ + +from model_utils.models import TimeStampedModel + + +@python_2_unicode_compatible +class Group(TimeStampedModel, models.Model): + groupname = models.CharField( + _('Group name'), max_length=16, unique=True) + gid = models.PositiveSmallIntegerField( + _('Group ID'), unique=True, primary_key=True) + descr = models.TextField(_('Description'), blank=True) + passwd = models.CharField( + _('Group password'), max_length=128, blank=True) + + class Meta: + verbose_name = _('Group') + verbose_name_plural = _('Groups') + + def __str__(self): + return '{0} ({1})'.format(self.groupname, self.gid) + + +@python_2_unicode_compatible +class User(TimeStampedModel, models.Model): + username = models.CharField( + _('User name'), max_length=64, unique=True) + uid = models.PositiveSmallIntegerField( + _('User ID'), unique=True, primary_key=True) + group = models.ForeignKey(Group, verbose_name=_('Group')) + gecos = models.CharField(_('Gecos field'), max_length=128, blank=True) + homedir = models.CharField(_('Home directory'), max_length=256) + shell = models.CharField(_('Login shell'), max_length=64) + + class Meta: + verbose_name = _('User') + verbose_name_plural = _('Users') + + def __str__(self): + return '{0} ({1})'.format(self.username, self.uid) diff --git a/gvaldap/osusers/tasks.py b/gvaldap/osusers/tasks.py new file mode 100644 index 0000000..f0b6fbc --- /dev/null +++ b/gvaldap/osusers/tasks.py @@ -0,0 +1,28 @@ +from __future__ import absolute_import + +from celery import shared_task +from ldapentities.models import ( + LdapGroup, + LdapUser, +) + + +@shared_task +def create_ldap_group(group): + ldapgroup = LdapGroup(gid=group.gid, name=group.groupname) + ldapgroup.save() + return ldapgroup.dn + + +@shared_task +def create_ldap_user(user, password): + ldapuser = LdapUser( + uid=user.uid, group=user.group.gid, gecos=user.gecos, + home_directory=user.homedir, login_shell=user.shell, + username=user.username, common_name=user.username) + ldapuser.set_password(password) + ldapgroup = LdapGroup.objects.get(gid=ldapuser.group) + ldapgroup.members.append(ldapuser.username) + ldapgroup.save() + ldapuser.save() + return ldapuser.dn diff --git a/gvaldap/osusers/tests.py b/gvaldap/osusers/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/gvaldap/osusers/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/requirements/base.txt b/requirements/base.txt index f3ed2c7..3f694fb 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,3 +7,6 @@ logutils==0.3.3 South==0.8.4 celery==3.1.11 passlib==1.6.2 +billiard==3.3.0.17 +kombu==3.0.16 +pytz==2014.3 From 5174e144baa14d710949c55780ea87363cae45e0 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 30 May 2014 18:37:58 +0200 Subject: [PATCH 05/18] use YAML for celery serialization - add CELERY_ACCEPT_CONTENT, CELERY_TASK_SERIALIZER and CELERY_RESULT_SERIALIZER in gvaldap.settings.base - add pyaml to requirements/base.txt --- gvaldap/gvaldap/settings/base.py | 3 ++- requirements/base.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gvaldap/gvaldap/settings/base.py b/gvaldap/gvaldap/settings/base.py index 525fd78..70de0e7 100644 --- a/gvaldap/gvaldap/settings/base.py +++ b/gvaldap/gvaldap/settings/base.py @@ -286,5 +286,6 @@ BROKER_URL = get_env_setting('GVALDAP_BROKER_URL') CELERY_RESULT_BACKEND = 'amqp' CELERY_RESULT_PERSISTENT = True CELERY_TASK_RESULT_EXPIRES = None -CELERY_ACCEPT_CONTENT = ['pickle'] +CELERY_ACCEPT_CONTENT = ['yaml'] +CELERY_RESULT_SERIALIZER = 'yaml' ########## END CELERY CONFIGURATION diff --git a/requirements/base.txt b/requirements/base.txt index 3f694fb..a2c45e6 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -10,3 +10,4 @@ passlib==1.6.2 billiard==3.3.0.17 kombu==3.0.16 pytz==2014.3 +pyaml==14.05.7 From 4b9d8d02ba526e39efda1d3b646ecdde2bf3ab13 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 30 May 2014 18:42:04 +0200 Subject: [PATCH 06/18] use primitive values for task parameters - remove all code from osusers.models - add description field to ldapentities.models.LdapGroup - change tasks defined in osusers.tasks to use primitive values as parameters to avoid serialization and model synchronization --- gvaldap/ldapentities/models.py | 1 + gvaldap/osusers/models.py | 42 ----------- gvaldap/osusers/tasks.py | 124 ++++++++++++++++++++++++++++++--- 3 files changed, 114 insertions(+), 53 deletions(-) diff --git a/gvaldap/ldapentities/models.py b/gvaldap/ldapentities/models.py index f4ee071..ef1d390 100644 --- a/gvaldap/ldapentities/models.py +++ b/gvaldap/ldapentities/models.py @@ -23,6 +23,7 @@ class LdapGroup(ldapmodels.Model): # posixGroup attributes gid = IntegerField(db_column='gidNumber', unique=True) name = CharField(db_column='cn', max_length=200, primary_key=True) + description = CharField(db_column='description') members = ListField(db_column='memberUid', blank=True) def __str__(self): diff --git a/gvaldap/osusers/models.py b/gvaldap/osusers/models.py index e1c641f..e69de29 100644 --- a/gvaldap/osusers/models.py +++ b/gvaldap/osusers/models.py @@ -1,42 +0,0 @@ -from django.db import models -from django.utils.encoding import python_2_unicode_compatible -from django.utils.translation import ugettext as _ - -from model_utils.models import TimeStampedModel - - -@python_2_unicode_compatible -class Group(TimeStampedModel, models.Model): - groupname = models.CharField( - _('Group name'), max_length=16, unique=True) - gid = models.PositiveSmallIntegerField( - _('Group ID'), unique=True, primary_key=True) - descr = models.TextField(_('Description'), blank=True) - passwd = models.CharField( - _('Group password'), max_length=128, blank=True) - - class Meta: - verbose_name = _('Group') - verbose_name_plural = _('Groups') - - def __str__(self): - return '{0} ({1})'.format(self.groupname, self.gid) - - -@python_2_unicode_compatible -class User(TimeStampedModel, models.Model): - username = models.CharField( - _('User name'), max_length=64, unique=True) - uid = models.PositiveSmallIntegerField( - _('User ID'), unique=True, primary_key=True) - group = models.ForeignKey(Group, verbose_name=_('Group')) - gecos = models.CharField(_('Gecos field'), max_length=128, blank=True) - homedir = models.CharField(_('Home directory'), max_length=256) - shell = models.CharField(_('Login shell'), max_length=64) - - class Meta: - verbose_name = _('User') - verbose_name_plural = _('Users') - - def __str__(self): - return '{0} ({1})'.format(self.username, self.uid) diff --git a/gvaldap/osusers/tasks.py b/gvaldap/osusers/tasks.py index f0b6fbc..b1be4c1 100644 --- a/gvaldap/osusers/tasks.py +++ b/gvaldap/osusers/tasks.py @@ -1,28 +1,130 @@ from __future__ import absolute_import +from django.core.exceptions import ObjectDoesNotExist from celery import shared_task +from celery.utils.log import get_task_logger +from celery.exceptions import Reject from ldapentities.models import ( LdapGroup, LdapUser, ) +_logger = get_task_logger(__name__) + + @shared_task -def create_ldap_group(group): - ldapgroup = LdapGroup(gid=group.gid, name=group.groupname) +def create_ldap_group(groupname, gid, descr): + try: + ldapgroup = LdapGroup.objects.get(name=groupname) + _logger.info( + 'ldap group with dn {0} already exists'.format(ldapgroup.dn) + ) + ldapgroup.gid = gid + except LdapGroup.DoesNotExist: + ldapgroup = LdapGroup(gid=gid, name=groupname) + ldapgroup.description = descr ldapgroup.save() return ldapgroup.dn @shared_task -def create_ldap_user(user, password): - ldapuser = LdapUser( - uid=user.uid, group=user.group.gid, gecos=user.gecos, - home_directory=user.homedir, login_shell=user.shell, - username=user.username, common_name=user.username) - ldapuser.set_password(password) - ldapgroup = LdapGroup.objects.get(gid=ldapuser.group) - ldapgroup.members.append(ldapuser.username) - ldapgroup.save() +def create_ldap_user(username, uid, gid, gecos, homedir, shell, password): + try: + ldapuser = LdapUser.objects.get(username=username) + _logger.info( + 'ldap user with dn {0} already exists'.format(ldapuser.dn) + ) + except LdapUser.DoesNotExist: + ldapuser = LdapUser(username=username) + try: + ldapgroup = LdapGroup.objects.get(gid=gid) + except ObjectDoesNotExist as exc: + _logger.info('ldap group with gid {0} does not exist') + raise Reject(exc, requeue=False) + ldapuser.uid = uid + ldapuser.group = gid + ldapuser.gecos = gecos + ldapuser.home_directory = homedir + ldapuser.login_shell = shell + ldapuser.username = username + ldapuser.common_name = username + if password is not None: + ldapuser.set_password(password) + if ldapuser.username in ldapgroup.members: + _logger.info('user {0} is already member of {1}'.format( + ldapuser.username, ldapgroup.dn) + ) + else: + ldapgroup.members.append(ldapuser.username) + ldapgroup.save() ldapuser.save() return ldapuser.dn + + +@shared_task(bind=True) +def add_ldap_user_to_group(self, username, groupname): + try: + ldapgroup = LdapGroup.objects.get(name=groupname) + ldapuser = LdapUser.objects.get(username=username) + except LdapGroup.DoesNotExist: + _logger.error('ldap group {0} does not exist'.format(groupname)) + except LdapUser.DoesNotExist as exc: + _logger.error('ldap user {0} does not exist'.format(username)) + self.retry(exc=exc, time_limit=5) + else: + if not ldapuser.username in ldapgroup.members: + ldapgroup.members.append(ldapuser.username) + ldapgroup.save() + else: + _logger.info('ldap user {0} is already in group {1}'.format( + ldapuser.username, ldapgroup.dn) + ) + + +@shared_task +def remove_ldap_user_from_group(username, groupname): + ldapgroup = LdapGroup.objects.get(name=groupname) + ldapuser = LdapUser.objects.get(username=username) + if ldapuser.username in ldapgroup.members: + ldapgroup.members.remove(ldapuser.username) + ldapgroup.save() + + +@shared_task +def delete_ldap_user(username): + try: + ldapuser = LdapUser.objects.get(username=username) + except LdapUser.DoesNotExist: + _logger.info('there is no ldap user with uid {0}'.format( + username) + ) + else: + try: + ldapgroup = LdapGroup.objects.get(gid=ldapuser.group) + except LdapGroup.DoesNotExist: + _logger.info('group {0} for user {1} does not exist'.format( + ldapuser.group, ldapuser.username) + ) + else: + if ldapuser.username in ldapgroup.members: + ldapgroup.members.remove(ldapuser.username) + ldapgroup.save() + ldapuser.delete() + + +@shared_task +def delete_ldap_group_if_empty(groupname): + try: + ldapgroup = LdapGroup.objects.get(name=groupname) + except LdapGroup.DoesNotExist: + _logger.info('ldap group with name {0} does not exist'.format( + groupname) + ) + else: + if len(ldapgroup.members) == 0: + ldapgroup.delete() + else: + _logger.info('ldap group {0} still has {1} members'.format( + ldapgroup.dn, len(ldapgroup.members)) + ) From 2bce3942ead3ba66e7ef2f66b8c52e3761cad1b5 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 12:19:44 +0200 Subject: [PATCH 07/18] add releases to local requirements --- requirements/local.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/local.txt b/requirements/local.txt index 5f597de..8e4f5a9 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -4,3 +4,4 @@ coverage==3.7.1 django-debug-toolbar==1.2.1 Sphinx==1.2.2 sqlparse==0.1.11 +releases==0.6.1 From c792c9c7202fa583f2f09cdfb993cebafb9b13c3 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 13:15:32 +0200 Subject: [PATCH 08/18] ignore documentation builds --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b9ae4ff..f2aee66 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ Thumbs.db Desktop.ini .ropeproject +_build/ From 241ab005bbebfc0dee67d903ec445f486bb4dde9 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 13:16:21 +0200 Subject: [PATCH 09/18] remove recursive dependecies of celery --- requirements/base.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index a2c45e6..a00a80c 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,7 +7,4 @@ logutils==0.3.3 South==0.8.4 celery==3.1.11 passlib==1.6.2 -billiard==3.3.0.17 -kombu==3.0.16 -pytz==2014.3 pyaml==14.05.7 From f96cc5eb145addf08e605934d41b5dc425956461 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 13:18:46 +0200 Subject: [PATCH 10/18] add changelog - add docs/changelog.rst with initial feature - add and configure releases extension in docs/conf.py - add changelog to toc tree in index.rst --- docs/changelog.rst | 4 ++++ docs/conf.py | 6 +++++- docs/index.rst | 3 +-- 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 docs/changelog.rst diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 0000000..db3d09e --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1,4 @@ +Changelog +========= + +* :feature:`-` intial support for creating LDAP users and groups diff --git a/docs/conf.py b/docs/conf.py index c0cb2c1..07386c0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,11 +26,15 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] +extensions = ['releases'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +releases_issue_uri = 'https://dev.gnuviech-server.de/gvaldap/ticket/%s' + +releases_release_uri = 'https://dev.gnuviech-server.de/gvaldap/milestone/%s' + # The suffix of source filenames. source_suffix = '.rst' diff --git a/docs/index.rst b/docs/index.rst index 3267489..5716510 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,8 +13,7 @@ Contents: install deploy - tests - + changelog Indices and tables From fdcaef18685d26556b4d3d2a17626fb49ab80f7c Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 13:25:39 +0200 Subject: [PATCH 11/18] move installation documentation - move installation documentation from README.rst to docs/install.rst --- README.rst | 49 +++------------------------------- docs/index.rst | 2 ++ docs/install.rst | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 46 deletions(-) diff --git a/README.rst b/README.rst index a7fff78..97c5c6d 100644 --- a/README.rst +++ b/README.rst @@ -4,49 +4,8 @@ gvaldap This is the GNUViech Admin LDAP administration tool project. -Working Environment -=================== +GNUViech Admin is a suite of tools for server management used for hosting +customer management at `Jan Dittberner IT-Consulting & -Solutions +`_. -You have several options in setting up your working environment. We recommend -using virtualenv to separate the dependencies of your project from your -system's python environment. If on Linux or Mac OS X, you can also use -virtualenvwrapper to help manage multiple virtualenvs across different -projects. - -Virtualenv Only ---------------- - -First, make sure you are using virtualenv (http://www.virtualenv.org). Once -that's installed, create your virtualenv:: - - $ virtualenv --distribute gvaldap - -You will also need to ensure that the virtualenv has the project directory -added to the path. Adding the project directory will allow `django-admin.py` to -be able to change settings using the `--settings` flag. - -Virtualenv with virtualenvwrapper ------------------------------------- - -In Linux and Mac OSX, you can install virtualenvwrapper -(http://virtualenvwrapper.readthedocs.org/en/latest/), which will take care of -managing your virtual environments and adding the project path to the -`site-directory` for you:: - - $ mkdir gvaldap - $ mkvirtualenv -a gvaldap gvaldap-dev - $ cd gvaldap && add2virtualenv `pwd` - - -Installation of Dependencies -============================= - -Depending on where you are installing dependencies: - -In development:: - - $ pip install -r requirements/local.txt - -For production:: - - $ pip install -r requirements.txt +Read the :doc:`Installation instructions ` to get started locally. diff --git a/docs/index.rst b/docs/index.rst index 5716510..0bf07e1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,6 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. include:: ../README.rst + Welcome to gvaldap's documentation! ==================================== diff --git a/docs/install.rst b/docs/install.rst index 7ebed79..f0cb69d 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -1,4 +1,70 @@ +.. index:: installation + +======= Install ======= -This is where you write how to get a new laptop to run this project. +Working Environment +=================== + +You have several options in setting up your working environment. We recommend +using virtualenv to separate the dependencies of your project from your +system's python environment. If on Linux or Mac OS X, you can also use +virtualenvwrapper to help manage multiple virtualenvs across different +projects. + +.. index:: virtualenv + +Virtualenv Only +--------------- + +First, make sure you are using `virtualenv`_. Once that's installed, create +your virtualenv: + +.. code-block:: sh + + $ virtualenv --distribute gvaldap + +.. _virtualenv: https://virtualenv.pypa.io/en/latest/ + +You will also need to ensure that the virtualenv has the project directory +added to the path. Adding the project directory will allow `django-admin.py` to +be able to change settings using the `--settings` flag. + +.. index:: virtualenvwrapper + +Virtualenv with virtualenvwrapper +------------------------------------ + +In Linux and Mac OSX, you can install `virtualenvwrapper +`_, which will take care +of managing your virtual environments and adding the project path to the +`site-directory` for you: + +.. code-block:: sh + + $ mkdir gvaldap + $ mkvirtualenv -a gvaldap gvaldap-dev + $ cd gvaldap && add2virtualenv `pwd` + + +.. index:: pip, requirements, dependencies + +Installation of Dependencies +============================= + +Depending on where you are installing dependencies: + +In development: + +.. code-block:: sh + + $ pip install -r requirements/local.txt + +For production: + +.. code-block:: sh + + $ pip install -r requirements.txt + +.. index:: celery, worker, ldap queue From efae7ec1200f394f13b84c9b8a6ecf13eaff5a45 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 13:26:48 +0200 Subject: [PATCH 12/18] add celery startup and deployment documentation --- docs/deploy.rst | 8 +++++++- docs/install.rst | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/deploy.rst b/docs/deploy.rst index 1e642c7..9fd944b 100644 --- a/docs/deploy.rst +++ b/docs/deploy.rst @@ -1,4 +1,10 @@ Deploy ======== -This is where you describe how the project is deployed in production. +The production deployment for gvaldap is performed using saltstack and consists +of the following steps: + +* installation of native dependencies +* setup of a virtualenv +* installation of gvaldap production dependencies inside the virtualenv +* setup of celery worker under control of supervisord diff --git a/docs/install.rst b/docs/install.rst index f0cb69d..23a17ee 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -68,3 +68,17 @@ For production: $ pip install -r requirements.txt .. index:: celery, worker, ldap queue + +Running the Celery worker +========================= + +gvaldap uses the `Celery`_ distributed task queue system. The gvaldap logix is +executed by a celery worker. After all dependencies are installed you can go +into the gvaldap directory and run the celery worker with: + +.. code-block:: sh + + $ cd gvaldap + $ celery -A gvaldap worker -Q ldap -l info + +.. _Celery: http://www.celeryproject.org/ From ef47cf7862de926fa0d86ef849cc3deb379e8731 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 13:27:21 +0200 Subject: [PATCH 13/18] add code documentation stub --- docs/code.rst | 13 +++++++++++++ docs/conf.py | 7 ++++--- docs/index.rst | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 docs/code.rst diff --git a/docs/code.rst b/docs/code.rst new file mode 100644 index 0000000..f079065 --- /dev/null +++ b/docs/code.rst @@ -0,0 +1,13 @@ +================== +Code documentation +================== + +.. index:: Django + +gvaldap is implemented as a set of `Django`_ apps. + +.. _Django: https://www.djangoproject.com/ + +.. automodule:: ldapentities + +.. automodule:: osusers diff --git a/docs/conf.py b/docs/conf.py index 07386c0..1b5e738 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,12 +12,13 @@ # All configuration values have a default; values that are commented out # serve to show the default. -#import sys, os +import sys +import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join('..', 'gvaldap'))) # -- General configuration ----------------------------------------------------- @@ -26,7 +27,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['releases'] +extensions = ['releases', 'sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/index.rst b/docs/index.rst index 0bf07e1..0297002 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,6 +15,7 @@ Contents: install deploy + code changelog From 1466d3c93a71d1ba953cd9baef073f49fe35ed90 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 14:29:21 +0200 Subject: [PATCH 14/18] add docstrings for ldapentities app --- gvaldap/ldapentities/__init__.py | 7 ++++ gvaldap/ldapentities/admin.py | 17 ++++++++++ gvaldap/ldapentities/models.py | 56 ++++++++++++++++++++++++++++++-- gvaldap/ldapentities/tests.py | 3 -- 4 files changed, 78 insertions(+), 5 deletions(-) delete mode 100644 gvaldap/ldapentities/tests.py diff --git a/gvaldap/ldapentities/__init__.py b/gvaldap/ldapentities/__init__.py index e69de29..42332ea 100644 --- a/gvaldap/ldapentities/__init__.py +++ b/gvaldap/ldapentities/__init__.py @@ -0,0 +1,7 @@ +""" +This app takes care of managing LDAP entities, at the moment these are: + +* LDAP groups (:py:class:`ldapentities.models.LdapGroup`). +* LDAP users (:py:class:`ldapentities.models.LdapUser`) + +""" diff --git a/gvaldap/ldapentities/admin.py b/gvaldap/ldapentities/admin.py index 8d46d8a..97c81c5 100644 --- a/gvaldap/ldapentities/admin.py +++ b/gvaldap/ldapentities/admin.py @@ -1,3 +1,10 @@ +""" +Admin classes for easy `django admin`_ based administration of LDAP entities. + +.. _django admin: https://docs.djangoproject.com/en/dev/ref/contrib/admin/ + +""" + from django.contrib import admin from .models import ( @@ -7,12 +14,22 @@ from .models import ( class LdapGroupAdmin(admin.ModelAdmin): + """ + Admin class for :py:class:`LDAP group ` + entities. + + """ exclude = ['dn', 'members'] list_display = ['name', 'gid'] search_fields = ['name'] class LdapUserAdmin(admin.ModelAdmin): + """ + Admin class for :py:class:`LDAP user ` + entities. + + """ exclude = ['dn', 'password'] list_display = ['username', 'uid'] search_fields = ['username'] diff --git a/gvaldap/ldapentities/models.py b/gvaldap/ldapentities/models.py index ef1d390..89ee373 100644 --- a/gvaldap/ldapentities/models.py +++ b/gvaldap/ldapentities/models.py @@ -1,3 +1,12 @@ +""" +This module defines models for LDAP entities. + +The models are based on :py:class:`ldapmodels.Model` from `django-ldapdb`_. + +.. _django-ldapdb: https://github.com/jlaine/django-ldapdb#readme + +""" + from django.conf import settings from django.utils.encoding import python_2_unicode_compatible from ldapdb.models.fields import ( @@ -13,44 +22,87 @@ from passlib.hash import ldap_salted_sha1 @python_2_unicode_compatible class LdapGroup(ldapmodels.Model): """ - Class for representing an LDAP group entity. + Class for representing an LDAP group entity with objectClass `posixGroup`. + + .. seealso:: :rfc:`2307#section-4` + + .. py:attribute:: base_dn + + a string containing the LDAP base distinguished name + + .. py:attribute:: members + + contains the list of `memberUid` attributes """ # LDAP meta-data base_dn = settings.GROUP_BASE_DN + #: list of object classes object_classes = ['posixGroup'] # posixGroup attributes + #: group id (`gidNumber`) gid = IntegerField(db_column='gidNumber', unique=True) + #: group name (`cn`) name = CharField(db_column='cn', max_length=200, primary_key=True) + #: group description (`description`) description = CharField(db_column='description') members = ListField(db_column='memberUid', blank=True) def __str__(self): + """ + Get a string representation of this LDAP group. + """ return self.name @python_2_unicode_compatible class LdapUser(ldapmodels.Model): """ - Class for representing an LDAP user entity. + Class for representing an LDAP user entity with objectClasses `account` and + `posixAccount`. + + .. seealso:: :rfc:`2307#section-4`, :rfc:`4524#section-3.1` + + .. py:attribute:: base_dn + + a string containing the LDAP base distinguished name """ base_dn = settings.USER_BASE_DN + #: list of object classes object_classes = ['account', 'posixAccount'] # posixAccount + #: user id (`uidNumber`) uid = IntegerField(db_column='uidNumber', unique=True) + #: group id (`gidNumber`) of the user's primary group group = IntegerField(db_column='gidNumber') + #: GECOS field (`gecos`) gecos = CharField(db_column='gecos') + #: home directory (`homeDirectory`) home_directory = CharField(db_column='homeDirectory') + #: login shell (`loginShell`) login_shell = CharField(db_column='loginShell', default='/bin/bash') + #: user name (`uid`) username = CharField(db_column='uid', primary_key=True) + #: password (`userPassword`) in an LDAP compatible format password = CharField(db_column='userPassword') + #: common name (`cn`) common_name = CharField(db_column='cn') def __str__(self): + """ + Get a string representation of this LDAP user. + """ return self.username def set_password(self, password): + """ + Sets the encrypted password of the user from the given clear text + password. + + :param str password: the clear text password + + """ self.password = ldap_salted_sha1.encrypt(password) diff --git a/gvaldap/ldapentities/tests.py b/gvaldap/ldapentities/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/gvaldap/ldapentities/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. From 91791320cae8b83612ac7f3a7493d694feb9e9e7 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 15:18:39 +0200 Subject: [PATCH 15/18] document the celery tasks in osusers.tasks --- docs/code.rst | 29 +++++++++++++ docs/conf.py | 2 +- gvaldap/osusers/admin.py | 3 -- gvaldap/osusers/models.py | 3 ++ gvaldap/osusers/tasks.py | 91 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 123 insertions(+), 5 deletions(-) delete mode 100644 gvaldap/osusers/admin.py diff --git a/docs/code.rst b/docs/code.rst index f079065..1b90499 100644 --- a/docs/code.rst +++ b/docs/code.rst @@ -8,6 +8,35 @@ gvaldap is implemented as a set of `Django`_ apps. .. _Django: https://www.djangoproject.com/ + +:py:mod:`ldapentities` app +========================== + .. automodule:: ldapentities + +:py:mod:`ldapenties.admin` +-------------------------- + +.. automodule:: ldapentities.admin + :members: + + +:py:mod:`ldapenties.models` +--------------------------- + +.. automodule:: ldapentities.models + :members: + + +:py:mod:`osusers` app +===================== + .. automodule:: osusers + +:py:mod:`osusers.tasks` +----------------------- + +.. automodule:: osusers.tasks + :members: + :undoc-members: diff --git a/docs/conf.py b/docs/conf.py index 1b5e738..472a042 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,7 @@ sys.path.insert(0, os.path.abspath(os.path.join('..', 'gvaldap'))) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['releases', 'sphinx.ext.autodoc'] +extensions = ['releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/gvaldap/osusers/admin.py b/gvaldap/osusers/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/gvaldap/osusers/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/gvaldap/osusers/models.py b/gvaldap/osusers/models.py index e69de29..d1ff455 100644 --- a/gvaldap/osusers/models.py +++ b/gvaldap/osusers/models.py @@ -0,0 +1,3 @@ +""" +Empty models module required for Django to accept this as an app. +""" diff --git a/gvaldap/osusers/tasks.py b/gvaldap/osusers/tasks.py index b1be4c1..591d22a 100644 --- a/gvaldap/osusers/tasks.py +++ b/gvaldap/osusers/tasks.py @@ -1,9 +1,17 @@ +""" +This module defines `Celery`_ tasks to manage LDAP entities. + +.. _Celery: http://www.celeryproject.org/ + +""" + from __future__ import absolute_import from django.core.exceptions import ObjectDoesNotExist from celery import shared_task from celery.utils.log import get_task_logger from celery.exceptions import Reject + from ldapentities.models import ( LdapGroup, LdapUser, @@ -15,6 +23,19 @@ _logger = get_task_logger(__name__) @shared_task def create_ldap_group(groupname, gid, descr): + """ + This task creates an :py:class:`LDAP group ` + if it does not exist yet. + + If a group with the given name exists its group id and description + attributes are updated. + + :param str groupname: the group name + :param int gid: the group id + :param str descr: description text for the group + :return: the distinguished name of the group + :rtype: str + """ try: ldapgroup = LdapGroup.objects.get(name=groupname) _logger.info( @@ -30,6 +51,28 @@ def create_ldap_group(groupname, gid, descr): @shared_task def create_ldap_user(username, uid, gid, gecos, homedir, shell, password): + """ + This task creates an :py:class:`LDAP user ` + if it does not exist yet. + + The task is rejected if the primary group of the user is not defined. + + The user's fields are updated if the user already exists. + + :param str username: the user name + :param int uid: the user id + :param int gid: the user's primary group's id + :param str gecos: the text for the GECOS field + :param str homedir: the user's home directory + :param str shell: the user's login shell + :param str or None password: the clear text password, if :py:const:`None` + is passed the password is not touched + :raises celery.exceptions.Reject: if the specified primary group does not + exist + :return: the distinguished name of the user + :rtype: str + + """ try: ldapuser = LdapUser.objects.get(username=username) _logger.info( @@ -64,6 +107,19 @@ def create_ldap_user(username, uid, gid, gecos, homedir, shell, password): @shared_task(bind=True) def add_ldap_user_to_group(self, username, groupname): + """ + This task adds the specified user to the given group. + + This task does nothing if the user is already member of the group. + + :param str username: the user name + :param str groupname: the group name + :raises celery.exceptions.Retry: if the user does not exist yet, + :py:func:`create_ldap_user` should be called before + :return: True if the user has been added to the group otherwise False + :rtype: boolean + + """ try: ldapgroup = LdapGroup.objects.get(name=groupname) ldapuser = LdapUser.objects.get(username=username) @@ -80,19 +136,40 @@ def add_ldap_user_to_group(self, username, groupname): _logger.info('ldap user {0} is already in group {1}'.format( ldapuser.username, ldapgroup.dn) ) + return True + return False @shared_task def remove_ldap_user_from_group(username, groupname): + """ + This task removes the given user from the given group. + + :param str username: the user name + :param str groupname: the group name + :return: True if the user has been removed, False otherwise + :rtype: boolean + + """ ldapgroup = LdapGroup.objects.get(name=groupname) ldapuser = LdapUser.objects.get(username=username) - if ldapuser.username in ldapgroup.members: + performdelete = ldapuser.username in ldapgroup.members + if performdelete: ldapgroup.members.remove(ldapuser.username) ldapgroup.save() + return performdelete @shared_task def delete_ldap_user(username): + """ + This task deletes the given user. + + :param str username: the user name + :return: True if the user has been deleted, False otherwise + :rtype: boolean + + """ try: ldapuser = LdapUser.objects.get(username=username) except LdapUser.DoesNotExist: @@ -111,10 +188,20 @@ def delete_ldap_user(username): ldapgroup.members.remove(ldapuser.username) ldapgroup.save() ldapuser.delete() + return True + return False @shared_task def delete_ldap_group_if_empty(groupname): + """ + This task deletes the given group. + + :param str groupname: the group name + :return: True if the user has been deleted, False otherwise + :rtype: boolean + + """ try: ldapgroup = LdapGroup.objects.get(name=groupname) except LdapGroup.DoesNotExist: @@ -124,7 +211,9 @@ def delete_ldap_group_if_empty(groupname): else: if len(ldapgroup.members) == 0: ldapgroup.delete() + return True else: _logger.info('ldap group {0} still has {1} members'.format( ldapgroup.dn, len(ldapgroup.members)) ) + return False From d86ba33f216afb325ffe051545749fefddc6caeb Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 15:23:59 +0200 Subject: [PATCH 16/18] add module level documentation, remove emtpy tests - add docstring for module osusers - remove empty osusers.tests --- gvaldap/osusers/__init__.py | 3 +++ gvaldap/osusers/tests.py | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 gvaldap/osusers/tests.py diff --git a/gvaldap/osusers/__init__.py b/gvaldap/osusers/__init__.py index e69de29..b960717 100644 --- a/gvaldap/osusers/__init__.py +++ b/gvaldap/osusers/__init__.py @@ -0,0 +1,3 @@ +""" +This module contains :py:mod:`osusers.tasks`. +""" diff --git a/gvaldap/osusers/tests.py b/gvaldap/osusers/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/gvaldap/osusers/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. From 4f4247ea9d65f50daa32f6c1f3740641e2eadd52 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 16:12:36 +0200 Subject: [PATCH 17/18] add documentation for gvaldap project code --- docs/code.rst | 57 +++++++++++++++++++++++++- gvaldap/gvaldap/__init__.py | 3 ++ gvaldap/gvaldap/celery.py | 12 +++--- gvaldap/gvaldap/settings/__init__.py | 4 +- gvaldap/gvaldap/settings/base.py | 15 ++++++- gvaldap/gvaldap/settings/local.py | 5 ++- gvaldap/gvaldap/settings/production.py | 5 ++- gvaldap/gvaldap/settings/test.py | 4 ++ gvaldap/gvaldap/urls.py | 5 +++ gvaldap/gvaldap/wsgi.py | 2 +- 10 files changed, 100 insertions(+), 12 deletions(-) diff --git a/docs/code.rst b/docs/code.rst index 1b90499..9001a7b 100644 --- a/docs/code.rst +++ b/docs/code.rst @@ -4,9 +4,64 @@ Code documentation .. index:: Django -gvaldap is implemented as a set of `Django`_ apps. +gvaldap is implemented as `Django`_ project and provides some `Celery`_ tasks. .. _Django: https://www.djangoproject.com/ +.. _Celery: http://www.celeryproject.org/ + + +The project module :py:mod:`gvaldap` +==================================== + +.. automodule:: gvaldap + + +:py:mod:`gvaldap.celery` +------------------------ + +.. automodule:: gvaldap.celery + :members: + + +:py:mod:`gvaldap.urls` +---------------------- + +.. automodule:: gvaldap.urls + + +:py:mod:`gvaldap.wsgi` +---------------------- + +.. automodule:: gvaldap.wsgi + :members: + + +:py:mod:`gvaldap.settings` +-------------------------- + +.. automodule:: gvaldap.settings + +:py:mod:`gvaldap.settings.base` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: gvaldap.settings.base + :members: + +:py:mod:`gvaldap.settings.local` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: gvaldap.settings.local + +:py:mod:`gvaldap.settings.production` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: gvaldap.settings.production + +:py:mod:`gvaldap.settings.test` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: gvaldap.settings.test + :py:mod:`ldapentities` app diff --git a/gvaldap/gvaldap/__init__.py b/gvaldap/gvaldap/__init__.py index e69de29..62a61ef 100644 --- a/gvaldap/gvaldap/__init__.py +++ b/gvaldap/gvaldap/__init__.py @@ -0,0 +1,3 @@ +""" +This is the gvaldap project module. +""" diff --git a/gvaldap/gvaldap/celery.py b/gvaldap/gvaldap/celery.py index fd9a616..e9a2f75 100644 --- a/gvaldap/gvaldap/celery.py +++ b/gvaldap/gvaldap/celery.py @@ -1,3 +1,9 @@ +""" +This module defines the Celery_ app for gvaldap. + +.. _Celery: http://www.celeryproject.org/ + +""" from __future__ import absolute_import import os @@ -10,12 +16,8 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gvaldap.settings.production') +#: The Celery application app = Celery('gvaldap') app.config_from_object('django.conf:settings') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) - - -@app.task(bind=True) -def debug_task(self): - print('Request: {0!r}'.format(self.request)) diff --git a/gvaldap/gvaldap/settings/__init__.py b/gvaldap/gvaldap/settings/__init__.py index 8b13789..4f53a5e 100644 --- a/gvaldap/gvaldap/settings/__init__.py +++ b/gvaldap/gvaldap/settings/__init__.py @@ -1 +1,3 @@ - +""" +This module contains settings for various environments. +""" diff --git a/gvaldap/gvaldap/settings/base.py b/gvaldap/gvaldap/settings/base.py index 70de0e7..46c8740 100644 --- a/gvaldap/gvaldap/settings/base.py +++ b/gvaldap/gvaldap/settings/base.py @@ -1,5 +1,9 @@ -"""Common settings and globals.""" +# -*- coding: utf-8 -*- # pymode:lint_ignore=E501 +""" +Common settings and globals. + +""" from os.path import abspath, basename, dirname, join, normpath @@ -12,7 +16,14 @@ from django.core.exceptions import ImproperlyConfigured def get_env_setting(setting): - """ Get the environment setting or return exception """ + """ + Get the environment setting or return exception. + + :param str setting: name of an environment setting + :raises ImproperlyConfigured: if the environment setting is not defined + :return: environment setting value + :rtype: str + """ try: return environ[setting] except KeyError: diff --git a/gvaldap/gvaldap/settings/local.py b/gvaldap/gvaldap/settings/local.py index 3329842..8a8d441 100644 --- a/gvaldap/gvaldap/settings/local.py +++ b/gvaldap/gvaldap/settings/local.py @@ -1,5 +1,8 @@ -"""Development settings and globals.""" # pymode:lint_ignore=W0401,E501 +""" +Development settings and globals based on :py:mod:`gvaldap.settings.base`. + +""" from __future__ import absolute_import diff --git a/gvaldap/gvaldap/settings/production.py b/gvaldap/gvaldap/settings/production.py index 7c9b280..288e1db 100644 --- a/gvaldap/gvaldap/settings/production.py +++ b/gvaldap/gvaldap/settings/production.py @@ -1,5 +1,8 @@ -"""Production settings and globals.""" # pymode:lint_ignore=W0401,E501 +""" +Production settings and globals based on :py:mod:`gvaldap.settings.base`. + +""" from __future__ import absolute_import diff --git a/gvaldap/gvaldap/settings/test.py b/gvaldap/gvaldap/settings/test.py index e510233..c39ee49 100644 --- a/gvaldap/gvaldap/settings/test.py +++ b/gvaldap/gvaldap/settings/test.py @@ -1,4 +1,8 @@ # pymode:lint_ignore=W0401 +""" +Test settings based on :py:mod:`gvaldap.settings.base`. + +""" from __future__ import absolute_import from .base import * diff --git a/gvaldap/gvaldap/urls.py b/gvaldap/gvaldap/urls.py index 120582d..37d1d10 100644 --- a/gvaldap/gvaldap/urls.py +++ b/gvaldap/gvaldap/urls.py @@ -1,3 +1,8 @@ +""" +This module defines the main URLConf for gvaldap. + +""" + from django.conf.urls import patterns, include, url from django.conf import settings diff --git a/gvaldap/gvaldap/wsgi.py b/gvaldap/gvaldap/wsgi.py index 29b3554..af02caa 100644 --- a/gvaldap/gvaldap/wsgi.py +++ b/gvaldap/gvaldap/wsgi.py @@ -26,10 +26,10 @@ path.append(SITE_ROOT) # os.environ["DJANGO_SETTINGS_MODULE"] = "jajaja.settings" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings.production") +from django.core.wsgi import get_wsgi_application # This application object is used by any WSGI server configured to use this # file. This includes Django's development server, if the WSGI_APPLICATION # setting points here. -from django.core.wsgi import get_wsgi_application application = get_wsgi_application() # Apply WSGI middleware here. From 837e58af07a5e3e59876f4fbd340c4d8f720fd08 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 31 May 2014 16:19:30 +0200 Subject: [PATCH 18/18] add release 0.1 to changelog --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index db3d09e..2c8c813 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,4 +1,5 @@ Changelog ========= +* :release:`0.1 <2014-05-31>` * :feature:`-` intial support for creating LDAP users and groups