[Checkins] SVN: z3c.recipe.ldap/trunk/ slapd instance tests
passing. Need to finish slapadd.
Ross Patterson
me at rpatterson.net
Sun Dec 9 08:55:30 EST 2007
Log message for revision 82210:
slapd instance tests passing. Need to finish slapadd.
Changed:
U z3c.recipe.ldap/trunk/setup.py
U z3c.recipe.ldap/trunk/z3c/recipe/ldap/__init__.py
U z3c.recipe.ldap/trunk/z3c/recipe/ldap/docs/README.txt
A z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapadd.py
A z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapd.py
U z3c.recipe.ldap/trunk/z3c/recipe/ldap/tests/test_docs.py
-=-
Modified: z3c.recipe.ldap/trunk/setup.py
===================================================================
--- z3c.recipe.ldap/trunk/setup.py 2007-12-09 05:22:30 UTC (rev 82209)
+++ z3c.recipe.ldap/trunk/setup.py 2007-12-09 13:55:29 UTC (rev 82210)
@@ -14,10 +14,9 @@
long_description = open(README).read() + '\n\n'
-entry_point = 'z3c.recipe.ldap:Recipe'
+entry_points = {"zc.buildout": ["default = z3c.recipe.ldap:Slapd",
+ "slapadd = z3c.recipe.ldap:Slapadd"]}
-entry_points = {"zc.buildout": ["default = %s" % entry_point]}
-
setup(name='z3c.recipe.ldap',
version=version,
description="Deploy an OpenLDAP serve in a zc.buildout",
@@ -37,8 +36,8 @@
include_package_data=True,
zip_safe=True,
install_requires=['setuptools',
- 'zope.testing',
- 'zc.buildout'
+ 'zc.buildout',
+ 'zc.recipe.egg'
# -*- Extra requirements: -*-
],
entry_points=entry_points,
Modified: z3c.recipe.ldap/trunk/z3c/recipe/ldap/__init__.py
===================================================================
--- z3c.recipe.ldap/trunk/z3c/recipe/ldap/__init__.py 2007-12-09 05:22:30 UTC (rev 82209)
+++ z3c.recipe.ldap/trunk/z3c/recipe/ldap/__init__.py 2007-12-09 13:55:29 UTC (rev 82210)
@@ -1,19 +1,4 @@
-# -*- coding: utf-8 -*-
-"""Recipe ldap"""
+"""z3c.recipe.ldap"""
-class Recipe(object):
- """This recipe is used by zc.buildout"""
-
- def __init__(self, buildout, name, options):
- self.name, self.options = name, options
-
- def install(self):
- """installer"""
- # XXX do the job here
- # returns installed files
- return tuple()
-
- def update(self):
- """updater"""
- pass
-
+from slapd import Slapd
+from slapadd import Slapadd
Modified: z3c.recipe.ldap/trunk/z3c/recipe/ldap/docs/README.txt
===================================================================
--- z3c.recipe.ldap/trunk/z3c/recipe/ldap/docs/README.txt 2007-12-09 05:22:30 UTC (rev 82209)
+++ z3c.recipe.ldap/trunk/z3c/recipe/ldap/docs/README.txt 2007-12-09 13:55:29 UTC (rev 82210)
@@ -17,3 +17,198 @@
How to use z3c.recipe.ldap ?
============================
+-------------------------
+Installing slapd instance
+-------------------------
+
+The default recipe in z3c.recipe.ldap can be used to deploy a slapd
+LDAP server in the buildout. Options in the slapd part not used by
+the recipe itself will be used to create and populate a slapd.conf
+file.
+
+The only required option is the suffix argupent. Specifying the
+suffix with a dc requires that the "dc" LDAP attribute type
+configuration. Write a buildout.cfg with a suffix and including the
+attribute type configuration. Also specify that the server should use
+a socket instead of a network port::
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = slapd
+ ...
+ ... [slapd]
+ ... recipe = z3c.recipe.ldap
+ ... use-socket = True
+ ... include =
+ ... foo.schema
+ ... bar.conf
+ ... suffix = "dc=localhost"
+ ... """)
+
+Create the files to be included::
+
+ >>> write(sample_buildout, 'foo.schema',
+ ... """
+ ... attributetype ( 0.9.2342.19200300.100.1.25
+ ... NAME ( 'dc' 'domainComponent' )
+ ... DESC 'RFC1274/2247: domain component'
+ ... EQUALITY caseIgnoreIA5Match
+ ... SUBSTR caseIgnoreIA5SubstringsMatch
+ ... SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+ ... """)
+ >>> write(sample_buildout, 'bar.conf', '\n')
+
+Run the buildout::
+
+ >>> print system(buildout),
+ Installing slapd.
+ Generated script '/sample-buildout/bin/slapd'.
+
+The configuration file is created in the part by default. Note that
+keys that can be specified multiple times in slapd.conf, such as
+include, will be constitued from multiple line separated values when
+present. Also note that keys that contain file paths in slapd.conf,
+such as include, will be expanded from the buildout directory::
+
+ >>> ls(sample_buildout, 'parts', 'slapd')
+ - slapd.conf
+ >>> cat(sample_buildout, 'parts', 'slapd', 'slapd.conf')
+ include /sample-buildout/foo.schema
+ include /sample-buildout/bar.conf...
+
+An empty directory is created for the LDAP database::
+
+ >>> ls(sample_buildout, 'var')
+ d slapd
+ >>> ls(sample_buildout, 'var', 'slapd')
+
+A script is also created for starting and stopping the slapd server::
+
+ >>> ls(sample_buildout, 'bin')
+ - buildout
+ - slapd
+
+Start the slapd server::
+
+ >>> bin = join(sample_buildout, 'bin', 'slapd')
+ >>> print system(bin+' start'),
+
+On first run, the LDAP database is created::
+
+ >>> ls(sample_buildout, 'var', 'slapd')
+ - __db.001...
+
+While the server is running a pid file is created::
+
+ >>> ls(sample_buildout, 'parts', 'slapd')
+ - slapd.conf
+ - slapd.pid
+
+Stop the slapd server::
+
+ >>> print system(bin+' stop'),
+
+Wait for it to shutdown::
+
+ >>> import time
+ >>> time.sleep(0.1)
+
+When the slapd server finishes shutting down the pid file is deleted::
+
+ >>> ls(sample_buildout, 'parts', 'slapd')
+ - slapd.conf
+
+Specifying the slapd binary
+---------------------------
+
+The slapd binary to be used can be specified. A buildout could, for
+example, include a part using a CMMI recipe and use the slapd binary
+from that build.
+
+Before specifying the slapd to use, it's left up to the environment::
+
+ >>> cat(sample_buildout, '.installed.cfg')
+ [buildout]...
+ [slapd]...
+ slapd = slapd...
+
+Specify a slapd in the buildout.cfg::
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = slapd
+ ...
+ ... [slapd]
+ ... recipe = z3c.recipe.ldap
+ ... slapd = /usr/sbin/slapd
+ ... use-socket = True
+ ... include =
+ ... foo.schema
+ ... bar.conf
+ ... suffix = "dc=localhost"
+ ... """)
+
+Run the buildout::
+
+ >>> print system(buildout),
+ Uninstalling slapd.
+ Installing slapd.
+ Generated script '/sample-buildout/bin/slapd'.
+
+Now it uses the specific slapd binary::
+
+ >>> cat(sample_buildout, '.installed.cfg')
+ [buildout]...
+ [slapd]...
+ slapd = /usr/sbin/slapd...
+
+----------------------------
+Initalizing an LDAP database
+----------------------------
+
+In the simplest form, simply provide an ldif arguemnt in the part with
+one or more filenames.
+
+ >>> write(sample_buildout, 'foo.ldif',
+ ... """
+ ... olcAttributeTypes: ( 0.9.2342.19200300.100.1.25
+ ... NAME ( 'dc' 'domainComponent' )
+ ... DESC 'RFC1274/2247: domain component'
+ ... EQUALITY caseIgnoreIA5Match
+ ... SUBSTR caseIgnoreIA5SubstringsMatch
+ ... SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+ ... """)
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = slapd slapadd
+ ...
+ ... [slapd]
+ ... recipe = z3c.recipe.ldap
+ ... include =
+ ... foo.schema
+ ... suffix = "dc=localhost"
+ ...
+ ... [slapadd]
+ ... recipe = z3c.recipe.ldap:slapadd
+ ... conf = ${slapd:conf}
+ ... ldif = foo.ldif
+ ... """)
+
+ >>> print system(buildout),
+ Uninstalling slapd.
+ Installing slapd.
+ Generated script '/sample-buildout/bin/slapd'.
+ Installing slapadd.
+
+Multiple LDIF files can be specified::
+
+ >>> TODO
+
+An alternate open ldap instance directory can be specified in the
+'directory' option::
+
+ >>> TODO
\ No newline at end of file
Copied: z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapadd.py (from rev 82208, z3c.recipe.ldap/trunk/z3c/recipe/ldap/__init__.py)
===================================================================
--- z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapadd.py (rev 0)
+++ z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapadd.py 2007-12-09 13:55:29 UTC (rev 82210)
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+"""Recipe slapadd"""
+
+import os
+
+class Slapadd(object):
+ """This recipe is used by zc.buildout"""
+
+ def __init__(self, buildout, name, options):
+ self.name, self.options = name, options
+
+ self.ldifs = [
+ os.path.join(buildout['buildout']['directory'],
+ ldif.strip())
+ for ldif in options['ldif'].split('\n') if ldif.strip()]
+ options['ldif'] = '\n'.join(self.ldifs)
+
+ var = options.get('var')
+ if var is None:
+ self.var = options['var'] = os.path.join(
+ buildout['buildout']['directory'],
+ 'var', self.name)
+ else:
+ self.var = options['var'] = os.path.join(
+ buildout['buildout']['directory'], var)
+
+ def install(self):
+ """installer"""
+ if not os.path.exists(self.var):
+ os.mkdir(self.var)
+
+ return tuple()
+
+ def update(self):
+ """updater"""
+ pass
+
Copied: z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapd.py (from rev 82208, z3c.recipe.ldap/trunk/z3c/recipe/ldap/__init__.py)
===================================================================
--- z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapd.py (rev 0)
+++ z3c.recipe.ldap/trunk/z3c/recipe/ldap/slapd.py 2007-12-09 13:55:29 UTC (rev 82210)
@@ -0,0 +1,150 @@
+# -*- coding: utf-8 -*-
+"""Recipe ldap"""
+
+import sys, os, signal, subprocess
+
+import zc.buildout
+import zc.recipe.egg
+
+class Slapd(object):
+ """This recipe is used by zc.buildout"""
+
+ def __init__(self, buildout, name, options):
+ self.egg = zc.recipe.egg.Egg(buildout, options['recipe'], options)
+ self.name, self.options = name, options
+
+ options['location'] = os.path.join(
+ buildout['buildout']['parts-directory'], name)
+
+ if 'slapd' in options:
+ options['slapd'] = os.path.join(
+ buildout['buildout']['directory'], options['slapd'])
+ else:
+ options['slapd'] = 'slapd'
+
+ if 'conf' not in options:
+ options['conf'] = os.path.join(
+ options['location'], name+'.conf')
+
+ if 'pidfile' not in options:
+ options['pidfile'] = os.path.join(
+ options['location'], name+'.pid')
+
+ if 'directory' not in options:
+ options['directory'] = os.path.join(
+ buildout['buildout']['directory'], 'var', name)
+
+ if 'urls' in options and 'use-socket' in options:
+ raise ValueError('Cannot specify both the "urls" and '
+ '"use-socket" options')
+ if 'use-socket' in options:
+ options['urls'] = 'ldapi:/%s' % os.path.join(
+ options['location'], name+'.socket')
+
+ # Initialize the conf options
+ init_conf_options(
+ options, dir=buildout['buildout']['directory'])
+
+ def install(self):
+ """installer"""
+ # Install slapd.conf
+ os.makedirs(self.options['location'])
+ conf = file(self.options['conf'], 'w')
+ conf.writelines(get_conf_lines(self.options))
+ conf.close()
+
+ if not os.path.exists(self.options['directory']):
+ # Install the DB dir
+ os.makedirs(self.options['directory'])
+
+ # Install the control script
+ _, ws = self.egg.working_set(['z3c.recipe.ldap'])
+ zc.buildout.easy_install.scripts(
+ [(self.name, 'z3c.recipe.ldap.slapd', 'ctl')],
+ ws, self.options['executable'],
+ self.options['bin-directory'],
+ arguments=repr(self.options))
+
+ return (self.options['location'],)
+
+ def update(self):
+ """updater"""
+ pass
+
+conf_exclude = [
+ 'slapd', 'conf', 'urls', 'recipe', 'location', 'executable',
+ 'bin-directory', 'eggs-directory', 'develop-eggs-directory',
+ '_e', '_d', '_b']
+conf_paths = [
+ 'include', 'pidfile', 'argsfile', 'directory', 'modulepath']
+conf_multiple = ['include', 'moduleload', 'access', 'index']
+conf_defaults = [('modulepath', '/usr/lib/ldap'),
+ ('moduleload', 'back_bdb'),
+ ('database', 'bdb'),
+ ('index', 'objectClass\teq')]
+conf_order = [
+ 'include', 'pidfile', 'argsfile', 'access', 'modulepath',
+ 'moduleload', 'database', 'suffix', 'directory', 'index']
+
+def init_conf_options(options, dir='.', exclude=conf_exclude,
+ paths=conf_paths, multiple=conf_multiple,
+ defaults=conf_defaults):
+ for key, value in defaults:
+ if key not in options:
+ options[key] = value
+
+ for key, value in options.iteritems():
+ if key in exclude:
+ continue
+
+ if key in multiple:
+ values = []
+ for v in value.split('\n'):
+ v = v.strip()
+ if not v:
+ continue
+ if key in paths:
+ # expand file paths
+ v = os.path.join(dir, v)
+ values.append(v)
+ options[key] = '\n'.join(values)
+ continue
+
+ if key in paths:
+ options[key] = os.path.join(dir, value)
+
+def order_keys(keys, order=conf_order):
+ for key in order:
+ if key in keys:
+ yield key
+ for key in keys:
+ if key not in order:
+ yield key
+
+def get_conf_lines(options, exclude=conf_exclude,
+ multiple=conf_multiple, template='%s\t%s\n'):
+ for key in order_keys(options):
+ if key in exclude:
+ continue
+
+ value = options[key]
+ if key in multiple:
+ for v in value.split('\n'):
+ yield template % (key, v)
+ else:
+ yield template % (key, value)
+
+def ctl(options):
+ command, = sys.argv[1:]
+ if command.lower() == 'start':
+ args = [options['slapd'], '-f', options['conf']]
+ if 'urls' in options:
+ args.extend(['-h', options['urls']])
+ subprocess.Popen(args)
+ elif command.lower() == 'stop':
+ pidfile = file(options['pidfile'])
+ pid = int(pidfile.read())
+ pidfile.close()
+ os.kill(pid, signal.SIGTERM)
+ else:
+ raise ValueError('Command %s unsupported' % command)
Modified: z3c.recipe.ldap/trunk/z3c/recipe/ldap/tests/test_docs.py
===================================================================
--- z3c.recipe.ldap/trunk/z3c/recipe/ldap/tests/test_docs.py 2007-12-09 05:22:30 UTC (rev 82209)
+++ z3c.recipe.ldap/trunk/z3c/recipe/ldap/tests/test_docs.py 2007-12-09 13:55:29 UTC (rev 82210)
@@ -9,20 +9,26 @@
import sys
import os
-from zope.testing import doctest
+from zope.testing import doctest, renormalizing
+import zc.buildout.testing
current_dir = os.path.dirname(__file__)
-def doc_suite(test_dir, setUp=None, tearDown=None, globs=None):
+def setUp(test):
+ zc.buildout.testing.buildoutSetUp(test)
+ zc.buildout.testing.install_develop('zc.recipe.egg', test)
+ zc.buildout.testing.install_develop('z3c.recipe.ldap', test)
+
+def doc_suite(test_dir, setUp=setUp,
+ tearDown=zc.buildout.testing.buildoutTearDown,
+ globs=None):
"""Returns a test suite, based on doctests found in /doctest."""
- suite = []
if globs is None:
globs = globals()
globs['test_dir'] = current_dir
- flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE |
- doctest.REPORT_ONLY_FIRST_FAILURE)
+ flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE)
package_dir = os.path.split(test_dir)[0]
if package_dir not in sys.path:
@@ -34,14 +40,14 @@
docs = [os.path.join(doctest_dir, doc) for doc in
os.listdir(doctest_dir) if doc.endswith('.txt')]
- for test in docs:
- suite.append(doctest.DocFileSuite(test, optionflags=flags,
- globs=globs, setUp=setUp,
- tearDown=tearDown,
- module_relative=False))
+ return unittest.TestSuite(
+ doctest.DocFileSuite(
+ test, optionflags=flags, globs=globs, setUp=setUp,
+ tearDown=tearDown, module_relative=False,
+ checker=renormalizing.RENormalizing([
+ zc.buildout.testing.normalize_path]))
+ for test in docs)
- return unittest.TestSuite(suite)
-
def test_suite():
"""returns the test suite"""
return doc_suite(current_dir)
More information about the Checkins
mailing list