summaryrefslogtreecommitdiffstats
path: root/ipaserver/install/installutils.py
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2015-10-05 14:37:05 +0200
committerMartin Basti <mbasti@redhat.com>2015-10-15 18:37:52 +0200
commit63638ac9a32b528677694b438b276812e75917c4 (patch)
tree1d2d3434f67527d31ae36f2ce5744048480091f8 /ipaserver/install/installutils.py
parent9e007edbd902a5395797ca0ca9a698033540d755 (diff)
downloadfreeipa-63638ac9a32b528677694b438b276812e75917c4.tar.gz
freeipa-63638ac9a32b528677694b438b276812e75917c4.tar.xz
freeipa-63638ac9a32b528677694b438b276812e75917c4.zip
Make offline LDIF modify more robust
* move code to installutils * add replace_value method * use lists instead of single values for add_value, remove_value methods https://fedorahosted.org/freeipa/ticket/4949 Also fixes: https://fedorahosted.org/freeipa/ticket/4048 https://fedorahosted.org/freeipa/ticket/1930 Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
Diffstat (limited to 'ipaserver/install/installutils.py')
-rw-r--r--ipaserver/install/installutils.py98
1 files changed, 98 insertions, 0 deletions
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 52a110bb9..8e9e43d15 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -23,6 +23,7 @@ from __future__ import print_function
import socket
import getpass
import gssapi
+import ldif
import os
import re
import fileinput
@@ -1215,3 +1216,100 @@ def check_creds(options, realm_name):
raise ScriptError("Invalid credentials: %s" % e)
os.environ['KRB5CCNAME'] = ccache_name
+
+
+class ModifyLDIF(ldif.LDIFParser):
+ """
+ Allows to modify LDIF file.
+
+ Operations keep the order in which were specified per DN.
+ Warning: only modifications of existing DNs are supported
+ """
+ def __init__(self, input_file, output_file):
+ """
+ :param input_file: an LDIF
+ :param output_file: an LDIF file
+ """
+ ldif.LDIFParser.__init__(self, input_file)
+ self.writer = ldif.LDIFWriter(output_file)
+ self.dn_updated = set()
+
+ self.modifications = {} # keep modify operations in original order
+
+ def add_value(self, dn, attr, values):
+ """
+ Add value to LDIF.
+ :param dn: DN of entry (must exists)
+ :param attr: attribute name
+ :param value: value to be added
+ """
+ assert isinstance(values, list)
+ self.modifications.setdefault(dn, []).append(
+ dict(
+ op="add",
+ attr=attr,
+ values=values,
+ )
+ )
+
+ def remove_value(self, dn, attr, values=None):
+ """
+ Remove value from LDIF.
+ :param dn: DN of entry
+ :param attr: attribute name
+ :param value: value to be removed, if value is None, attribute will
+ be removed
+ """
+ assert values is None or isinstance(values, list)
+ self.modifications.setdefault(dn, []).append(
+ dict(
+ op="del",
+ attr=attr,
+ values=values,
+ )
+ )
+
+ def replace_value(self, dn, attr, values):
+ """
+ Replace values in LDIF with new value.
+ :param dn: DN of entry
+ :param attr: attribute name
+ :param value: new value for atribute
+ """
+ assert isinstance(values, list)
+ self.remove_value(dn, attr)
+ self.add_value(dn, attr, values)
+
+ def handle(self, dn, entry):
+ if dn in self.modifications:
+ self.dn_updated.add(dn)
+ for mod in self.modifications.get(dn, []):
+ attr_name = mod["attr"]
+ values = mod["values"]
+
+ if mod["op"] == "del":
+ # delete
+ attribute = entry.setdefault(attr_name, [])
+ if values is None:
+ attribute = []
+ else:
+ attribute = [v for v in attribute if v not in values]
+ if not attribute: # empty
+ del entry[attr_name]
+ elif mod["op"] == "add":
+ # add
+ attribute = entry.setdefault(attr_name, [])
+ attribute.extend([v for v in values if v not in attribute])
+ else:
+ assert False, "Unknown operation: %r" % mod["op"]
+
+ self.writer.unparse(dn, entry)
+
+ def parse(self):
+ ldif.LDIFParser.parse(self)
+
+ # check if there are any remaining modifications
+ remaining_changes = set(self.modifications.keys()) - self.dn_updated
+ for dn in remaining_changes:
+ root_logger.error(
+ "DN: %s does not exists or haven't been updated", dn)