diff options
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 cd6cd2eee..86a9fe9b1 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 |