diff options
author | Martin Basti <mbasti@redhat.com> | 2015-04-28 10:04:31 +0200 |
---|---|---|
committer | Petr Vobornik <pvoborni@redhat.com> | 2015-05-05 11:56:49 +0200 |
commit | 882ce85ad566a1f426398ce346829b1a4dcb5422 (patch) | |
tree | 48c4f1a899dd7359c92ef5d9a031c87ac19915f0 /ipaserver/install | |
parent | 522cbb23f129033f836e40282ca41e76d315cbe3 (diff) | |
download | freeipa-882ce85ad566a1f426398ce346829b1a4dcb5422.tar.gz freeipa-882ce85ad566a1f426398ce346829b1a4dcb5422.tar.xz freeipa-882ce85ad566a1f426398ce346829b1a4dcb5422.zip |
Server Upgrade: use LDIF parser to modify DSE.ldif
Ticket: https://fedorahosted.org/freeipa/ticket/4925
Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
Diffstat (limited to 'ipaserver/install')
-rw-r--r-- | ipaserver/install/upgradeinstance.py | 185 |
1 files changed, 165 insertions, 20 deletions
diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py index 08d5e91fb..f70312f09 100644 --- a/ipaserver/install/upgradeinstance.py +++ b/ipaserver/install/upgradeinstance.py @@ -17,6 +17,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +import ldif import os import sys import shutil @@ -32,6 +33,116 @@ from ipaserver.install import service DSE = 'dse.ldif' + +class GetEntryFromLDIF(ldif.LDIFParser): + """ + LDIF parser. + To get results, method parse() must be called first, then method + get_results() which return parsed entries + """ + def __init__(self, input_file, entries_dn=[]): + """ + Parse LDIF file. + :param input_file: an LDIF file to be parsed + :param entries_dn: list of DN which will be returned. All entries are + returned if list is empty. + """ + ldif.LDIFParser.__init__(self, input_file) + self.entries_dn = entries_dn + self.results = {} + + def get_results(self): + """ + Returns results in dictionary {DN: entry, ...} + """ + return self.results + + def handle(self, dn, entry): + if self.entries_dn and dn not in self.entries_dn: + return + + self.results[dn] = entry + + +class ModifyLDIF(ldif.LDIFParser): + """ + Allows to modify LDIF file. + + Remove operations are executed before add operations + """ + def __init__(self, input_file, writer): + """ + :param input_file: an LDIF + :param writer: ldif.LDIFWriter instance where modified LDIF will + be written + """ + ldif.LDIFParser.__init__(self, input_file) + self.writer = writer + + self.add_dict = {} + self.remove_dict = {} + + def add_value(self, dn, attr, value): + """ + Add value to LDIF. + :param dn: DN of entry (must exists) + :param attr: attribute name + :param value: value to be added + """ + attr = attr.lower() + entry = self.add_dict.setdefault(dn, {}) + attribute = entry.setdefault(attr, []) + if value not in attribute: + attribute.append(value) + + def remove_value(self, dn, attr, value=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 + """ + attr = attr.lower() + entry = self.remove_dict.setdefault(dn, {}) + + if entry is None: + return + attribute = entry.setdefault(attr, []) + if value is None: + # remove all values + entry[attr] = None + return + elif attribute is None: + # already marked to remove all values + return + if value not in attribute: + attribute.append(value) + + def handle(self, dn, entry): + if dn in self.remove_dict: + for name, value in self.remove_dict[dn].iteritems(): + if value is None: + attribute = [] + else: + attribute = entry.setdefault(name, []) + attribute = [v for v in attribute if v not in value] + entry[name] = attribute + + if not attribute: # empty + del entry[name] + + if dn in self.add_dict: + for name, value in self.add_dict[dn].iteritems(): + attribute = entry.setdefault(name, []) + attribute.extend([v for v in value if v not in attribute]) + + if not entry: # empty + return + + self.writer.unparse(dn, entry) + + class IPAUpgrade(service.Service): """ Update the LDAP data in an instance by turning off all network @@ -89,34 +200,68 @@ class IPAUpgrade(service.Service): def __save_config(self): shutil.copy2(self.filename, self.savefilename) - port = installutils.get_directive(self.filename, 'nsslapd-port', - separator=':') - security = installutils.get_directive(self.filename, 'nsslapd-security', - separator=':') + with open(self.filename, "rb") as in_file: + parser = GetEntryFromLDIF(in_file, entries_dn=["cn=config"]) + parser.parse() + try: + config_entry = parser.get_results()["cn=config"] + except KeyError: + raise RuntimeError("Unable to find cn=config entry in %s" % + self.filename) + + try: + port = config_entry['nsslapd-port'][0] + except KeyError: + pass + else: + self.backup_state('nsslapd-port', port) - self.backup_state('nsslapd-port', port) - self.backup_state('nsslapd-security', security) + try: + security = config_entry['nsslapd-security'][0] + except KeyError: + pass + else: + self.backup_state('nsslapd-security', security) def __restore_config(self): port = self.restore_state('nsslapd-port') security = self.restore_state('nsslapd-security') - if port is not None: - installutils.set_directive( - self.filename, 'nsslapd-port', port, - quotes=False, separator=':') - if security is not None: - installutils.set_directive( - self.filename, 'nsslapd-security', security, - quotes=False, separator=':') + ldif_outfile = "%s.modified.out" % self.filename + with open(ldif_outfile, "wb") as out_file: + ldif_writer = ldif.LDIFWriter(out_file) + with open(self.filename, "rb") as in_file: + parser = ModifyLDIF(in_file, ldif_writer) + + if port is not None: + parser.remove_value("cn=config", "nsslapd-port") + parser.add_value("cn=config", "nsslapd-port", port) + if security is not None: + parser.remove_value("cn=config", "nsslapd-security") + parser.add_value("cn=config", "nsslapd-security", security) + + parser.parse() + + shutil.copy2(ldif_outfile, self.filename) def __disable_listeners(self): - installutils.set_directive(self.filename, 'nsslapd-port', - 0, quotes=False, separator=':') - installutils.set_directive(self.filename, 'nsslapd-security', - 'off', quotes=False, separator=':') - installutils.set_directive(self.filename, 'nsslapd-ldapientrysearchbase', - None, quotes=False, separator=':') + ldif_outfile = "%s.modified.out" % self.filename + with open(ldif_outfile, "wb") as out_file: + ldif_writer = ldif.LDIFWriter(out_file) + with open(self.filename, "rb") as in_file: + parser = ModifyLDIF(in_file, ldif_writer) + + parser.remove_value("cn=config", "nsslapd-port") + parser.add_value("cn=config", "nsslapd-port", "0") + + parser.remove_value("cn=config", "nsslapd-security") + parser.add_value("cn=config", "nsslapd-security", "off") + + parser.remove_value("cn=config", "nsslapd-ldapientrysearchbase") + + parser.parse() + + shutil.copy2(ldif_outfile, self.filename) def __update_schema(self): self.modified = schemaupdate.update_schema( |