summaryrefslogtreecommitdiffstats
path: root/ipa-server/ipa-ldap-updater
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2008-09-12 18:40:26 -0400
committerRob Crittenden <rcritten@redhat.com>2008-09-12 20:07:48 -0400
commit88960f1597eb4516186bebd1aa624806c55895c1 (patch)
tree7ff4e42741a89e6fedc824118bc1974be3e292f3 /ipa-server/ipa-ldap-updater
parent1eec34393b8a7ccd420a7fa540462f5d8779977c (diff)
downloadfreeipa-88960f1597eb4516186bebd1aa624806c55895c1.tar.gz
freeipa-88960f1597eb4516186bebd1aa624806c55895c1.tar.xz
freeipa-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-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