diff options
-rw-r--r-- | install/updates/10-bind-schema.update | 2 | ||||
-rw-r--r-- | ipaserver/install/ldapupdate.py | 52 |
2 files changed, 52 insertions, 2 deletions
diff --git a/install/updates/10-bind-schema.update b/install/updates/10-bind-schema.update index 0edbad204..3c43c8ec7 100644 --- a/install/updates/10-bind-schema.update +++ b/install/updates/10-bind-schema.update @@ -75,4 +75,6 @@ add:objectClasses: MUST idnsName MAY managedBy X-ORIGIN 'IPA v3' ) + +dn: cn=schema replace:objectClasses:( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsZoneActive $$ idnsSOAmName $$ idnsSOArName $$ idnsSOAserial $$ idnsSOArefresh $$ idnsSOAretry $$ idnsSOAexpire $$ idnsSOAminimum ) MAY idnsUpdatePolicy )::( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsName $$ idnsZoneActive $$ idnsSOAmName $$ idnsSOArName $$ idnsSOAserial $$ idnsSOArefresh $$ idnsSOAretry $$ idnsSOAexpire $$ idnsSOAminimum ) MAY ( idnsUpdatePolicy $$ idnsAllowQuery $$ idnsAllowTransfer $$ idnsAllowSyncPTR $$ idnsForwardPolicy $$ idnsForwarders ) ) diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index d673ad57d..111769ffe 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -35,6 +35,7 @@ from ipalib import errors from ipalib import api from ipapython.dn import DN import ldap +from ldap.schema.models import ObjectClass from ipapython.ipa_log_manager import * import krbV import platform @@ -546,6 +547,28 @@ class LDAPUpdate: entry_values = [] else: entry_values = [entry_values] + + # Replacing objectClassess needs a special handling and + # normalization of OC definitions to avoid update failures for + # example when X-ORIGIN is the only difference + objectclass_replacement = False + if action == "replace" and entry.dn == DN(('cn', 'schema')) and \ + attr.lower() == "objectclasses": + objectclass_replacement = True + oid_index = {} + # build the OID index for replacing + for objectclass in entry_values: + try: + objectclass_object = ObjectClass(str(objectclass)) + except Exception, e: + self.error('replace: cannot parse ObjectClass "%s": %s', + objectclass, e) + continue + # In a corner case, there may be more representations of + # the same objectclass due to the previous updates + # We want to replace them all + oid_index.setdefault(objectclass_object.oid, []).append(objectclass) + for update_value in update_values: if action == 'remove': self.debug("remove: '%s' from %s, current value %s", update_value, attr, entry_values) @@ -601,7 +624,28 @@ class LDAPUpdate: except ValueError: raise BadSyntax, "bad syntax in replace, needs to be in the format old::new in %s" % update_value try: - entry_values.remove(old) + if objectclass_replacement: + try: + objectclass_old = ObjectClass(str(old)) + except Exception, e: + self.error('replace: cannot parse replaced ObjectClass "%s": %s', + old, e) + continue + replaced_values = [] + for objectclass in oid_index.get(objectclass_old.oid, []): + objectclass_object = ObjectClass(str(objectclass)) + if str(objectclass_old).lower() == str(objectclass_object).lower(): + # compare normalized values + replaced_values.append(objectclass) + self.debug('replace: replace ObjectClass "%s" with "%s"', + old, new) + if not replaced_values: + self.debug('replace: no match for replaced ObjectClass "%s"', old) + continue + for value in replaced_values: + entry_values.remove(value) + else: + entry_values.remove(old) entry_values.append(new) self.debug('replace: updated value %s', entry_values) entry.setValues(attr, entry_values) @@ -728,7 +772,11 @@ class LDAPUpdate: updated = False changes = self.conn.generateModList(entry.origDataDict(), entry.toDict()) if (entry.dn == DN(('cn', 'schema'))): - updated = self.is_schema_updated(entry.toDict()) + d = dict() + e = entry.toDict() + for k,v in e.items(): + d[k] = [str(x) for x in v] + updated = self.is_schema_updated(d) else: if len(changes) >= 1: updated = True |