Index: python/univention-get-ldif-from-master.py =================================================================== --- python/univention-get-ldif-from-master.py (Revision 0) +++ python/univention-get-ldif-from-master.py (Revision 51193) @@ -0,0 +1,137 @@ +#!/usr/bin/python2.6 +# -*- coding: utf-8 -*- +# +# Univention Directory Listener +"""Read ldap from the DC master and create ldif file (and update local schema)""" +# +# Copyright 2004-2014 Univention GmbH +# +# http://www.univention.de/ +# +# All rights reserved. +# +# The source code of this program is made available +# under the terms of the GNU Affero General Public License version 3 +# (GNU AGPL V3) as published by the Free Software Foundation. +# +# Binary versions of this program provided by Univention to you as +# well as other copyrighted, protected or trademarked materials like +# Logos, graphics, fonts, specific documentations and configurations, +# cryptographic keys etc. are subject to a license agreement between +# you and Univention and not subject to the GNU AGPL V3. +# +# In the case you use this program under the terms of the GNU AGPL V3, +# the program is provided in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License with the Debian GNU/Linux or Univention distribution in file +# /usr/share/common-licenses/AGPL-3; if not, see +# . + +import univention.uldap as uldap +import univention.config_registry + +import ldap +import ldif +import sys +import os +import optparse + +from ldap.controls import LDAPControl +from ldap.controls import SimplePagedResultsControl + +sys.path.append("/usr/lib/univention-directory-listener/system/") +import replication + +# from replication.py +def _update_schema(attr): + fp = open('/var/lib/univention-ldap/schema.conf.new', 'w') + print >>fp, '# This schema was automatically replicated from the master server' + print >>fp, '# Please do not edit this file\n' + subschema = ldap.schema.SubSchema(attr) + for oid in replication.subschema_sort(subschema, ldap.schema.AttributeType): + if oid in replication.BUILTIN_OIDS: + continue + obj = subschema.get_obj(ldap.schema.AttributeType, oid) + print >>fp, 'attributetype', str(obj) + for oid in replication.subschema_sort(subschema, ldap.schema.ObjectClass): + if oid in replication.BUILTIN_OIDS: + continue + obj = subschema.get_obj(ldap.schema.ObjectClass, oid) + print >>fp, 'objectclass', str(obj) + fp.close() + os.rename('/var/lib/univention-ldap/schema.conf.new', '/var/lib/univention-ldap/schema.conf') + +# update the ldap schema file +def update_schema(lo): + res = lo.search(base="cn=Subschema", scope=ldap.SCOPE_BASE, filter='(objectclass=*)', attr=['+', '*']) + for r in res: + dn, data = r + _update_schema(data) + +# create ldif file from everything from lo +def create_ldif_from_master(lo, ldif_file, base, page_size): + + if os.path.isfile(ldif_file): + os.unlink(ldif_file) + + lc = SimplePagedResultsControl( + ldap.LDAP_CONTROL_PAGE_OID, True, (page_size,'') + ) + + msgid = lo.lo.search_ext(base, ldap.SCOPE_SUBTREE, '(objectclass=*)', ['+', '*'], serverctrls=[lc]) + fh = open(ldif_file, "w") + while True: + rtype, rdata, rmsgid, serverctrls = lo.lo.result3(msgid) + for i in rdata: + dn, data = i + fh.write(ldif.CreateLDIF(dn, data)) + fh.close() + pctrls = [ + c + for c in serverctrls + if c.controlType == ldap.LDAP_CONTROL_PAGE_OID + ] + if pctrls: + est, cookie = pctrls[0].controlValue + if cookie: + lc.controlValue = (page_size, cookie) + msgid = lo.lo.search_ext(base, ldap.SCOPE_SUBTREE, filter, attrs, serverctrls=[lc]) + else: + break + else: + print "Warning: Server ignores RFC 2696 control." + break + fh.close() + +if __name__ == "__main__": + + usage = "usage: %prog [options]\n" + parser = optparse.OptionParser(usage=usage) + parser.add_option("-l", "--ldif", dest="ldif", action="store_true", default=False, help="create ldif file") + parser.add_option("-s", "--schema", dest="schema", action="store_true", default=False, help="update ldap schema") + parser.add_option("-o", "--outfile", dest="outfile", default="/var/lib/univention-directory-listener/master.ldif", help="file to store ldif data") + parser.add_option("-p", "--pagesize", dest="pagesize", type="int", default=10000, help="page size to use for ldap paged search") + opts, args = parser.parse_args() + + ucr = univention.config_registry.ConfigRegistry() + ucr.load() + base = ucr.get("ldap/base") + lo = uldap.getMachineConnection(ldap_master = True) + + if opts.schema: + sys.stdout.write("updating schema ...") + sys.stdout.flush() + update_schema(lo) + sys.stdout.write(" OK\n") + + if opts.ldif: + sys.stdout.write("creating ldif file %s ..." % opts.outfile) + sys.stdout.flush() + create_ldif_from_master(lo, opts.outfile, base, opts.pagesize) + sys.stdout.write(" OK\n") + + sys.exit(0) Eigenschaftsänderungen: python/univention-get-ldif-from-master.py ___________________________________________________________________ Hinzugefügt: svn:executable + * Index: 03univention-directory-listener.inst =================================================================== --- 03univention-directory-listener.inst (Revision 51192) +++ 03univention-directory-listener.inst (Revision 51193) @@ -80,8 +80,62 @@ fi options="$options -ZZ -d $debugLevel" -options="$options -i -h $ldap_master -b "$ldap_base" -m $moduledir -c $cachedir" +# 1: fake replication.py initialization on non master systems +# init the listener without replication.py, instead slapadd a ldif +# file to the local ldap +if [ -n "$server_role" -a "$server_role" != "domaincontroller_master" ]; then + invoke-rc.d slapd stop + invoke-rc.d univention-directory-listener stop + # update schema + /usr/share/univention-directory-listener/univention-get-ldif-from-master.py -s + + # get and store notifier id to get changes during initialization + notifier_id_master="$(/usr/share/univention-directory-listener/get_notifier_id.py)" || exit 1 + + # check if we use a pre-defined ldif or if we create the ldif + def_notifier_id="$(ucr get listener/join/notifier/id)" + def_ldif="$(ucr get listener/join/ldif/file)" + if [ -n "$def_ldif" -a -n "$def_notifier_id" -a -e "$def_ldif" ]; then + # use local ldif file and defined id + echo "using pre-defined ldif and notifier id" + notifier_id="$def_notifier_id" + ldif="$def_ldif" + + else + echo "creating ldif file" + notifier_id="$notifier_id_master" + ldif="/var/lib/univention-directory-listener/master.ldif" + /usr/share/univention-directory-listener/univention-get-ldif-from-master.py -l -o "$ldif" + fi + + echo "using $ldif as ldif file for fake replication.py initialization" + echo "using $notifier_id as notifier_id file for fake replication.py initialization" + + # set notifier id + echo $notifier_id > /var/lib/univention-directory-listener/notifier_id + chown listener /var/lib/univention-directory-listener/notifier_id + + # update local ldap + rm /var/lib/univention-ldap/ldap/* + ucr commit /var/lib/univention-ldap/ldap/DB_CONFIG + slapadd -q -l "$ldif" || exit 1 + sync + invoke-rc.d slapd start + #rm "$ldif" + + # fake replication handler initialization + mkdir -p /var/lib/univention-directory-listener/handlers/ + echo 3 > /var/lib/univention-directory-listener/handlers/replication + chown -R listener /var/lib/univention-directory-listener/handlers/ + + # fake listener initialization (-P) + options="$options -P -h $ldap_master -b "$ldap_base" -m $moduledir -c $cachedir" +else + # real listener initialization + options="$options -i -h $ldap_master -b "$ldap_base" -m $moduledir -c $cachedir" +fi + if [ -n "$server_role" ]; then if [ "$server_role" = "domaincontroller_master" -o "$server_role" = "domaincontroller_backup" ]; then /usr/sbin/univention-directory-listener $options -D "cn=admin,$ldap_base" -y /etc/ldap.secret @@ -94,6 +148,18 @@ exit_status=$? +# 2: fake replication.py initialization on non master systems +# copy listener cache (if defined), because cache without replication.py +# is not fully filled +if [ -n "$server_role" -a "$server_role" != "domaincontroller_master" ]; then + lcache="$(ucr get listener/join/cache/file)" + if [ -n "$lcache" -a -e "$lcache" ]; then + cp "$lcache" /var/lib/univention-directory-listener/cache.db + chown listener:nogroup /var/lib/univention-directory-listener/cache.db + chmod 600 /var/lib/univention-directory-listener/cache.db + fi +fi + univention-config-registry set ldap/database/ldbm/dbsync=$ldap_database_ldbm_dbsync # needed for db sync @@ -118,6 +184,27 @@ # The samba join script needs a running listener. Bug #19128 /etc/init.d/univention-directory-listener start +# 3: fake replication.py initialization on non master systems +# wait until local notifier id is equal to notifier id of the master +# before the fake replication.py +# otherwise if we use listener/join/notifier/id we could miss +# the password change for the local host account +if [ -n "$server_role" -a "$server_role" != "domaincontroller_master" ]; then + while true; do + echo "waiting for replication" + lid="$(cat /var/lib/univention-directory-listener/notifier_id)" + if [ 1 -eq $(echo "$lid >= $notifier_id_master" | bc) ]; then + break + fi + # wait for max 2hrs + timeout=$(($timeout + 1)) + if [ $timeout -ge 7200 ]; then + break + fi + sleep 1 + done +fi + test -x /usr/sbin/nscd && /usr/sbin/nscd -i passwd test -x /usr/sbin/nscd && /usr/sbin/nscd -i group Index: debian/univention-directory-listener.install =================================================================== --- debian/univention-directory-listener.install (Revision 51192) +++ debian/univention-directory-listener.install (Revision 51193) @@ -3,6 +3,7 @@ src/verify usr/sbin/ src/listener-ctrl usr/sbin/ python/get_notifier_id.py usr/share/univention-directory-listener/ +python/univention-get-ldif-from-master.py usr/share/univention-directory-listener/ python/ldap_server.py usr/lib/univention-directory-listener/system/ python/listener.py usr/lib/python2.6/site-packages/ 03univention-directory-listener.inst usr/lib/univention-install/