diff options
author | Rob Crittenden <rcritten@redhat.com> | 2008-09-12 18:40:26 -0400 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2008-09-12 20:07:48 -0400 |
commit | 88960f1597eb4516186bebd1aa624806c55895c1 (patch) | |
tree | 7ff4e42741a89e6fedc824118bc1974be3e292f3 /ipa-server/ipa-ldap-updater | |
parent | 1eec34393b8a7ccd420a7fa540462f5d8779977c (diff) | |
download | freeipa.git-88960f1597eb4516186bebd1aa624806c55895c1.tar.gz freeipa.git-88960f1597eb4516186bebd1aa624806c55895c1.tar.xz freeipa.git-88960f1597eb4516186bebd1aa624806c55895c1.zip |
Sort updates by DN length and by default process all files in the updates dir.
The updates directory is currently hardcoded to /usr/share/ipa/updates.
All of the files are read into memory and then sorted by the length of the DN.
This is so we can be sure that parent entries are added before children.
Also add a man page.
Diffstat (limited to 'ipa-server/ipa-ldap-updater')
-rwxr-xr-x | ipa-server/ipa-ldap-updater | 103 |
1 files changed, 81 insertions, 22 deletions
diff --git a/ipa-server/ipa-ldap-updater b/ipa-server/ipa-ldap-updater index cd6cd2ee..86a9fe9b 100755 --- a/ipa-server/ipa-ldap-updater +++ b/ipa-server/ipa-ldap-updater @@ -23,6 +23,8 @@ # TODO # save undo files? +UPDATES_DIR="/usr/share/ipa/updates/" + import sys try: from optparse import OptionParser @@ -37,6 +39,8 @@ try: import shlex import time import random + import os + import fnmatch except ImportError: print >> sys.stderr, """\ There was a problem importing one of the required Python modules. The @@ -57,7 +61,9 @@ class BadSyntax(Exception): return repr(self.value) def parse_options(): - parser = OptionParser("%prog [options] input_file(s)") + usage = "%prog [options] input_file(s)\n" + usage += "%prog [options]\n" + parser = OptionParser(usage=usage, formatter=config.IPAFormatter()) parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Display debugging information about the update(s)") @@ -67,8 +73,6 @@ def parse_options(): config.add_standard_options(parser) options, args = parser.parse_args() - if len(args) < 1: - parser.error("missing file operand") config.init_config(options) return options, args @@ -186,7 +190,38 @@ def entry_to_entity(ent): entry[key] = value[0] return entity.Entity(entry) -def parse_update_file(conn, data): +def combine_updates(dn_list, all_updates, update): + """Combine a new update with the list of total updates + + Updates are stored in 2 lists: + dn_list: contains a unique list of DNs in the updates + all_updates: the actual updates that need to be applied + + We want to apply the updates from the shortest to the longest + path so if new child and parent entries are in different updates + we can be sure the parent gets written first. This also lets + us apply any schema first since it is in the very short cn=schema. + """ + dn = update.get('dn') + dns = ldap.explode_dn(dn.lower()) + l = len(dns) + if dn_list.get(l): + if dn not in dn_list[l]: + dn_list[l].append(dn) + else: + dn_list[l] = [dn] + if not all_updates.get(dn): + all_updates[dn] = update + return all_updates + + e = all_updates[dn] + e['updates'] = e['updates'] + update['updates'] + + all_updates[dn] = e + + return all_updates + +def parse_update_file(conn, data, all_updates, dn_list): """Parse the update file into a dictonary of lists and apply the update for each DN in the file.""" valid_keywords = ["default", "add", "remove", "only"] @@ -203,7 +238,7 @@ def parse_update_file(conn, data): if line.lower().startswith('dn:'): if dn is not None: - update_record(conn, update) + all_updates = combine_updates(dn_list, all_updates, update) update = {} dn = line[3:].strip() @@ -246,9 +281,9 @@ def parse_update_file(conn, data): update[index] = d if dn is not None: - update_record(conn, update) + all_updates = combine_updates(dn_list, all_updates, update) - return + return (all_updates, dn_list) def create_index_task(conn, attribute): """Create a task to update an index for an attribute""" @@ -487,6 +522,17 @@ def update_record(conn, update): monitor_index_task(conn, id) return +def get_all_files(root, recursive=False): + """Get all update files""" + f = [] + for path, subdirs, files in os.walk(root): + for name in files: + if fnmatch.fnmatch(name, "*.update"): + f.append(os.path.join(path, name)) + if not recursive: + break + return f + def main(): global sub_dict, live_run loglevel = logging.INFO @@ -521,22 +567,35 @@ def main(): dirman_password = get_dirman_password(fqdn) - for a in args: - try: - logging.info("Parsing file %s" % a) - data = read_file(a) - except Exception, e: - print e - sys.exit(1) - - conn = None + files=[] + if len(args) < 1: + files = get_all_files(UPDATES_DIR) + else: + files = args - try: - conn = ipaldap.IPAdmin(fqdn) - conn.do_simple_bind(bindpw=dirman_password) - parse_update_file(conn, data) - finally: - if conn: conn.unbind() + conn = None + try: + conn = ipaldap.IPAdmin(fqdn) + conn.do_simple_bind(bindpw=dirman_password) + all_updates = {} + dn_list = {} + for f in files: + try: + logging.info("Parsing file %s" % f) + data = read_file(f) + except Exception, e: + print e + sys.exit(1) + + (all_updates, dn_list) = parse_update_file(conn, data, all_updates, dn_list) + + sortedkeys = dn_list.keys() + sortedkeys.sort() + for k in sortedkeys: + for dn in dn_list[k]: + update_record(conn, all_updates[dn]) + finally: + if conn: conn.unbind() return |