Merge branch 'release/0.6.0' into production
* release/0.6.0: (29 commits) Release preparation for 0.6.0 Fix missing bind=True Implement automatic retry for LDAP errors Unify docker setup with gvaweb and gva Add Dockerfile and entrypoint script Reorganize package structure Fix compatibility with Django 2.2 and other dependencies Use Pipenv for dependency management Change gvacommon dependency URL Update vagrant setup to stretch64 with LXC Protect /etc/salt/grains Ignore PyCharm files Improve Vagrant setup Refactoring of ldaptasks Mark LDAP field names as byte strings Change salt minion id in Vagrantfile Add tests for delete tasks Add tests for ldaptasks functions Update Django and gvacommon dependencies Add unit tests
This commit is contained in:
commit
99e22ab9dd
44 changed files with 1585 additions and 698 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -40,3 +40,8 @@ Desktop.ini
|
||||||
|
|
||||||
.ropeproject
|
.ropeproject
|
||||||
_build/
|
_build/
|
||||||
|
.vagrant/
|
||||||
|
.coverage
|
||||||
|
coverage-report/
|
||||||
|
.idea/
|
||||||
|
.env
|
52
Dockerfile
Normal file
52
Dockerfile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
ARG DEBIAN_RELEASE=buster
|
||||||
|
FROM debian:$DEBIAN_RELEASE
|
||||||
|
LABEL maintainer="Jan Dittberner <jan@dittberner.info>"
|
||||||
|
|
||||||
|
ENV LC_ALL=C.UTF-8
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
dumb-init \
|
||||||
|
gettext \
|
||||||
|
git \
|
||||||
|
python3-dev \
|
||||||
|
python3-pip \
|
||||||
|
python3-setuptools \
|
||||||
|
python3-virtualenv \
|
||||||
|
python3-wheel \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*.*
|
||||||
|
|
||||||
|
RUN python3 -m pip install --prefix=/usr/local pipenv
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
libldap2-dev \
|
||||||
|
libsasl2-dev \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*.*
|
||||||
|
|
||||||
|
ARG GVAGID=2000
|
||||||
|
ARG GVAUID=2000
|
||||||
|
|
||||||
|
ARG GVAAPP=gvaldap
|
||||||
|
|
||||||
|
WORKDIR /srv/$GVAAPP
|
||||||
|
|
||||||
|
COPY Pipfile Pipfile.lock /srv/$GVAAPP/
|
||||||
|
|
||||||
|
RUN addgroup --gid $GVAGID $GVAAPP ; \
|
||||||
|
adduser --home /home/$GVAAPP --shell /bin/bash --uid $GVAUID --gid $GVAGID --disabled-password --gecos "User for gnuviechadmin component $GVAAPP" $GVAAPP
|
||||||
|
|
||||||
|
USER $GVAAPP
|
||||||
|
RUN python3 -m virtualenv --python=python3 /home/$GVAAPP/$GVAAPP-venv ; \
|
||||||
|
/home/$GVAAPP/$GVAAPP-venv/bin/python3 -m pip install -U pip ; \
|
||||||
|
VIRTUAL_ENV=/home/$GVAAPP/$GVAAPP-venv pipenv install --deploy --ignore-pipfile --dev
|
||||||
|
|
||||||
|
VOLUME /srv/$GVAAPP
|
||||||
|
|
||||||
|
COPY gvaldap.sh /srv/
|
||||||
|
|
||||||
|
ENTRYPOINT ["dumb-init", "/srv/gvaldap.sh"]
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2014, 2015 Jan Dittberner
|
Copyright (c) 2014-2020 Jan Dittberner
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person
|
||||||
obtaining a copy of this software and associated documentation
|
obtaining a copy of this software and associated documentation
|
||||||
|
|
33
Pipfile
Normal file
33
Pipfile
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[[source]]
|
||||||
|
url = "https://$PYPI_GNUVIECH_USERNAME:${PYPI_GNUVIECH_PASSWORD}@pypi.gnuviech-server.de/simple"
|
||||||
|
name = "gnuviech"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
Sphinx = "*"
|
||||||
|
coverage = "*"
|
||||||
|
django-debug-toolbar = "*"
|
||||||
|
releases = "==1.0.0"
|
||||||
|
volatildap = "*"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
gvacommon = {version = "*",index = "gnuviech"}
|
||||||
|
Django = "<3"
|
||||||
|
amqp = "*"
|
||||||
|
celery = "*"
|
||||||
|
django-braces = "*"
|
||||||
|
django-ldapdb = "*"
|
||||||
|
django-model-utils = "*"
|
||||||
|
kombu = "*"
|
||||||
|
passlib = "*"
|
||||||
|
python-ldap = "*"
|
||||||
|
pytz = "*"
|
||||||
|
redis = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.7"
|
462
Pipfile.lock
generated
Normal file
462
Pipfile.lock
generated
Normal file
|
@ -0,0 +1,462 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "447a8091237b0e5a54b560066ec2329cce2fc5d564bbc2b37e2f9ec0c1af8ea2"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.7"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gnuviech",
|
||||||
|
"url": "https://$PYPI_GNUVIECH_USERNAME:${PYPI_GNUVIECH_PASSWORD}@pypi.gnuviech-server.de/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"amqp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6e649ca13a7df3faacdc8bbb280aa9a6602d22fd9d545336077e573a1f4ff3b8",
|
||||||
|
"sha256:77f1aef9410698d20eaeac5b73a87817365f457a507d82edf292e12cbb83b08d"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.5.2"
|
||||||
|
},
|
||||||
|
"billiard": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:bff575450859a6e0fbc2f9877d9b715b0bbc07c3565bb7ed2280526a0cdf5ede",
|
||||||
|
"sha256:d91725ce6425f33a97dfa72fb6bfef0e47d4652acd98a032bd1a7fbf06d5fa6a"
|
||||||
|
],
|
||||||
|
"version": "==3.6.3.0"
|
||||||
|
},
|
||||||
|
"celery": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3c5fcd6bfcf9a6323cb742cfc121d1790d50cfeddf300ba723cfa0b356413f07",
|
||||||
|
"sha256:a650525303ee866fb0c62c82f68681fcc2183eebbfafae552c27d30125fe518b"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.4.1"
|
||||||
|
},
|
||||||
|
"django": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a",
|
||||||
|
"sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.2.10"
|
||||||
|
},
|
||||||
|
"django-braces": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:83705b78948de00804bfacf40c315d001bb39630f35bbdd8588211c2d5b4d43f",
|
||||||
|
"sha256:a6d9b34cf3e4949635e54884097c30410d7964fc7bec7231445ea7079b8c5722"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.14.0"
|
||||||
|
},
|
||||||
|
"django-ldapdb": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:36990757f26c1bd7642bbb0ed88cc1a4d8fe945dfcae6094142b9889b976e3f8",
|
||||||
|
"sha256:6c2d3b645fab20f97f1d33d8924114b85f699fca1bdf2cdd251074fa0331d75e"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.4.0"
|
||||||
|
},
|
||||||
|
"django-model-utils": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:9cf882e5b604421b62dbe57ad2b18464dc9c8f963fc3f9831badccae66c1139c",
|
||||||
|
"sha256:adf09e5be15122a7f4e372cb5a6dd512bbf8d78a23a90770ad0983ee9d909061"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.0.0"
|
||||||
|
},
|
||||||
|
"gvacommon": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:adf1ebc824433196d112764c61d9ca869481d33f612818c2840069f57ab42c25"
|
||||||
|
],
|
||||||
|
"index": "gnuviech",
|
||||||
|
"version": "==0.5.0"
|
||||||
|
},
|
||||||
|
"importlib-metadata": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302",
|
||||||
|
"sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"
|
||||||
|
],
|
||||||
|
"markers": "python_version < '3.8'",
|
||||||
|
"version": "==1.5.0"
|
||||||
|
},
|
||||||
|
"kombu": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2d1cda774126a044d91a7ff5fa6d09edf99f46924ab332a810760fe6740e9b76",
|
||||||
|
"sha256:598e7e749d6ab54f646b74b2d2df67755dee13894f73ab02a2a9feb8870c7cb2"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.6.8"
|
||||||
|
},
|
||||||
|
"passlib": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:68c35c98a7968850e17f1b6892720764cc7eed0ef2b7cb3116a89a28e43fe177",
|
||||||
|
"sha256:8d666cef936198bc2ab47ee9b0410c94adf2ba798e5a84bf220be079ae7ab6a8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.7.2"
|
||||||
|
},
|
||||||
|
"pyasn1": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d",
|
||||||
|
"sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"
|
||||||
|
],
|
||||||
|
"version": "==0.4.8"
|
||||||
|
},
|
||||||
|
"pyasn1-modules": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e",
|
||||||
|
"sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"
|
||||||
|
],
|
||||||
|
"version": "==0.2.8"
|
||||||
|
},
|
||||||
|
"python-ldap": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7d1c4b15375a533564aad3d3deade789221e450052b21ebb9720fb822eccdb8e"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.2.0"
|
||||||
|
},
|
||||||
|
"pytz": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
|
||||||
|
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2019.3"
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0dcfb335921b88a850d461dc255ff4708294943322bd55de6cfd68972490ca1f",
|
||||||
|
"sha256:b205cffd05ebfd0a468db74f0eedbff8df1a7bfc47521516ade4692991bb0833"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.4.1"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
|
||||||
|
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
|
||||||
|
],
|
||||||
|
"version": "==1.14.0"
|
||||||
|
},
|
||||||
|
"sqlparse": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e",
|
||||||
|
"sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"
|
||||||
|
],
|
||||||
|
"version": "==0.3.1"
|
||||||
|
},
|
||||||
|
"vine": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87",
|
||||||
|
"sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"
|
||||||
|
],
|
||||||
|
"version": "==1.3.0"
|
||||||
|
},
|
||||||
|
"zipp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:12248a63bbdf7548f89cb4c7cda4681e537031eda29c02ea29674bc6854460c2",
|
||||||
|
"sha256:7c0f8e91abc0dc07a5068f315c52cb30c66bfbc581e5b50704c8a2f6ebae794a"
|
||||||
|
],
|
||||||
|
"version": "==3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"alabaster": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
|
||||||
|
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
|
||||||
|
],
|
||||||
|
"version": "==0.7.12"
|
||||||
|
},
|
||||||
|
"asgiref": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0",
|
||||||
|
"sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5"
|
||||||
|
],
|
||||||
|
"version": "==3.2.3"
|
||||||
|
},
|
||||||
|
"babel": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38",
|
||||||
|
"sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"
|
||||||
|
],
|
||||||
|
"version": "==2.8.0"
|
||||||
|
},
|
||||||
|
"certifi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
|
||||||
|
"sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
|
||||||
|
],
|
||||||
|
"version": "==2019.11.28"
|
||||||
|
},
|
||||||
|
"chardet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||||
|
],
|
||||||
|
"version": "==3.0.4"
|
||||||
|
},
|
||||||
|
"coverage": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3",
|
||||||
|
"sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c",
|
||||||
|
"sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0",
|
||||||
|
"sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477",
|
||||||
|
"sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a",
|
||||||
|
"sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf",
|
||||||
|
"sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691",
|
||||||
|
"sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73",
|
||||||
|
"sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987",
|
||||||
|
"sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894",
|
||||||
|
"sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e",
|
||||||
|
"sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef",
|
||||||
|
"sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf",
|
||||||
|
"sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68",
|
||||||
|
"sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8",
|
||||||
|
"sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954",
|
||||||
|
"sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2",
|
||||||
|
"sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40",
|
||||||
|
"sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc",
|
||||||
|
"sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc",
|
||||||
|
"sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e",
|
||||||
|
"sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d",
|
||||||
|
"sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f",
|
||||||
|
"sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc",
|
||||||
|
"sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301",
|
||||||
|
"sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea",
|
||||||
|
"sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb",
|
||||||
|
"sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af",
|
||||||
|
"sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52",
|
||||||
|
"sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37",
|
||||||
|
"sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==5.0.3"
|
||||||
|
},
|
||||||
|
"django": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a",
|
||||||
|
"sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.2.10"
|
||||||
|
},
|
||||||
|
"django-debug-toolbar": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:eabbefe89881bbe4ca7c980ff102e3c35c8e8ad6eb725041f538988f2f39a943",
|
||||||
|
"sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.2"
|
||||||
|
},
|
||||||
|
"docutils": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af",
|
||||||
|
"sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"
|
||||||
|
],
|
||||||
|
"version": "==0.16"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
|
||||||
|
"sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
|
||||||
|
],
|
||||||
|
"version": "==2.9"
|
||||||
|
},
|
||||||
|
"imagesize": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1",
|
||||||
|
"sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"
|
||||||
|
],
|
||||||
|
"version": "==1.2.0"
|
||||||
|
},
|
||||||
|
"jinja2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250",
|
||||||
|
"sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"
|
||||||
|
],
|
||||||
|
"version": "==2.11.1"
|
||||||
|
},
|
||||||
|
"markupsafe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||||
|
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||||
|
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||||
|
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||||
|
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||||
|
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||||
|
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||||
|
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||||
|
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||||
|
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||||
|
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||||
|
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||||
|
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||||
|
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||||
|
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||||
|
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||||
|
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||||
|
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||||
|
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||||
|
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||||
|
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||||
|
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||||
|
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||||
|
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||||
|
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||||
|
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||||
|
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||||
|
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||||
|
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||||
|
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||||
|
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||||
|
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||||
|
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
|
||||||
|
],
|
||||||
|
"version": "==1.1.1"
|
||||||
|
},
|
||||||
|
"packaging": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73",
|
||||||
|
"sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"
|
||||||
|
],
|
||||||
|
"version": "==20.1"
|
||||||
|
},
|
||||||
|
"pygments": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b",
|
||||||
|
"sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"
|
||||||
|
],
|
||||||
|
"version": "==2.5.2"
|
||||||
|
},
|
||||||
|
"pyparsing": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f",
|
||||||
|
"sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"
|
||||||
|
],
|
||||||
|
"version": "==2.4.6"
|
||||||
|
},
|
||||||
|
"pytz": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
|
||||||
|
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2019.3"
|
||||||
|
},
|
||||||
|
"releases": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:23792ba473dca124e1b60f3bb6428d775b84b05ee73c0bfd1ba8439b833c5749",
|
||||||
|
"sha256:a9e65295578bf2e352ccc86d33c12b6b7ba27e3da1342d2ffee7f3f7d602a604"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.0"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee",
|
||||||
|
"sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"
|
||||||
|
],
|
||||||
|
"version": "==2.23.0"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
|
||||||
|
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
|
||||||
|
],
|
||||||
|
"version": "==1.14.0"
|
||||||
|
},
|
||||||
|
"snowballstemmer": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
|
||||||
|
"sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
|
||||||
|
],
|
||||||
|
"version": "==2.0.0"
|
||||||
|
},
|
||||||
|
"sphinx": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:776ff8333181138fae52df65be733127539623bb46cc692e7fa0fcfc80d7aa88",
|
||||||
|
"sha256:ca762da97c3b5107cbf0ab9e11d3ec7ab8d3c31377266fd613b962ed971df709"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.4.3"
|
||||||
|
},
|
||||||
|
"sphinxcontrib-applehelp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
|
||||||
|
"sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"
|
||||||
|
],
|
||||||
|
"version": "==1.0.2"
|
||||||
|
},
|
||||||
|
"sphinxcontrib-devhelp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e",
|
||||||
|
"sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"
|
||||||
|
],
|
||||||
|
"version": "==1.0.2"
|
||||||
|
},
|
||||||
|
"sphinxcontrib-htmlhelp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f",
|
||||||
|
"sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"
|
||||||
|
],
|
||||||
|
"version": "==1.0.3"
|
||||||
|
},
|
||||||
|
"sphinxcontrib-jsmath": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178",
|
||||||
|
"sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"
|
||||||
|
],
|
||||||
|
"version": "==1.0.1"
|
||||||
|
},
|
||||||
|
"sphinxcontrib-qthelp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72",
|
||||||
|
"sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"
|
||||||
|
],
|
||||||
|
"version": "==1.0.3"
|
||||||
|
},
|
||||||
|
"sphinxcontrib-serializinghtml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc",
|
||||||
|
"sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"
|
||||||
|
],
|
||||||
|
"version": "==1.1.4"
|
||||||
|
},
|
||||||
|
"sqlparse": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e",
|
||||||
|
"sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"
|
||||||
|
],
|
||||||
|
"version": "==0.3.1"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
|
||||||
|
"sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
|
||||||
|
],
|
||||||
|
"version": "==1.25.8"
|
||||||
|
},
|
||||||
|
"volatildap": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7ef4cac02c4f907b87d5e3f5e872287a874d0c0d0a7c1054a8caae8e9c17b367",
|
||||||
|
"sha256:d9ef3ee7fcdf8d3ae1dd243e0a8c3892e404e4552caa60153fa0de97287bcfc6"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,4 +10,4 @@ customer management at `Jan Dittberner IT-Consulting & -Solutions
|
||||||
|
|
||||||
Read the :doc:`Installation instructions <install>` to get started locally.
|
Read the :doc:`Installation instructions <install>` to get started locally.
|
||||||
|
|
||||||
The project page for gvaldap is at http://dev.gnuviech-server.de/gvaldap.
|
The project page for gvaldap is at http://git.dittberner.info/gnuviech/gvaldap.
|
||||||
|
|
24
Vagrantfile
vendored
Normal file
24
Vagrantfile
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# vi: set ft=ruby :
|
||||||
|
|
||||||
|
Vagrant.configure(2) do |config|
|
||||||
|
config.vm.box = "debian/stretch64"
|
||||||
|
|
||||||
|
config.vm.hostname = "gvaldap.local"
|
||||||
|
config.vm.network "private_network", ip: "172.16.3.3", lxc__bridge_name: 'vlxcbr1'
|
||||||
|
|
||||||
|
config.vm.network "forwarded_port", guest: 8000, host: 8001
|
||||||
|
|
||||||
|
config.vm.synced_folder "../gvasalt/states/", "/srv/salt/"
|
||||||
|
config.vm.synced_folder "../gvasalt/pillar/", "/srv/pillar/"
|
||||||
|
|
||||||
|
config.vm.provision :salt do |salt|
|
||||||
|
salt.bootstrap_script = "salt/bootstrap.sh"
|
||||||
|
salt.minion_id = "gvaldap"
|
||||||
|
salt.masterless = true
|
||||||
|
salt.run_highstate = true
|
||||||
|
salt.verbose = true
|
||||||
|
salt.colorize = true
|
||||||
|
salt.log_level = "warning"
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,12 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
* :release:`0.6.0 <2020-03-03>`
|
||||||
|
* :support:`-` add Python 3 support
|
||||||
|
* :support:`-` upgrade to Django 2.2.10
|
||||||
|
* :support:`-` use Pipenv for dependency management
|
||||||
|
* :feature:`-` properly handle unavailable LDAP server
|
||||||
|
|
||||||
* :release:`0.5.2 <2015-01-29>`
|
* :release:`0.5.2 <2015-01-29>`
|
||||||
* :bug:`-` fix minor log message issue
|
* :bug:`-` fix minor log message issue
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,6 @@ The project module :py:mod:`gvaldap`
|
||||||
.. automodule:: gvaldap
|
.. automodule:: gvaldap
|
||||||
|
|
||||||
|
|
||||||
:py:mod:`celery <gvaldap.celery>`
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. automodule:: gvaldap.celery
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
:py:mod:`urls <gvaldap.urls>`
|
:py:mod:`urls <gvaldap.urls>`
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
@ -41,27 +34,6 @@ The project module :py:mod:`gvaldap`
|
||||||
|
|
||||||
.. automodule:: gvaldap.settings
|
.. automodule:: gvaldap.settings
|
||||||
|
|
||||||
:py:mod:`base <gvaldap.settings.base>`
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. automodule:: gvaldap.settings.base
|
|
||||||
:members:
|
|
||||||
|
|
||||||
:py:mod:`local <gvaldap.settings.local>`
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. automodule:: gvaldap.settings.local
|
|
||||||
|
|
||||||
:py:mod:`production <gvaldap.settings.production>`
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. automodule:: gvaldap.settings.production
|
|
||||||
|
|
||||||
:py:mod:`test <gvaldap.settings.test>`
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. automodule:: gvaldap.settings.test
|
|
||||||
|
|
||||||
|
|
||||||
:py:mod:`ldapentities` app
|
:py:mod:`ldapentities` app
|
||||||
==========================
|
==========================
|
||||||
|
@ -89,6 +61,13 @@ The project module :py:mod:`gvaldap`
|
||||||
.. automodule:: ldaptasks
|
.. automodule:: ldaptasks
|
||||||
|
|
||||||
|
|
||||||
|
:py:mod:`celery <ldaptasks.celery>`
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ldaptasks.celery
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
:py:mod:`tasks <ldaptasks.tasks>`
|
:py:mod:`tasks <ldaptasks.tasks>`
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
|
|
20
docs/conf.py
20
docs/conf.py
|
@ -21,6 +21,7 @@ import django
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join('..', 'gvaldap')))
|
sys.path.insert(0, os.path.abspath(os.path.join('..', 'gvaldap')))
|
||||||
|
|
||||||
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'gvaldap.settings'
|
||||||
os.environ['GVALDAP_ALLOWED_HOSTS'] = 'localhost'
|
os.environ['GVALDAP_ALLOWED_HOSTS'] = 'localhost'
|
||||||
os.environ['GVALDAP_SERVER_EMAIL'] = 'root@localhost'
|
os.environ['GVALDAP_SERVER_EMAIL'] = 'root@localhost'
|
||||||
|
|
||||||
|
@ -35,13 +36,13 @@ django.setup()
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx']
|
extensions = ['releases', 'sphinx.ext.autodoc', 'celery.contrib.sphinx']
|
||||||
|
|
||||||
|
# configuration for releases extension
|
||||||
|
releases_issue_uri = 'https://dev.gnuviech-server.de/gvaldap/ticket/%s'
|
||||||
|
releases_release_uri = 'https://dev.gnuviech-server.de/gvaldap/browser/?rev=%s'
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
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.
|
# The suffix of source filenames.
|
||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
@ -53,16 +54,17 @@ master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'gvaldap'
|
project = u'gvaldap'
|
||||||
copyright = u'2014, 2015 Jan Dittberner'
|
copyright = u'2014-2020 Jan Dittberner'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
|
||||||
version = '0.5'
|
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.5.2'
|
from gvaldap import __version__ as release
|
||||||
|
|
||||||
|
# The short X.Y version.
|
||||||
|
version = ".".join(release.split('.')[:2])
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -103,7 +105,7 @@ pygments_style = 'sphinx'
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'default'
|
html_theme = 'alabaster'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
|
|
@ -7,4 +7,4 @@ of the following steps:
|
||||||
* installation of native dependencies
|
* installation of native dependencies
|
||||||
* setup of a virtualenv
|
* setup of a virtualenv
|
||||||
* installation of gvaldap production dependencies inside the virtualenv
|
* installation of gvaldap production dependencies inside the virtualenv
|
||||||
* setup of celery worker under control of supervisord
|
* setup of celery worker under control of systemd
|
||||||
|
|
|
@ -7,65 +7,17 @@ Install
|
||||||
Working Environment
|
Working Environment
|
||||||
===================
|
===================
|
||||||
|
|
||||||
You have several options in setting up your working environment. We recommend
|
To get a running work environment use `pipenv`_.
|
||||||
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
|
.. _pipenv: https://pipenv.kennethreitz.org/en/latest/
|
||||||
|
|
||||||
Virtualenv Only
|
To get started install `pip` and `pipenv` and use `pipenv install --dev`:
|
||||||
---------------
|
|
||||||
|
|
||||||
First, make sure you are using `virtualenv`_. Once that's installed, create
|
|
||||||
your virtualenv:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
$ virtualenv --distribute gvaldap
|
$ apt install python3-pip
|
||||||
|
$ python3 -m pip install --user -U pipenv
|
||||||
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
|
$ pipenv install --dev
|
||||||
|
|
||||||
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
|
|
||||||
<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:
|
|
||||||
|
|
||||||
.. 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
|
.. index:: celery, worker, ldap queue
|
||||||
|
|
||||||
|
@ -79,6 +31,6 @@ into the gvaldap directory and run the celery worker with:
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
$ cd gvaldap
|
$ cd gvaldap
|
||||||
$ celery -A gvaldap worker -Q ldap -l info
|
$ pipenv run celery -A ldaptasks worker -Q web -l info
|
||||||
|
|
||||||
.. _Celery: http://www.celeryproject.org/
|
.. _Celery: http://www.celeryproject.org/
|
||||||
|
|
7
gvaldap.sh
Executable file
7
gvaldap.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
. /home/gvaldap/gvaldap-venv/bin/activate
|
||||||
|
cd /srv/gvaldap/gvaldap
|
||||||
|
celery -A ldaptasks worker -Q ldap -l info
|
3
gvaldap/gvacommon/.gitignore
vendored
3
gvaldap/gvacommon/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
||||||
.*.swp
|
|
||||||
*.pyc
|
|
||||||
.ropeproject/
|
|
|
@ -1,15 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
|
|
||||||
class GvaRouter(object):
|
|
||||||
|
|
||||||
def route_for_task(self, task, args=None, kwargs=None):
|
|
||||||
for route in ['ldap', 'file', 'mysql', 'pgsql']:
|
|
||||||
if route in task:
|
|
||||||
return {
|
|
||||||
'exchange': route,
|
|
||||||
'exchange_type': 'direct',
|
|
||||||
'queue': route,
|
|
||||||
}
|
|
||||||
return None
|
|
|
@ -1,3 +1,8 @@
|
||||||
"""
|
"""
|
||||||
This is the gvaldap project module.
|
This is the gvaldap project module.
|
||||||
"""
|
"""
|
||||||
|
__version__ = "0.6.0"
|
||||||
|
|
||||||
|
from ldaptasks.celery import app as celery_app
|
||||||
|
|
||||||
|
__all__ = ("celery_app",)
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
"""
|
|
||||||
This module defines the Celery_ app for gvaldap.
|
|
||||||
|
|
||||||
.. _Celery: http://www.celeryproject.org/
|
|
||||||
|
|
||||||
"""
|
|
||||||
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')
|
|
||||||
|
|
||||||
|
|
||||||
#: The Celery application
|
|
||||||
app = Celery('gvaldap')
|
|
||||||
|
|
||||||
app.config_from_object('django.conf:settings')
|
|
||||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
|
315
gvaldap/gvaldap/settings.py
Normal file
315
gvaldap/gvaldap/settings.py
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# pymode:lint_ignore=E501
|
||||||
|
"""
|
||||||
|
Common settings and globals.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from os.path import abspath, basename, dirname, join, normpath
|
||||||
|
from sys import path
|
||||||
|
|
||||||
|
from gvacommon.settings_utils import get_env_variable
|
||||||
|
|
||||||
|
# ######### PATH CONFIGURATION
|
||||||
|
# Absolute filesystem path to the Django project directory:
|
||||||
|
DJANGO_ROOT = dirname(dirname(abspath(__file__)))
|
||||||
|
|
||||||
|
# Absolute filesystem path to the top-level project folder:
|
||||||
|
SITE_ROOT = dirname(DJANGO_ROOT)
|
||||||
|
|
||||||
|
# Site name:
|
||||||
|
SITE_NAME = basename(DJANGO_ROOT)
|
||||||
|
|
||||||
|
# Add our project to our pythonpath, this way we don't need to type our project
|
||||||
|
# name in our dotted import paths:
|
||||||
|
path.append(DJANGO_ROOT)
|
||||||
|
# ######### END PATH CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### DEBUG CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
||||||
|
DEBUG = get_env_variable("GVALDAP_DEBUG", bool, False)
|
||||||
|
|
||||||
|
# ######### MANAGER CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
|
||||||
|
ADMINS = (
|
||||||
|
(get_env_variable("GVALDAP_ADMIN_NAME"), get_env_variable("GVALDAP_ADMIN_EMAIL")),
|
||||||
|
)
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#managers
|
||||||
|
MANAGERS = ADMINS
|
||||||
|
# ######### END MANAGER CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### DATABASE CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
|
"NAME": normpath(join(DJANGO_ROOT, "default.db")),
|
||||||
|
"USER": "",
|
||||||
|
"PASSWORD": "",
|
||||||
|
"HOST": "",
|
||||||
|
"PORT": "",
|
||||||
|
},
|
||||||
|
"ldap": {
|
||||||
|
"ENGINE": "ldapdb.backends.ldap",
|
||||||
|
"NAME": get_env_variable("GVALDAP_LDAP_URL"),
|
||||||
|
"USER": get_env_variable("GVALDAP_LDAP_USER"),
|
||||||
|
"PASSWORD": get_env_variable("GVALDAP_LDAP_PASSWORD"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
DATABASE_ROUTERS = ["ldapdb.router.Router"]
|
||||||
|
# ######### END DATABASE CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### GENERAL CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#time-zone
|
||||||
|
TIME_ZONE = "Europe/Berlin"
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
|
||||||
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
||||||
|
SITE_ID = 1
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
|
||||||
|
USE_TZ = True
|
||||||
|
# ######### END GENERAL CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### MEDIA CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
|
||||||
|
MEDIA_ROOT = normpath(join(SITE_ROOT, "media"))
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
|
||||||
|
MEDIA_URL = "/media/"
|
||||||
|
# ######### END MEDIA CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### STATIC FILE CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
|
# See:
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders # noqa
|
||||||
|
STATICFILES_FINDERS = ("django.contrib.staticfiles.finders.AppDirectoriesFinder",)
|
||||||
|
# ######### END STATIC FILE CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### SECRET CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
|
# Note: This key should only be used for development and testing.
|
||||||
|
SECRET_KEY = get_env_variable("GVALDAP_SECRETKEY")
|
||||||
|
# ######### END SECRET CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### FIXTURE CONFIGURATION
|
||||||
|
# See:
|
||||||
|
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS # noqa
|
||||||
|
FIXTURE_DIRS = (normpath(join(SITE_ROOT, "fixtures")),)
|
||||||
|
# ######### END FIXTURE CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### TEMPLATE CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/1.9/ref/settings/#std:setting-TEMPLATES # noqa
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
|
"DIRS": [normpath(join(SITE_ROOT, "templates"))],
|
||||||
|
"APP_DIRS": True,
|
||||||
|
"OPTIONS": {
|
||||||
|
"context_processors": [
|
||||||
|
"django.contrib.auth.context_processors.auth",
|
||||||
|
"django.template.context_processors.debug",
|
||||||
|
"django.template.context_processors.i18n",
|
||||||
|
"django.template.context_processors.media",
|
||||||
|
"django.template.context_processors.static",
|
||||||
|
"django.template.context_processors.tz",
|
||||||
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
"django.template.context_processors.request",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# ######### END TEMPLATE CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### MIDDLEWARE CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#middleware-classes
|
||||||
|
MIDDLEWARE = (
|
||||||
|
# Default Django middleware.
|
||||||
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
"django.middleware.locale.LocaleMiddleware",
|
||||||
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
)
|
||||||
|
# ######### END MIDDLEWARE CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### URL CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
|
||||||
|
ROOT_URLCONF = "%s.urls" % SITE_NAME
|
||||||
|
# ######### END URL CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### TEST RUNNER CONFIGURATION
|
||||||
|
TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
||||||
|
# ######### END TEST RUNNER CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### APP CONFIGURATION
|
||||||
|
DJANGO_APPS = (
|
||||||
|
# Default Django apps:
|
||||||
|
"django.contrib.auth",
|
||||||
|
"django.contrib.contenttypes",
|
||||||
|
"django.contrib.sessions",
|
||||||
|
"django.contrib.sites",
|
||||||
|
"django.contrib.messages",
|
||||||
|
"django.contrib.staticfiles",
|
||||||
|
# Admin panel and documentation:
|
||||||
|
"django.contrib.admin",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apps specific for this project go here.
|
||||||
|
LOCAL_APPS = ("ldapentities", "ldaptasks")
|
||||||
|
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||||
|
INSTALLED_APPS = DJANGO_APPS + LOCAL_APPS
|
||||||
|
# ######### END APP CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### LOGGING CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
||||||
|
# A sample logging configuration. The only tangible logging
|
||||||
|
# performed by this configuration is to send an email to
|
||||||
|
# the site admins on every HTTP 500 error when DEBUG=False.
|
||||||
|
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||||
|
# more details on how to customize your logging configuration.
|
||||||
|
LOGGING = {
|
||||||
|
"version": 1,
|
||||||
|
"disable_existing_loggers": False,
|
||||||
|
"formatters": {
|
||||||
|
"verbose": {
|
||||||
|
"format": "%(levelname)s %(asctime)s %(name)s "
|
||||||
|
"%(module)s:%(lineno)d %(process)d %(thread)d %(message)s"
|
||||||
|
},
|
||||||
|
"simple": {"format": "%(levelname)s %(name)s:%(lineno)d %(message)s"},
|
||||||
|
},
|
||||||
|
"filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}},
|
||||||
|
"handlers": {
|
||||||
|
"mail_admins": {
|
||||||
|
"level": "ERROR",
|
||||||
|
"filters": ["require_debug_false"],
|
||||||
|
"class": "django.utils.log.AdminEmailHandler",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"loggers": {
|
||||||
|
"django.request": {
|
||||||
|
"handlers": ["mail_admins"],
|
||||||
|
"level": "ERROR",
|
||||||
|
"propagate": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
# ######### END LOGGING CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### WSGI CONFIGURATION
|
||||||
|
# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
|
||||||
|
WSGI_APPLICATION = "%s.wsgi.application" % SITE_NAME
|
||||||
|
# ######### END WSGI CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
|
# ######### LDAP SETTINGS
|
||||||
|
GROUP_BASE_DN = get_env_variable("GVALDAP_BASEDN_GROUP")
|
||||||
|
USER_BASE_DN = get_env_variable("GVALDAP_BASEDN_USER")
|
||||||
|
# ######### END LDAP SETTINGS
|
||||||
|
|
||||||
|
|
||||||
|
# ######### CELERY CONFIGURATION
|
||||||
|
CELERY_BROKER_URL = get_env_variable("GVALDAP_BROKER_URL")
|
||||||
|
CELERY_RESULT_BACKEND = get_env_variable("GVALDAP_RESULTS_REDIS_URL")
|
||||||
|
CELERY_TASK_RESULT_EXPIRES = None
|
||||||
|
CELERY_ROUTES = ("gvacommon.celeryrouters.GvaRouter",)
|
||||||
|
CELERY_TIMEZONE = "Europe/Berlin"
|
||||||
|
CELERY_ENABLE_UTC = True
|
||||||
|
CELERY_ACCEPT_CONTENT = ["json"]
|
||||||
|
CELERY_TASK_SERIALIZER = "json"
|
||||||
|
CELERY_RESULT_SERIALIZER = "json"
|
||||||
|
# ######### END CELERY CONFIGURATION
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
CACHES = {"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}}
|
||||||
|
INSTALLED_APPS += ("debug_toolbar",)
|
||||||
|
|
||||||
|
MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
|
||||||
|
|
||||||
|
LOGGING["handlers"].update(
|
||||||
|
{
|
||||||
|
"console": {
|
||||||
|
"level": "DEBUG",
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "simple",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
LOGGING["loggers"].update(
|
||||||
|
dict(
|
||||||
|
[
|
||||||
|
(key, {"handlers": ["console"], "level": "DEBUG", "propagate": True})
|
||||||
|
for key in ["ldapentities", "ldaptasks"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
INTERNAL_IPS = get_env_variable("GVALDAP_INTERNAL_IPS", str, "127.0.0.1").split(",")
|
||||||
|
else:
|
||||||
|
ALLOWED_HOSTS = get_env_variable("GVALDAP_ALLOWED_HOSTS").split(",")
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
|
EMAIL_SUBJECT_PREFIX = "[%s] " % SITE_NAME
|
||||||
|
DEFAULT_FROM_EMAIL = get_env_variable("GVALDAP_ADMIN_EMAIL")
|
||||||
|
SERVER_EMAIL = get_env_variable("GVALDAP_SERVER_EMAIL")
|
||||||
|
|
||||||
|
if get_env_variable("GVALDAP_TEST", bool, False):
|
||||||
|
PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",)
|
||||||
|
# ######### IN-MEMORY TEST DATABASE
|
||||||
|
DATABASES["default"] = {
|
||||||
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
|
"NAME": ":memory:",
|
||||||
|
"USER": "",
|
||||||
|
"PASSWORD": "",
|
||||||
|
"HOST": "",
|
||||||
|
"PORT": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGING["handlers"].update(
|
||||||
|
{
|
||||||
|
"console": {
|
||||||
|
"level": "ERROR",
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "simple",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
LOGGING["loggers"].update(
|
||||||
|
dict(
|
||||||
|
[
|
||||||
|
(key, {"handlers": ["console"], "level": "ERROR", "propagate": True})
|
||||||
|
for key in ["ldapentities", "ldaptasks"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
CELERY_BROKER_URL = CELERY_BROKER_URL + "_test"
|
||||||
|
CELERY_RESULT_PERSISTENT = False
|
|
@ -1,3 +0,0 @@
|
||||||
"""
|
|
||||||
This module contains settings for various environments.
|
|
||||||
"""
|
|
|
@ -1,301 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# pymode:lint_ignore=E501
|
|
||||||
"""
|
|
||||||
Common settings and globals.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from os.path import abspath, basename, dirname, join, normpath
|
|
||||||
from sys import path
|
|
||||||
from os import environ
|
|
||||||
|
|
||||||
# Normally you should not import ANYTHING from Django directly
|
|
||||||
# into your settings, but ImproperlyConfigured is an exception.
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
|
|
||||||
|
|
||||||
def get_env_setting(setting):
|
|
||||||
"""
|
|
||||||
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:
|
|
||||||
error_msg = "Set the %s env variable" % setting
|
|
||||||
raise ImproperlyConfigured(error_msg)
|
|
||||||
|
|
||||||
|
|
||||||
########## PATH CONFIGURATION
|
|
||||||
# Absolute filesystem path to the Django project directory:
|
|
||||||
DJANGO_ROOT = dirname(dirname(abspath(__file__)))
|
|
||||||
|
|
||||||
# Absolute filesystem path to the top-level project folder:
|
|
||||||
SITE_ROOT = dirname(DJANGO_ROOT)
|
|
||||||
|
|
||||||
# Site name:
|
|
||||||
SITE_NAME = basename(DJANGO_ROOT)
|
|
||||||
|
|
||||||
# Add our project to our pythonpath, this way we don't need to type our project
|
|
||||||
# name in our dotted import paths:
|
|
||||||
path.append(DJANGO_ROOT)
|
|
||||||
########## END PATH CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## DEBUG CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
|
|
||||||
TEMPLATE_DEBUG = DEBUG
|
|
||||||
########## END DEBUG CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## MANAGER CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
|
|
||||||
ADMINS = (
|
|
||||||
(get_env_setting('GVALDAP_ADMIN_NAME'), get_env_setting('GVALDAP_ADMIN_EMAIL')),
|
|
||||||
)
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#managers
|
|
||||||
MANAGERS = ADMINS
|
|
||||||
########## END MANAGER CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## DATABASE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
|
||||||
'NAME': normpath(join(DJANGO_ROOT, 'default.db')),
|
|
||||||
'USER': '',
|
|
||||||
'PASSWORD': '',
|
|
||||||
'HOST': '',
|
|
||||||
'PORT': '',
|
|
||||||
},
|
|
||||||
'ldap': {
|
|
||||||
'ENGINE': 'ldapdb.backends.ldap',
|
|
||||||
'NAME': get_env_setting('GVALDAP_LDAP_URL'),
|
|
||||||
'USER': get_env_setting('GVALDAP_LDAP_USER'),
|
|
||||||
'PASSWORD': get_env_setting('GVALDAP_LDAP_PASSWORD'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DATABASE_ROUTERS = ['ldapdb.router.Router']
|
|
||||||
########## END DATABASE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## GENERAL CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#time-zone
|
|
||||||
TIME_ZONE = 'Europe/Berlin'
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
|
||||||
USE_I18N = True
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
|
|
||||||
USE_L10N = True
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
|
|
||||||
USE_TZ = True
|
|
||||||
########## END GENERAL CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## MEDIA CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
|
|
||||||
MEDIA_ROOT = normpath(join(SITE_ROOT, 'media'))
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
|
|
||||||
MEDIA_URL = '/media/'
|
|
||||||
########## END MEDIA CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## STATIC FILE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
|
|
||||||
STATIC_ROOT = normpath(join(SITE_ROOT, 'assets'))
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
|
||||||
STATIC_URL = '/static/'
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
|
||||||
STATICFILES_DIRS = (
|
|
||||||
normpath(join(SITE_ROOT, 'static')),
|
|
||||||
)
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
|
|
||||||
STATICFILES_FINDERS = (
|
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
|
||||||
)
|
|
||||||
########## END STATIC FILE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## SECRET CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
|
||||||
# Note: This key should only be used for development and testing.
|
|
||||||
SECRET_KEY = get_env_setting('GVALDAP_SECRETKEY')
|
|
||||||
########## END SECRET CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## SITE CONFIGURATION
|
|
||||||
# Hosts/domain names that are valid for this site
|
|
||||||
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
########## END SITE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## FIXTURE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS
|
|
||||||
FIXTURE_DIRS = (
|
|
||||||
normpath(join(SITE_ROOT, 'fixtures')),
|
|
||||||
)
|
|
||||||
########## END FIXTURE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## TEMPLATE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
|
||||||
'django.contrib.auth.context_processors.auth',
|
|
||||||
'django.core.context_processors.debug',
|
|
||||||
'django.core.context_processors.i18n',
|
|
||||||
'django.core.context_processors.media',
|
|
||||||
'django.core.context_processors.static',
|
|
||||||
'django.core.context_processors.tz',
|
|
||||||
'django.contrib.messages.context_processors.messages',
|
|
||||||
'django.core.context_processors.request',
|
|
||||||
)
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
|
|
||||||
TEMPLATE_LOADERS = (
|
|
||||||
'django.template.loaders.filesystem.Loader',
|
|
||||||
'django.template.loaders.app_directories.Loader',
|
|
||||||
)
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
|
|
||||||
TEMPLATE_DIRS = (
|
|
||||||
normpath(join(SITE_ROOT, 'templates')),
|
|
||||||
)
|
|
||||||
########## END TEMPLATE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## MIDDLEWARE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#middleware-classes
|
|
||||||
MIDDLEWARE_CLASSES = (
|
|
||||||
# Default Django middleware.
|
|
||||||
'django.middleware.common.CommonMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
||||||
)
|
|
||||||
########## END MIDDLEWARE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## URL CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
|
|
||||||
ROOT_URLCONF = '%s.urls' % SITE_NAME
|
|
||||||
########## END URL CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## TEST RUNNER CONFIGURATION
|
|
||||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
|
|
||||||
########## END TEST RUNNER CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## APP CONFIGURATION
|
|
||||||
DJANGO_APPS = (
|
|
||||||
# Default Django apps:
|
|
||||||
'django.contrib.auth',
|
|
||||||
'django.contrib.contenttypes',
|
|
||||||
'django.contrib.sessions',
|
|
||||||
'django.contrib.sites',
|
|
||||||
'django.contrib.messages',
|
|
||||||
'django.contrib.staticfiles',
|
|
||||||
|
|
||||||
# Useful template tags:
|
|
||||||
# 'django.contrib.humanize',
|
|
||||||
|
|
||||||
# Admin panel and documentation:
|
|
||||||
'django.contrib.admin',
|
|
||||||
# 'django.contrib.admindocs',
|
|
||||||
)
|
|
||||||
|
|
||||||
# Apps specific for this project go here.
|
|
||||||
LOCAL_APPS = (
|
|
||||||
'ldapentities',
|
|
||||||
'ldaptasks',
|
|
||||||
)
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
|
||||||
INSTALLED_APPS = DJANGO_APPS + LOCAL_APPS
|
|
||||||
########## END APP CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## LOGGING CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
|
||||||
# A sample logging configuration. The only tangible logging
|
|
||||||
# performed by this configuration is to send an email to
|
|
||||||
# the site admins on every HTTP 500 error when DEBUG=False.
|
|
||||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
|
||||||
# more details on how to customize your logging configuration.
|
|
||||||
LOGGING = {
|
|
||||||
'version': 1,
|
|
||||||
'disable_existing_loggers': False,
|
|
||||||
'filters': {
|
|
||||||
'require_debug_false': {
|
|
||||||
'()': 'django.utils.log.RequireDebugFalse'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'handlers': {
|
|
||||||
'mail_admins': {
|
|
||||||
'level': 'ERROR',
|
|
||||||
'filters': ['require_debug_false'],
|
|
||||||
'class': 'django.utils.log.AdminEmailHandler'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'loggers': {
|
|
||||||
'django.request': {
|
|
||||||
'handlers': ['mail_admins'],
|
|
||||||
'level': 'ERROR',
|
|
||||||
'propagate': True,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
########## END LOGGING CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## WSGI CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
########## CELERY CONFIGURATION
|
|
||||||
BROKER_URL = get_env_setting('GVALDAP_BROKER_URL')
|
|
||||||
CELERY_RESULT_BACKEND = 'amqp'
|
|
||||||
CELERY_RESULT_PERSISTENT = True
|
|
||||||
CELERY_TASK_RESULT_EXPIRES = None
|
|
||||||
CELERY_ROUTES = (
|
|
||||||
'gvacommon.celeryrouters.GvaRouter',
|
|
||||||
)
|
|
||||||
CELERY_TIMEZONE = 'Europe/Berlin'
|
|
||||||
CELERY_ENABLE_UTC = True
|
|
||||||
CELERY_ACCEPT_CONTENT = ['json']
|
|
||||||
CELERY_TASK_SERAILIZER = 'json'
|
|
||||||
CELERY_RESULT_SERIALIZER = 'json'
|
|
||||||
########## END CELERY CONFIGURATION
|
|
|
@ -1,51 +0,0 @@
|
||||||
# pymode:lint_ignore=W0401,E501
|
|
||||||
"""
|
|
||||||
Development settings and globals based on :py:mod:`gvaldap.settings.base`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from .base import *
|
|
||||||
|
|
||||||
|
|
||||||
########## DEBUG CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
|
|
||||||
DEBUG = True
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
|
|
||||||
TEMPLATE_DEBUG = DEBUG
|
|
||||||
########## END DEBUG CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## EMAIL CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
|
||||||
########## END EMAIL CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## CACHE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
|
||||||
CACHES = {
|
|
||||||
'default': {
|
|
||||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
########## END CACHE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## TOOLBAR CONFIGURATION
|
|
||||||
# See: http://django-debug-toolbar.readthedocs.org/en/latest/installation.html#explicit-setup
|
|
||||||
INSTALLED_APPS += (
|
|
||||||
'debug_toolbar',
|
|
||||||
)
|
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES += (
|
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
|
||||||
)
|
|
||||||
|
|
||||||
DEBUG_TOOLBAR_PATCH_SETTINGS = False
|
|
||||||
|
|
||||||
# http://django-debug-toolbar.readthedocs.org/en/latest/installation.html
|
|
||||||
INTERNAL_IPS = ('127.0.0.1',)
|
|
||||||
########## END TOOLBAR CONFIGURATION
|
|
|
@ -1,50 +0,0 @@
|
||||||
# pymode:lint_ignore=W0401,E501
|
|
||||||
"""
|
|
||||||
Production settings and globals based on :py:mod:`gvaldap.settings.base`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from .base import *
|
|
||||||
|
|
||||||
########## HOST CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/1.5/releases/1.5/#allowed-hosts-required-in-production
|
|
||||||
ALLOWED_HOSTS = get_env_setting('GVALDAP_ALLOWED_HOSTS').split(',')
|
|
||||||
########## END HOST CONFIGURATION
|
|
||||||
|
|
||||||
########## EMAIL CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host
|
|
||||||
#EMAIL_HOST = environ.get('EMAIL_HOST', 'smtp.gmail.com')
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host-password
|
|
||||||
#EMAIL_HOST_PASSWORD = environ.get('EMAIL_HOST_PASSWORD', '')
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-host-user
|
|
||||||
#EMAIL_HOST_USER = environ.get('EMAIL_HOST_USER', 'your_email@example.com')
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-port
|
|
||||||
#EMAIL_PORT = environ.get('EMAIL_PORT', 587)
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
|
|
||||||
EMAIL_SUBJECT_PREFIX = '[%s] ' % SITE_NAME
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#email-use-tls
|
|
||||||
#EMAIL_USE_TLS = True
|
|
||||||
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#server-email
|
|
||||||
SERVER_EMAIL = get_env_setting('GVALDAP_SERVER_EMAIL')
|
|
||||||
########## END EMAIL CONFIGURATION
|
|
||||||
|
|
||||||
########## DATABASE CONFIGURATION
|
|
||||||
#DATABASES = {}
|
|
||||||
########## END DATABASE CONFIGURATION
|
|
||||||
|
|
||||||
|
|
||||||
########## CACHE CONFIGURATION
|
|
||||||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
|
||||||
#CACHES = {}
|
|
||||||
########## END CACHE CONFIGURATION
|
|
|
@ -1,20 +0,0 @@
|
||||||
# pymode:lint_ignore=W0401
|
|
||||||
"""
|
|
||||||
Test settings based on :py:mod:`gvaldap.settings.base`.
|
|
||||||
|
|
||||||
"""
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from .base import *
|
|
||||||
|
|
||||||
########## IN-MEMORY TEST DATABASE
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
|
||||||
"NAME": ":memory:",
|
|
||||||
"USER": "",
|
|
||||||
"PASSWORD": "",
|
|
||||||
"HOST": "",
|
|
||||||
"PORT": "",
|
|
||||||
},
|
|
||||||
}
|
|
12
gvaldap/gvaldap/tests/test_wsgi.py
Normal file
12
gvaldap/gvaldap/tests/test_wsgi.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
"""
|
||||||
|
This module provides tests for :py:mod:`gvaldap.wsgi`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class WSGITest(TestCase):
|
||||||
|
|
||||||
|
def test_wsgi_application(self):
|
||||||
|
from gvaldap import wsgi
|
||||||
|
self.assertIsNotNone(wsgi.application)
|
|
@ -3,23 +3,27 @@ This module defines the main URLConf for gvaldap.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf.urls import patterns, include, url
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.conf.urls import include, url
|
||||||
# Uncomment the next two lines to enable the admin:
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
|
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
|
||||||
urlpatterns = patterns(
|
urlpatterns = [
|
||||||
'',
|
url(r'^admin/', admin.site.urls),
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
]
|
||||||
)
|
|
||||||
|
|
||||||
# Uncomment the next line to serve media files in dev.
|
# Uncomment the next line to serve media files in dev.
|
||||||
# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG: # pragma: no cover
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
urlpatterns += patterns('',
|
|
||||||
url(r'^__debug__/', include(debug_toolbar.urls)),
|
urlpatterns = (
|
||||||
)
|
[
|
||||||
|
url(r'^__debug__/', include(debug_toolbar.urls)),
|
||||||
|
]
|
||||||
|
+ staticfiles_urlpatterns()
|
||||||
|
+ urlpatterns
|
||||||
|
)
|
||||||
|
|
|
@ -17,6 +17,11 @@ import os
|
||||||
from os.path import abspath, dirname
|
from os.path import abspath, dirname
|
||||||
from sys import path
|
from sys import path
|
||||||
|
|
||||||
|
# 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 # noqa
|
||||||
|
|
||||||
SITE_ROOT = dirname(dirname(abspath(__file__)))
|
SITE_ROOT = dirname(dirname(abspath(__file__)))
|
||||||
path.append(SITE_ROOT)
|
path.append(SITE_ROOT)
|
||||||
|
|
||||||
|
@ -24,12 +29,8 @@ path.append(SITE_ROOT)
|
||||||
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
||||||
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
||||||
# os.environ["DJANGO_SETTINGS_MODULE"] = "jajaja.settings"
|
# os.environ["DJANGO_SETTINGS_MODULE"] = "jajaja.settings"
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings.production")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings")
|
||||||
|
|
||||||
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.
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|
||||||
# Apply WSGI middleware here.
|
# Apply WSGI middleware here.
|
||||||
|
|
|
@ -7,7 +7,7 @@ Admin classes for easy `django admin`_ based administration of LDAP entities.
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import (
|
from ldapentities.models import (
|
||||||
LdapGroup,
|
LdapGroup,
|
||||||
LdapUser,
|
LdapUser,
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,9 +6,9 @@ The models are based on :py:class:`ldapmodels.Model` from `django-ldapdb`_.
|
||||||
.. _django-ldapdb: https://github.com/jlaine/django-ldapdb#readme
|
.. _django-ldapdb: https://github.com/jlaine/django-ldapdb#readme
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from ldapdb.models.fields import (
|
from ldapdb.models.fields import (
|
||||||
CharField,
|
CharField,
|
||||||
IntegerField,
|
IntegerField,
|
||||||
|
@ -19,7 +19,6 @@ import ldapdb.models as ldapmodels
|
||||||
from passlib.hash import ldap_salted_sha1
|
from passlib.hash import ldap_salted_sha1
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class LdapGroup(ldapmodels.Model):
|
class LdapGroup(ldapmodels.Model):
|
||||||
"""
|
"""
|
||||||
Class for representing an LDAP group entity with objectClass `posixGroup`.
|
Class for representing an LDAP group entity with objectClass `posixGroup`.
|
||||||
|
@ -56,7 +55,6 @@ class LdapGroup(ldapmodels.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class LdapUser(ldapmodels.Model):
|
class LdapUser(ldapmodels.Model):
|
||||||
"""
|
"""
|
||||||
Class for representing an LDAP user entity with objectClasses `account` and
|
Class for representing an LDAP user entity with objectClasses `account` and
|
||||||
|
|
0
gvaldap/ldapentities/tests/__init__.py
Normal file
0
gvaldap/ldapentities/tests/__init__.py
Normal file
69
gvaldap/ldapentities/tests/test_admin.py
Normal file
69
gvaldap/ldapentities/tests/test_admin.py
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
"""
|
||||||
|
This module provides tests for :py:mod:`ldapentities.admin`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import volatildap
|
||||||
|
from django.conf import settings
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
TEST_USER = 'admin'
|
||||||
|
TEST_EMAIL = 'admin@example.org'
|
||||||
|
TEST_PASSWORD = 'secret'
|
||||||
|
|
||||||
|
admin = (settings.DATABASES['ldap']['USER'], {
|
||||||
|
'objectClass': ['person'],
|
||||||
|
'userPassword': [
|
||||||
|
settings.DATABASES['ldap'][
|
||||||
|
'PASSWORD']],
|
||||||
|
'sn': 'Admin',
|
||||||
|
})
|
||||||
|
|
||||||
|
groups = (settings.GROUP_BASE_DN, {
|
||||||
|
'objectClass': ['top', 'organizationalUnit'], 'ou': ['groups']})
|
||||||
|
users = (
|
||||||
|
settings.USER_BASE_DN, {
|
||||||
|
'objectClass': ['top', 'organizationalUnit'], 'ou': ['users']})
|
||||||
|
|
||||||
|
|
||||||
|
class LdapUserAdminTest(TestCase):
|
||||||
|
databases = ["default", "ldap"]
|
||||||
|
directory = dict([admin, groups, users])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(LdapUserAdminTest, cls).setUpClass()
|
||||||
|
cls.ldap_server = volatildap.LdapServer(
|
||||||
|
initial_data=cls.directory,
|
||||||
|
schemas=['core.schema', 'cosine.schema', 'inetorgperson.schema',
|
||||||
|
'nis.schema'],
|
||||||
|
)
|
||||||
|
settings.DATABASES['ldap']['USER'] = cls.ldap_server.rootdn
|
||||||
|
settings.DATABASES['ldap']['PASSWORD'] = cls.ldap_server.rootpw
|
||||||
|
settings.DATABASES['ldap']['NAME'] = cls.ldap_server.uri
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
cls.ldap_server.stop()
|
||||||
|
super(LdapUserAdminTest, cls).tearDownClass()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
TEST_USER, email=TEST_EMAIL, password=TEST_PASSWORD)
|
||||||
|
self.client.login(username=TEST_USER, password=TEST_PASSWORD)
|
||||||
|
self.ldap_server.start()
|
||||||
|
|
||||||
|
def test_can_administer_groups(self):
|
||||||
|
response = self.client.get(reverse(
|
||||||
|
'admin:ldapentities_ldapgroup_changelist'))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_can_administer_users(self):
|
||||||
|
response = self.client.get(reverse(
|
||||||
|
'admin:ldapentities_ldapuser_changelist'))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
37
gvaldap/ldapentities/tests/test_models.py
Normal file
37
gvaldap/ldapentities/tests/test_models.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
"""
|
||||||
|
This model provides tests for :py:mod:`ldapentities.models`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from passlib.hash import ldap_salted_sha1
|
||||||
|
|
||||||
|
from ldapentities.models import LdapGroup, LdapUser
|
||||||
|
|
||||||
|
|
||||||
|
class LdapGroupTest(TestCase):
|
||||||
|
|
||||||
|
def test___str__(self):
|
||||||
|
ldapgroup = LdapGroup(
|
||||||
|
gid=5000, name='test', description='test group')
|
||||||
|
self.assertEqual(str(ldapgroup), 'test')
|
||||||
|
|
||||||
|
|
||||||
|
class LdapUserTest(TestCase):
|
||||||
|
|
||||||
|
def test___str__(self):
|
||||||
|
ldapuser = LdapUser(
|
||||||
|
uid=5000, group=5000, gecos="a test user",
|
||||||
|
home_directory='/home/test', login_shell='/bin/bash',
|
||||||
|
username='test', password='test', common_name='Test')
|
||||||
|
self.assertEqual(str(ldapuser), 'test')
|
||||||
|
|
||||||
|
def test_set_password(self):
|
||||||
|
ldapuser = LdapUser(
|
||||||
|
uid=5000, group=5000, gecos="a test user",
|
||||||
|
home_directory='/home/test', login_shell='/bin/bash',
|
||||||
|
username='test', password='test', common_name='Test')
|
||||||
|
self.assertEqual(ldapuser.password, 'test')
|
||||||
|
ldapuser.set_password('test2')
|
||||||
|
self.assertTrue(ldap_salted_sha1.verify('test2', ldapuser.password))
|
17
gvaldap/ldaptasks/celery.py
Normal file
17
gvaldap/ldaptasks/celery.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
"""
|
||||||
|
This module defines the Celery_ app for gvaldap.
|
||||||
|
|
||||||
|
.. _Celery: http://www.celeryproject.org/
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings")
|
||||||
|
|
||||||
|
app = Celery("ldaptasks")
|
||||||
|
|
||||||
|
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||||
|
|
||||||
|
app.autodiscover_tasks()
|
|
@ -7,22 +7,22 @@ This module defines `Celery`_ tasks to manage LDAP entities.
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from copy import deepcopy
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from celery.utils.log import get_task_logger
|
|
||||||
from celery.exceptions import Reject
|
from celery.exceptions import Reject
|
||||||
|
from celery.utils.log import get_task_logger
|
||||||
|
|
||||||
from ldapentities.models import (
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
LdapGroup,
|
from django.db.utils import Error as DjangoDBUtilsError
|
||||||
LdapUser,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
from ldapentities.models import LdapGroup, LdapUser
|
||||||
|
|
||||||
_LOGGER = get_task_logger(__name__)
|
_LOGGER = get_task_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def create_ldap_group(groupname, gid, descr):
|
def create_ldap_group(groupname, gid, description):
|
||||||
"""
|
"""
|
||||||
This task creates an :py:class:`LDAP group <ldapentities.models.LdapGroup>`
|
This task creates an :py:class:`LDAP group <ldapentities.models.LdapGroup>`
|
||||||
if it does not exist yet.
|
if it does not exist yet.
|
||||||
|
@ -32,26 +32,34 @@ def create_ldap_group(groupname, gid, descr):
|
||||||
|
|
||||||
:param str groupname: the group name
|
:param str groupname: the group name
|
||||||
:param int gid: the group id
|
:param int gid: the group id
|
||||||
:param str descr: description text for the group
|
:param str description: description text for the group
|
||||||
:return: the distinguished name of the group
|
:return: dictionary containing groupname, gid, description and
|
||||||
:rtype: str
|
:py:const:`group_dn` set to the distinguished name of the newly created
|
||||||
|
or existing LDAP group
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP group %s with groupname %s already exists',
|
"LDAP group %s with groupname %s already exists", ldapgroup.dn, groupname
|
||||||
ldapgroup.dn, groupname)
|
)
|
||||||
ldapgroup.gid = gid
|
ldapgroup.gid = gid
|
||||||
except LdapGroup.DoesNotExist:
|
except LdapGroup.DoesNotExist:
|
||||||
ldapgroup = LdapGroup(gid=gid, name=groupname)
|
ldapgroup = LdapGroup(gid=gid, name=groupname)
|
||||||
_LOGGER.info('created LDAP group %s', ldapgroup.dn)
|
_LOGGER.info("created LDAP group %s", ldapgroup.dn)
|
||||||
ldapgroup.description = descr
|
ldapgroup.description = description
|
||||||
ldapgroup.save()
|
ldapgroup.save()
|
||||||
_LOGGER.info('set description of LDAP group %s', ldapgroup.dn)
|
_LOGGER.info("set description of LDAP group %s", ldapgroup.dn)
|
||||||
return ldapgroup.dn
|
return {
|
||||||
|
"groupname": groupname,
|
||||||
|
"gid": gid,
|
||||||
|
"description": description,
|
||||||
|
"group_dn": ldapgroup.dn,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def create_ldap_user(username, uid, gid, gecos, homedir, shell, password):
|
def create_ldap_user(username, uid, gid, gecos, homedir, shell, password):
|
||||||
"""
|
"""
|
||||||
This task creates an :py:class:`LDAP user <ldapentities.models.LdapUser>`
|
This task creates an :py:class:`LDAP user <ldapentities.models.LdapUser>`
|
||||||
|
@ -71,21 +79,23 @@ def create_ldap_user(username, uid, gid, gecos, homedir, shell, password):
|
||||||
is passed the password is not touched
|
is passed the password is not touched
|
||||||
:raises celery.exceptions.Reject: if the specified primary group does not
|
:raises celery.exceptions.Reject: if the specified primary group does not
|
||||||
exist
|
exist
|
||||||
:return: the distinguished name of the user
|
:return: dictionary containing username, uid, gid, gecos, homedir, shell,
|
||||||
:rtype: str
|
password and :py:const:`user_dn` set to the distinguished name of the
|
||||||
|
newly created or existing LDAP user
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
ldapuser = LdapUser.objects.get(username=username)
|
ldapuser = LdapUser.objects.get(username=username)
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP user %s with username %s already exists',
|
"LDAP user %s with username %s already exists", ldapuser.dn, username
|
||||||
ldapuser.dn, username)
|
)
|
||||||
except LdapUser.DoesNotExist:
|
except LdapUser.DoesNotExist:
|
||||||
ldapuser = LdapUser(username=username)
|
ldapuser = LdapUser(username=username)
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(gid=gid)
|
ldapgroup = LdapGroup.objects.get(gid=gid)
|
||||||
except ObjectDoesNotExist as exc:
|
except ObjectDoesNotExist as exc:
|
||||||
_LOGGER.error('LDAP group with gid %d does not exist', gid)
|
_LOGGER.error("LDAP group with gid %d does not exist", gid)
|
||||||
raise Reject(exc, requeue=False)
|
raise Reject(exc, requeue=False)
|
||||||
ldapuser.uid = uid
|
ldapuser.uid = uid
|
||||||
ldapuser.group = gid
|
ldapuser.group = gid
|
||||||
|
@ -96,46 +106,58 @@ def create_ldap_user(username, uid, gid, gecos, homedir, shell, password):
|
||||||
ldapuser.common_name = username
|
ldapuser.common_name = username
|
||||||
if password is not None:
|
if password is not None:
|
||||||
ldapuser.set_password(password)
|
ldapuser.set_password(password)
|
||||||
_LOGGER.info('set password for LDAP user %s', ldapuser.dn)
|
_LOGGER.info("set password for LDAP user %s", ldapuser.dn)
|
||||||
ldapuser.save()
|
ldapuser.save()
|
||||||
_LOGGER.info('LDAP user %s created', ldapuser.dn)
|
_LOGGER.info("LDAP user %s created", ldapuser.dn)
|
||||||
if ldapuser.username in ldapgroup.members:
|
if ldapuser.username in ldapgroup.members:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP user %s is already member of LDAP group %s',
|
"LDAP user %s is already member of LDAP group %s", ldapuser.dn, ldapgroup.dn
|
||||||
ldapuser.dn, ldapgroup.dn)
|
)
|
||||||
else:
|
else:
|
||||||
ldapgroup.members.append(ldapuser.username)
|
ldapgroup.members.append(ldapuser.username)
|
||||||
ldapgroup.save()
|
ldapgroup.save()
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP user %s has been added to LDAP group %s',
|
"LDAP user %s has been added to LDAP group %s", ldapuser.dn, ldapgroup.dn
|
||||||
ldapuser.dn, ldapgroup.dn)
|
)
|
||||||
return ldapuser.dn
|
return {
|
||||||
|
"username": username,
|
||||||
|
"uid": uid,
|
||||||
|
"gid": gid,
|
||||||
|
"gecos": gecos,
|
||||||
|
"homedir": homedir,
|
||||||
|
"shell": shell,
|
||||||
|
"user_dn": ldapuser.dn,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True)
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def set_ldap_user_password(self, username, password):
|
def set_ldap_user_password(username, password):
|
||||||
"""
|
"""
|
||||||
This task sets the password of an existing :py:class:`LDAP user
|
This task sets the password of an existing :py:class:`LDAP user
|
||||||
<ldapentities.models.LdapUser>`.
|
<ldapentities.models.LdapUser>`.
|
||||||
|
|
||||||
:param str username: the user name
|
:param str username: the user name
|
||||||
:param str password: teh clear text password
|
:param str password: teh clear text password
|
||||||
:return: :py:const:`True` if the password has been set, :py:const:`False`
|
:return: dictionary containing the username and a flag
|
||||||
if the user does not exist.
|
:py:const:`password_set` that is set to :py:const:`True` if the
|
||||||
|
password has been set, :py:const:`False` if the user does not exist.
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
retval = {"username": username, "password_set": False}
|
||||||
try:
|
try:
|
||||||
ldapuser = LdapUser.objects.get(username=username)
|
ldapuser = LdapUser.objects.get(username=username)
|
||||||
except LdapUser.DoesNotExist:
|
except LdapUser.DoesNotExist:
|
||||||
_LOGGER.info('there is no LDAP user with username %s', username)
|
_LOGGER.info("there is no LDAP user with username %s", username)
|
||||||
return False
|
return retval
|
||||||
ldapuser.set_password(password)
|
ldapuser.set_password(password)
|
||||||
ldapuser.save()
|
ldapuser.save()
|
||||||
_LOGGER.info("set new password for LDAP user %s", ldapuser.dn)
|
_LOGGER.info("set new password for LDAP user %s", ldapuser.dn)
|
||||||
return True
|
retval["password_set"] = True
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True)
|
@shared_task(bind=True, autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def add_ldap_user_to_group(self, username, groupname):
|
def add_ldap_user_to_group(self, username, groupname):
|
||||||
"""
|
"""
|
||||||
This task adds the specified user to the given group.
|
This task adds the specified user to the given group.
|
||||||
|
@ -146,146 +168,198 @@ def add_ldap_user_to_group(self, username, groupname):
|
||||||
:param str groupname: the group name
|
:param str groupname: the group name
|
||||||
:raises celery.exceptions.Retry: if the user does not exist yet,
|
:raises celery.exceptions.Retry: if the user does not exist yet,
|
||||||
:py:func:`create_ldap_user` should be called before
|
:py:func:`create_ldap_user` should be called before
|
||||||
:return: True if the user has been added to the group otherwise False
|
:return: dictionary containing the username, groupname and a flag
|
||||||
:rtype: boolean
|
:py:const`added` that is as a :py:const:`True` if the user has been
|
||||||
|
added to the group otherwise to :py:const:`False`
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
retval = {"username": username, "groupname": groupname, "added": False}
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||||
ldapuser = LdapUser.objects.get(username=username)
|
ldapuser = LdapUser.objects.get(username=username)
|
||||||
except LdapGroup.DoesNotExist:
|
except LdapGroup.DoesNotExist:
|
||||||
_LOGGER.error('LDAP group with groupname %s does not exist', groupname)
|
_LOGGER.error("LDAP group with groupname %s does not exist", groupname)
|
||||||
except LdapUser.DoesNotExist as exc:
|
except LdapUser.DoesNotExist as exc:
|
||||||
_LOGGER.error('LDAP user with username %s does not exist', username)
|
_LOGGER.error("LDAP user with username %s does not exist", username)
|
||||||
self.retry(exc=exc, time_limit=5)
|
self.retry(exc=exc, time_limit=5)
|
||||||
else:
|
else:
|
||||||
if ldapuser.username not in ldapgroup.members:
|
if ldapuser.username not in ldapgroup.members:
|
||||||
ldapgroup.members.append(ldapuser.username)
|
ldapgroup.members.append(ldapuser.username)
|
||||||
ldapgroup.save()
|
ldapgroup.save()
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP user %s has been added to LDAP group %s',
|
"LDAP user %s has been added to LDAP group %s",
|
||||||
ldapuser.username, ldapgroup.dn)
|
ldapuser.username,
|
||||||
|
ldapgroup.dn,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP user %s is already in LDAP group %s',
|
"LDAP user %s is already in LDAP group %s",
|
||||||
ldapuser.username, ldapgroup.dn)
|
ldapuser.username,
|
||||||
return True
|
ldapgroup.dn,
|
||||||
return False
|
)
|
||||||
|
retval["added"] = True
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def remove_ldap_user_from_group(username, groupname):
|
def remove_ldap_user_from_group(username, groupname):
|
||||||
"""
|
"""
|
||||||
This task removes the given user from the given group.
|
This task removes the given user from the given group.
|
||||||
|
|
||||||
:param str username: the user name
|
:param str username: the user name
|
||||||
:param str groupname: the group name
|
:param str groupname: the group name
|
||||||
:return: True if the user has been removed, False otherwise
|
:return: dictionary containing the input parameters and a flag
|
||||||
:rtype: boolean
|
:py:const:`removed` that is set to :py:const:`True` if the user has
|
||||||
|
been removed, False otherwise
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
retval = {"username": username, "groupname": groupname, "removed": False}
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||||
ldapuser = LdapUser.objects.get(username=username)
|
ldapuser = LdapUser.objects.get(username=username)
|
||||||
except LdapGroup.DoesNotExist:
|
except LdapGroup.DoesNotExist:
|
||||||
_LOGGER.error('LDAP group with groupname %s does not exist', groupname)
|
_LOGGER.error("LDAP group with groupname %s does not exist", groupname)
|
||||||
except LdapUser.DoesNotExist:
|
except LdapUser.DoesNotExist:
|
||||||
_LOGGER.error('LDAP user with username %s does not exist', username)
|
_LOGGER.error("LDAP user with username %s does not exist", username)
|
||||||
else:
|
else:
|
||||||
if ldapuser.username in ldapgroup.members:
|
if ldapuser.username in ldapgroup.members:
|
||||||
ldapgroup.members.remove(ldapuser.username)
|
ldapgroup.members.remove(ldapuser.username)
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'removed LDAP user %s from LDAP group %s',
|
"removed LDAP user %s from LDAP group %s", ldapuser.dn, ldapgroup.dn
|
||||||
ldapuser.dn, ldapgroup.dn)
|
)
|
||||||
ldapgroup.save()
|
ldapgroup.save()
|
||||||
return True
|
retval["removed"] = True
|
||||||
else:
|
else:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP user %s is not a member of LDAP group %s',
|
"LDAP user %s is not a member of LDAP group %s",
|
||||||
ldapuser.dn, ldapgroup.dn)
|
ldapuser.dn,
|
||||||
return False
|
ldapgroup.dn,
|
||||||
|
)
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def delete_ldap_user(username):
|
def delete_ldap_user(username, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
This task deletes the given user.
|
This task deletes the given user.
|
||||||
|
|
||||||
:param str username: the user name
|
:param str username: the user name
|
||||||
:return: True if the user has been deleted, False otherwise
|
:return: dictionary containing the username and a flag :py:const:`deleted`
|
||||||
:rtype: boolean
|
that is set to :py:const:`True` if the user has been deleted and is set
|
||||||
|
to :py:const:`False` otherwise
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This variant can only be used at the beginning of a Celery task chain
|
||||||
|
or as a standalone task.
|
||||||
|
|
||||||
|
Use :py:func:`ldaptasks.tasks.delete_ldap_user_chained` at other
|
||||||
|
positions in the task chain
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
retval = {"username": username, "deleted": False}
|
||||||
try:
|
try:
|
||||||
ldapuser = LdapUser.objects.get(username=username)
|
ldapuser = LdapUser.objects.get(username=username)
|
||||||
except LdapUser.DoesNotExist:
|
except LdapUser.DoesNotExist:
|
||||||
_LOGGER.info('there is no LDAP user with username %s', username)
|
_LOGGER.info("there is no LDAP user with username %s", username)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(gid=ldapuser.group)
|
ldapgroup = LdapGroup.objects.get(gid=ldapuser.group)
|
||||||
except LdapGroup.DoesNotExist:
|
except LdapGroup.DoesNotExist:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP group %s of LDAP user %s does not exist',
|
"LDAP group %s of LDAP user %s does not exist",
|
||||||
ldapuser.group, ldapuser.dn)
|
ldapuser.group,
|
||||||
|
ldapuser.dn,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if ldapuser.username in ldapgroup.members:
|
if ldapuser.username in ldapgroup.members:
|
||||||
ldapgroup.members.remove(ldapuser.username)
|
ldapgroup.members.remove(ldapuser.username)
|
||||||
ldapgroup.save()
|
ldapgroup.save()
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'removed LDAP user %s from LDAP group %s',
|
"removed LDAP user %s from LDAP group %s", ldapuser.dn, ldapgroup.dn
|
||||||
ldapuser.dn, ldapgroup.dn)
|
)
|
||||||
userdn = ldapuser.dn
|
userdn = ldapuser.dn
|
||||||
ldapuser.delete()
|
ldapuser.delete()
|
||||||
_LOGGER.info('deleted LDAP user %s', userdn)
|
_LOGGER.info("deleted LDAP user %s", userdn)
|
||||||
return True
|
retval["deleted"] = True
|
||||||
return False
|
return retval
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
|
def delete_ldap_user_chained(previous_result, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
This task deletes the given user.
|
||||||
|
|
||||||
|
:param dict previous_result: a dictionary describing the result of the
|
||||||
|
previous step in the Celery task chain. This dictionary must contain a
|
||||||
|
:py:const:`username` key
|
||||||
|
:return: a copy of the :py:obj:`previous_result` dictionary with a new
|
||||||
|
:py:const:`deleted` key set to :py:const:`True` if the user has been
|
||||||
|
deleted and set to :py:const:`False` otherwise
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
|
"""
|
||||||
|
username = previous_result["username"]
|
||||||
|
retval = deepcopy(previous_result)
|
||||||
|
retval.update(delete_ldap_user(username))
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def delete_ldap_group_if_empty(groupname):
|
def delete_ldap_group_if_empty(groupname):
|
||||||
"""
|
"""
|
||||||
This task deletes the given group.
|
This task deletes the given group if it is empty.
|
||||||
|
|
||||||
:param str groupname: the group name
|
:param str groupname: the group name
|
||||||
:return: True if the user has been deleted, False otherwise
|
:return: dictionary that contains the groupname and a flag
|
||||||
:rtype: boolean
|
:py:const:`deleted` that is set to :py:const:`True` if the group has
|
||||||
|
been deleted and is set to :py:const:`False` otherwise
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
retval = {"groupname": groupname, "deleted": False}
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||||
except LdapGroup.DoesNotExist:
|
except LdapGroup.DoesNotExist:
|
||||||
_LOGGER.info('LDAP group with groupname %s does not exist', groupname)
|
_LOGGER.info("LDAP group with groupname %s does not exist", groupname)
|
||||||
else:
|
else:
|
||||||
if len(ldapgroup.members) == 0:
|
if len(ldapgroup.members) == 0:
|
||||||
groupdn = ldapgroup.dn
|
groupdn = ldapgroup.dn
|
||||||
ldapgroup.delete()
|
ldapgroup.delete()
|
||||||
_LOGGER.info(
|
_LOGGER.info("deleted LDAP group %s", groupdn)
|
||||||
'deleted LDAP group %s', groupdn)
|
retval["deleted"] = True
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'LDAP group %s has not been deleted. It still has %d members',
|
"LDAP group %s has not been deleted. It still has %d members",
|
||||||
ldapgroup.dn, len(ldapgroup.members))
|
ldapgroup.dn,
|
||||||
return False
|
len(ldapgroup.members),
|
||||||
|
)
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task(autoretry_for=(DjangoDBUtilsError,), default_retry_delay=10)
|
||||||
def delete_ldap_group(groupname):
|
def delete_ldap_group(groupname):
|
||||||
"""
|
"""
|
||||||
This taks deletes the given group.
|
This task deletes the given group.
|
||||||
|
|
||||||
:param str groupname: the group name
|
:param str groupname: the group name
|
||||||
:return: True if the user has been deleted, False otherwise
|
:return: dictionary that contains the groupname and a flag
|
||||||
:rtype: boolean
|
:py:const:`deleted` that is set to :py:const:`True` if the group has
|
||||||
|
been deleted and is set to :py:const:`False` otherwise
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
retval = {"groupname": groupname, "deleted": False}
|
||||||
try:
|
try:
|
||||||
ldapgroup = LdapGroup.objects.get(name=groupname)
|
ldapgroup = LdapGroup.objects.get(name=groupname)
|
||||||
except LdapGroup.DoesNotExist:
|
except LdapGroup.DoesNotExist:
|
||||||
_LOGGER.info('LDAP group with name %s does not exist', groupname)
|
_LOGGER.info("LDAP group with name %s does not exist", groupname)
|
||||||
else:
|
else:
|
||||||
groupdn = ldapgroup.dn
|
groupdn = ldapgroup.dn
|
||||||
ldapgroup.delete()
|
ldapgroup.delete()
|
||||||
_LOGGER.info('deleted LDAP group %s', groupdn)
|
_LOGGER.info("deleted LDAP group %s", groupdn)
|
||||||
return True
|
retval["deleted"] = True
|
||||||
return False
|
return retval
|
||||||
|
|
0
gvaldap/ldaptasks/tests/__init__.py
Normal file
0
gvaldap/ldaptasks/tests/__init__.py
Normal file
264
gvaldap/ldaptasks/tests/test_tasks.py
Normal file
264
gvaldap/ldaptasks/tests/test_tasks.py
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
"""
|
||||||
|
This module provides tests for :py:mod:`ldaptasks.tasks`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import volatildap
|
||||||
|
from celery.exceptions import Reject
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from ldapentities.models import LdapUser
|
||||||
|
from ldaptasks.tasks import (
|
||||||
|
add_ldap_user_to_group,
|
||||||
|
create_ldap_group,
|
||||||
|
create_ldap_user,
|
||||||
|
delete_ldap_group,
|
||||||
|
delete_ldap_group_if_empty,
|
||||||
|
delete_ldap_user,
|
||||||
|
delete_ldap_user_chained,
|
||||||
|
remove_ldap_user_from_group,
|
||||||
|
set_ldap_user_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LdapTaskTestCase(TestCase):
|
||||||
|
databases = ["default", "ldap"]
|
||||||
|
|
||||||
|
directory = {
|
||||||
|
settings.DATABASES['ldap']['USER']: {
|
||||||
|
'objectClass': ['person'],
|
||||||
|
'userPassword': [settings.DATABASES['ldap']['PASSWORD']],
|
||||||
|
'sn': 'Admin',
|
||||||
|
},
|
||||||
|
settings.GROUP_BASE_DN: {
|
||||||
|
'objectClass': ['top', 'organizationalUnit'],
|
||||||
|
'ou': ['groups']
|
||||||
|
},
|
||||||
|
settings.USER_BASE_DN: {
|
||||||
|
'objectClass': ['top', 'organizationalUnit'],
|
||||||
|
'ou': ['users']
|
||||||
|
},
|
||||||
|
'cn=existing,' + settings.GROUP_BASE_DN: {
|
||||||
|
'objectClass': ['posixGroup'],
|
||||||
|
'gidNumber': ['4711'],
|
||||||
|
'cn': ['existing'],
|
||||||
|
'description': ['existing test group'],
|
||||||
|
'memberUid': ['existing'],
|
||||||
|
},
|
||||||
|
'uid=existing,' + settings.USER_BASE_DN: {
|
||||||
|
'objectClass': ['account', 'posixAccount'],
|
||||||
|
'uidNumber': ['815'],
|
||||||
|
'gidNumber': ['4711'],
|
||||||
|
'gecos': ['existing test user'],
|
||||||
|
'homeDirectory': ['/home/existing'],
|
||||||
|
'loginShell': ['/bin/bash'],
|
||||||
|
'uid': ['existing'],
|
||||||
|
'userPassword': ['secret'],
|
||||||
|
'cn': ['existing']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(LdapTaskTestCase, cls).setUpClass()
|
||||||
|
cls.ldap_server = volatildap.LdapServer(
|
||||||
|
initial_data=cls.directory,
|
||||||
|
schemas=['core.schema', 'cosine.schema', 'inetorgperson.schema',
|
||||||
|
'nis.schema'],
|
||||||
|
)
|
||||||
|
settings.DATABASES['ldap']['USER'] = cls.ldap_server.rootdn
|
||||||
|
settings.DATABASES['ldap']['PASSWORD'] = cls.ldap_server.rootpw
|
||||||
|
settings.DATABASES['ldap']['NAME'] = cls.ldap_server.uri
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
cls.ldap_server.stop()
|
||||||
|
super(LdapTaskTestCase, cls).tearDownClass()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.ldap_server.start()
|
||||||
|
|
||||||
|
def test_create_ldap_group(self):
|
||||||
|
result = create_ldap_group('test', 5000, 'test group')
|
||||||
|
self.assertEqual({
|
||||||
|
'groupname': 'test', 'gid': 5000, 'description': 'test group',
|
||||||
|
'group_dn': 'cn=test,%s' % settings.GROUP_BASE_DN
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_create_ldap_group_existing(self):
|
||||||
|
result = create_ldap_group('existing', 4711, 'existing test group')
|
||||||
|
self.assertEqual({
|
||||||
|
'groupname': 'existing', 'gid': 4711,
|
||||||
|
'description': 'existing test group',
|
||||||
|
'group_dn': 'cn=existing,%s' % settings.GROUP_BASE_DN
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_create_ldap_group_existing_modify(self):
|
||||||
|
result = create_ldap_group(
|
||||||
|
'existing', 4711, 'change existing test group')
|
||||||
|
self.assertEqual({
|
||||||
|
'groupname': 'existing', 'gid': 4711,
|
||||||
|
'description': 'change existing test group',
|
||||||
|
'group_dn': 'cn=existing,%s' % settings.GROUP_BASE_DN
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_create_ldap_user(self):
|
||||||
|
result = create_ldap_user(
|
||||||
|
'test', 5000, 4711, 'Test User', '/home/test', '/bin/bash',
|
||||||
|
'secret')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'test', 'uid': 5000, 'gid': 4711, 'gecos': 'Test User',
|
||||||
|
'homedir': '/home/test', 'shell': '/bin/bash',
|
||||||
|
'user_dn': 'uid=test,%s' % settings.USER_BASE_DN
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_create_ldap_user_invalid_group(self):
|
||||||
|
with self.assertRaises(Reject):
|
||||||
|
create_ldap_user(
|
||||||
|
'test', 5000, 5000, 'Test User', '/home/test', '/bin/bash',
|
||||||
|
'secret')
|
||||||
|
|
||||||
|
def test_create_ldap_user_no_password(self):
|
||||||
|
result = create_ldap_user(
|
||||||
|
'test', 5000, 4711, 'Test User', '/home/test', '/bin/bash',
|
||||||
|
None)
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'test', 'uid': 5000, 'gid': 4711, 'gecos': 'Test User',
|
||||||
|
'homedir': '/home/test', 'shell': '/bin/bash',
|
||||||
|
'user_dn': 'uid=test,%s' % settings.USER_BASE_DN
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_create_ldap_user_existing(self):
|
||||||
|
result = create_ldap_user(
|
||||||
|
'existing', 815, 4711, 'existing test user', '/home/existing',
|
||||||
|
'/bin/bash', 'secret'
|
||||||
|
)
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'uid': 815, 'gid': 4711,
|
||||||
|
'gecos': 'existing test user', 'homedir': '/home/existing',
|
||||||
|
'shell': '/bin/bash',
|
||||||
|
'user_dn': u'uid=existing,%s' % settings.USER_BASE_DN
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_set_ldap_user_password_existing(self):
|
||||||
|
result = set_ldap_user_password('existing', 'newpassword')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'password_set': True
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_set_ldap_user_password_missing(self):
|
||||||
|
result = set_ldap_user_password('missing', 'newpassword')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'missing', 'password_set': False
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_add_ldap_user_to_group_existing(self):
|
||||||
|
result = add_ldap_user_to_group('existing', 'existing')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'groupname': 'existing', 'added': True
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_add_ldap_user_to_group_new_user(self):
|
||||||
|
create_ldap_group('test', 5000, 'test group')
|
||||||
|
result = add_ldap_user_to_group('existing', 'test')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'groupname': 'test', 'added': True
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_add_ldap_user_to_group_no_group(self):
|
||||||
|
result = add_ldap_user_to_group('existing', 'test')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'groupname': 'test', 'added': False
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_add_ldap_user_to_group_no_user(self):
|
||||||
|
with self.assertRaises(LdapUser.DoesNotExist):
|
||||||
|
add_ldap_user_to_group('test', 'existing')
|
||||||
|
|
||||||
|
def test_remove_ldap_user_from_group_existing(self):
|
||||||
|
result = remove_ldap_user_from_group('existing', 'existing')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'groupname': 'existing', 'removed': True
|
||||||
|
}, result)
|
||||||
|
self.assertNotIn('memberUid', self.ldap_server.get(
|
||||||
|
'cn=existing,' + settings.GROUP_BASE_DN))
|
||||||
|
|
||||||
|
def test_remove_ldap_user_from_group_not_in_group(self):
|
||||||
|
create_ldap_group('test', 5000, 'test group')
|
||||||
|
result = remove_ldap_user_from_group('existing', 'test')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'groupname': 'test', 'removed': False
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_remove_ldap_user_from_group_no_group(self):
|
||||||
|
result = remove_ldap_user_from_group('existing', 'test')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'existing', 'groupname': 'test', 'removed': False
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_remove_ldap_user_from_group_no_user(self):
|
||||||
|
result = remove_ldap_user_from_group('test', 'existing')
|
||||||
|
self.assertEqual({
|
||||||
|
'username': 'test', 'groupname': 'existing', 'removed': False
|
||||||
|
}, result)
|
||||||
|
|
||||||
|
def test_delete_ldap_user_existing(self):
|
||||||
|
result = delete_ldap_user('existing')
|
||||||
|
self.assertEqual({'username': 'existing', 'deleted': True}, result)
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
self.ldap_server.get('uid=existing,' + settings.USER_BASE_DN)
|
||||||
|
self.assertNotIn('memberUid', self.ldap_server.get(
|
||||||
|
'cn=existing,' + settings.GROUP_BASE_DN))
|
||||||
|
|
||||||
|
def test_delete_ldap_user_missing(self):
|
||||||
|
result = delete_ldap_user('missing')
|
||||||
|
self.assertEqual({'username': 'missing', 'deleted': False}, result)
|
||||||
|
|
||||||
|
def test_delete_ldap_user_no_group(self):
|
||||||
|
self.ldap_server.get('uid=existing,' + settings.USER_BASE_DN)[
|
||||||
|
'gidNumber'] = '5000'
|
||||||
|
result = delete_ldap_user('existing')
|
||||||
|
self.assertEqual({'username': 'existing', 'deleted': True}, result)
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
self.ldap_server.get('uid=existing,' + settings.USER_BASE_DN)
|
||||||
|
|
||||||
|
def test_delete_ldap_user_chained_exsting(self):
|
||||||
|
result = delete_ldap_user_chained({'username': 'existing'})
|
||||||
|
self.assertEqual({'username': 'existing', 'deleted': True}, result)
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
self.ldap_server.get('uid=existing,' + settings.USER_BASE_DN)
|
||||||
|
group_object = self.ldap_server.get('cn=existing,' + settings.GROUP_BASE_DN)
|
||||||
|
self.assertNotIn('memberUid', group_object)
|
||||||
|
|
||||||
|
def test_delete_ldap_group_if_empty_nonempty(self):
|
||||||
|
result = delete_ldap_group_if_empty('existing')
|
||||||
|
self.assertEqual({'groupname': 'existing', 'deleted': False}, result)
|
||||||
|
ldap_object = self.ldap_server.get('cn=existing,' + settings.GROUP_BASE_DN)
|
||||||
|
self.assertIsNotNone(ldap_object)
|
||||||
|
|
||||||
|
def test_delete_ldap_group_if_empty_missing(self):
|
||||||
|
result = delete_ldap_group_if_empty('missing')
|
||||||
|
self.assertEqual({'groupname': 'missing', 'deleted': False}, result)
|
||||||
|
|
||||||
|
def test_delete_ldap_group_if_empty_empty(self):
|
||||||
|
self.ldap_server.add({'cn=emptygroup,' + settings.GROUP_BASE_DN: {
|
||||||
|
'objectClass': ['posixGroup'],
|
||||||
|
'gidNumber': ['4712'],
|
||||||
|
'cn': ['existing'],
|
||||||
|
'description': ['existing test group'],
|
||||||
|
}})
|
||||||
|
result = delete_ldap_group_if_empty('emptygroup')
|
||||||
|
self.assertEqual({'groupname': 'emptygroup', 'deleted': True}, result)
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
self.ldap_server.get('cn=emptygroup,' + settings.GROUP_BASE_DN)
|
||||||
|
|
||||||
|
def test_delete_ldap_group_existing(self):
|
||||||
|
result = delete_ldap_group('existing')
|
||||||
|
self.assertEqual({'groupname': 'existing', 'deleted': True}, result)
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
self.ldap_server.get('cn=existing,' + settings.GROUP_BASE_DN)
|
||||||
|
|
||||||
|
def test_delete_ldap_group_missing(self):
|
||||||
|
result = delete_ldap_group('missing')
|
||||||
|
self.assertEqual({'groupname': 'missing', 'deleted': False}, result)
|
|
@ -3,7 +3,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings.local")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gvaldap.settings")
|
||||||
|
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
|
25
gvaldap/setup.cfg
Normal file
25
gvaldap/setup.cfg
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[pep8]
|
||||||
|
exclude = migrations
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
exclude = migrations
|
||||||
|
|
||||||
|
[coverage:run]
|
||||||
|
source = gvaldap,ldapentities,ldaptasks
|
||||||
|
branch = True
|
||||||
|
omit = */migrations/*,*/tests/*.py,*/tests.py,gvaldap.py
|
||||||
|
relative_files = True
|
||||||
|
|
||||||
|
[coverage:report]
|
||||||
|
show_missing = True
|
||||||
|
|
||||||
|
[coverage:html]
|
||||||
|
directory = ../coverage-report
|
||||||
|
|
||||||
|
[isort]
|
||||||
|
multi_line_output = 3
|
||||||
|
line_length = 88
|
||||||
|
known_django = django
|
||||||
|
known_third_party = celery,volatildap
|
||||||
|
include_trailing_comma = True
|
||||||
|
sections = FUTURE,STDLIB,THIRDPARTY,DJANGO,FIRSTPARTY,LOCALFOLDER
|
|
@ -1,3 +0,0 @@
|
||||||
# This file is here because many Platforms as a Service look for
|
|
||||||
# requirements.txt in the root directory of a project.
|
|
||||||
-r requirements/production.txt
|
|
|
@ -1,9 +0,0 @@
|
||||||
Django==1.7.4
|
|
||||||
django-ldapdb==0.3.2
|
|
||||||
bpython==0.13.2
|
|
||||||
django-braces==1.4.0
|
|
||||||
django-model-utils==2.2
|
|
||||||
logutils==0.3.3
|
|
||||||
celery==3.1.17
|
|
||||||
passlib==1.6.2
|
|
||||||
requests==2.5.1
|
|
|
@ -1,8 +0,0 @@
|
||||||
# Local development dependencies go here
|
|
||||||
-r base.txt
|
|
||||||
coverage==3.7.1
|
|
||||||
django-debug-toolbar==1.2.2
|
|
||||||
Sphinx==1.2.3
|
|
||||||
sqlparse==0.1.14
|
|
||||||
releases==0.7.0
|
|
||||||
Pygments==2.0.2
|
|
|
@ -1,3 +0,0 @@
|
||||||
# Pro-tip: Try not to put anything here. There should be no dependency in
|
|
||||||
# production that isn't in development.
|
|
||||||
-r base.txt
|
|
|
@ -1,3 +0,0 @@
|
||||||
# Test dependencies go here.
|
|
||||||
-r base.txt
|
|
||||||
coverage==3.7.1
|
|
36
salt/bootstrap.sh
Executable file
36
salt/bootstrap.sh
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh -
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y python-cryptography
|
||||||
|
|
||||||
|
# We just download the bootstrap script by default and execute that.
|
||||||
|
if [ -x /usr/bin/fetch ]; then
|
||||||
|
/usr/bin/fetch -o - https://raw.githubusercontent.com/saltstack/salt-bootstrap/stable/bootstrap-salt.sh | sh -s -- "$@"
|
||||||
|
elif [ -x /usr/bin/curl ]; then
|
||||||
|
/usr/bin/curl -L https://raw.githubusercontent.com/saltstack/salt-bootstrap/stable/bootstrap-salt.sh | sh -s -- "$@"
|
||||||
|
else
|
||||||
|
python \
|
||||||
|
-c 'import urllib; print urllib.urlopen("https://raw.githubusercontent.com/saltstack/salt-bootstrap/stable/bootstrap-salt.sh").read()' \
|
||||||
|
| sh -s -- "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >/etc/salt/minion <<EOF
|
||||||
|
file_client: local
|
||||||
|
|
||||||
|
file_roots:
|
||||||
|
base:
|
||||||
|
- /srv/salt/
|
||||||
|
|
||||||
|
pillar_roots:
|
||||||
|
base:
|
||||||
|
- /srv/pillar
|
||||||
|
|
||||||
|
log_file: file:///dev/log
|
||||||
|
EOF
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
cat >/etc/salt/grains <<EOF
|
||||||
|
roles:
|
||||||
|
- ldapserver
|
||||||
|
- gnuviechadmin.gvaldap
|
||||||
|
EOF
|
Loading…
Reference in a new issue