summaryrefslogtreecommitdiffstats
path: root/ipa-server/ipa-ldap-updater
diff options
context:
space:
mode:
Diffstat (limited to 'ipa-server/ipa-ldap-updater')
-rwxr-xr-xipa-server/ipa-ldap-updater103
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