def create(self, suffix=None, bename=None, parent=None): ''' Create a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and that is stored in 'bename' backend. 'bename' backend must exists before creating the mapping tree entry. If a 'parent' is provided that means that we are creating a sub-suffix mapping tree. @param suffix - suffix mapped by this mapping tree entry. It will be the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param parent - if provided is a parent suffix of 'suffix' @return DN of the mapping tree entry @raise ldap.NO_SUCH_OBJECT - if the backend entry or parent mapping tree does not exist ''' # Check suffix is provided if not suffix: raise ValueError("suffix is mandatory") else: nsuffix = normalizeDN(suffix) # Check backend name is provided if not bename: raise ValueError("backend name is mandatory") # Check that if the parent suffix is provided then # it exists a mapping tree for it if parent: nparent = normalizeDN(parent) filt = suffixfilt(parent) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) pass except NoSuchEntryError: raise ValueError("parent suffix has no mapping tree") else: nparent = "" # Check if suffix exists, return filt = suffixfilt(suffix) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) return entry except NoSuchEntryError: entry = None # # Now start the real work # # fix me when we can actually used escaped DNs dn = ','.join(('cn="%s"' % nsuffix, DN_MAPPING_TREE)) entry = Entry(dn) entry.update({ 'objectclass': ['top', 'extensibleObject', MT_OBJECTCLASS_VALUE], 'nsslapd-state': 'backend', # the value in the dn has to be DN escaped # internal code will add the quoted value - unquoted value is useful for searching MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]: nsuffix, MT_PROPNAME_TO_ATTRNAME[MT_BACKEND]: bename }) # possibly add the parent if parent: entry.setValues(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX], nparent) try: self.log.debug("Creating entry: %s" % entry.dn) self.log.info("Entry %r" % entry) self.conn.add_s(entry) except ldap.LDAPError, e: raise ldap.LDAPError("Error adding suffix entry " + dn, e)
def getProperties(self, suffix=None, bename=None, name=None, properties=None): ''' Returns a dictionary of the requested properties. If properties is missing, it returns all the properties. The returned properties are those of the 'suffix' and that is stored in 'benamebase' backend. If 'name' is specified. It uses it to retrieve the mapping tree to delete Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to If 'name', 'benamebase' and 'suffix' are missing it raise an exception @param suffix - suffix mapped by this mapping tree entry. It is the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param name - DN of the mapping tree entry @param - properties - list of properties @return - returns a dictionary of the properties @raise ValueError - if some name of properties are not valid KeyError - if some name of properties are not valid ldap.NO_SUCH_OBJECT - if the mapping tree entry is not found ''' if name: filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE try: ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt, MT_PROPNAME_TO_ATTRNAME.values()) self.log.debug("delete: %s found by its DN" % ent.dn) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) else: filt=None if suffix: filt = suffixfilt(suffix) if bename: if filt: filt = "(&(%s=%s)%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename, filt) else: filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename) try: ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt, MT_PROPNAME_TO_ATTRNAME.values()) self.log.debug("delete: %s found by with %s" % (ent.dn, filt)) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) result = {} attrs = [] if properties: # # build the list of attributes we are looking for for prop_name in properties: prop_attr = MT_PROPNAME_TO_ATTRNAME[prop_name] if not prop_attr: raise ValueError("Improper property name: %s ", prop_name) self.log.debug("Look for attr %s (property: %s)" % (prop_attr, prop_name)) attrs.append(prop_attr) # now look for each attribute from the MT entry for attr in ent.getAttrs(): # given an attribute name retrieve the property name props = [ k for k, v in MT_PROPNAME_TO_ATTRNAME.iteritems() if v.lower() == attr.lower() ] # If this attribute is present in the MT properties and was requested, adds it to result if len(props) > 0: if len(attrs) > 0: if MT_PROPNAME_TO_ATTRNAME[props[0]] in attrs: # if the properties was requested self.log.debug("keep only attribute %s " % (props[0])) result[props[0]] = ent.getValues(attr) else: result[props[0]] = ent.getValues(attr) return result
def delete(self, suffix=None, bename=None, name=None): ''' Delete a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and that is stored in 'benamebase' backend. 'benamebase' backend is not changed by the mapping tree deletion. If 'name' is specified. It uses it to retrieve the mapping tree to delete Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to delete @param suffix - suffix mapped by this mapping tree entry. It is the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param name - DN of the mapping tree entry @return None @raise ldap.NO_SUCH_OBJECT - the entry is not found KeyError if 'name', 'suffix' and 'benamebase' are missing UnwillingToPerformError - If the mapping tree has subordinates ''' if name: filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE try: ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt) self.log.debug("delete: %s found by its DN" % ent.dn) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) else: filt=None if suffix: filt = suffixfilt(suffix) if bename: if filt: filt = "(&(%s=%s)%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename, filt) else: filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename) try: ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt) self.log.debug("delete: %s found by with %s" % (ent.dn, filt)) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) # # At this point 'ent' contains the mapping tree entry to delete # # First Check there is no child (replica, replica agreements) try: ents = self.conn.search_s(ent.dn, ldap.SCOPE_SUBTREE, "objectclass=*") except: raise if len(ents) != 1: for entry in ents: self.log.warning("Error: it exists %s under %s" % (entry.dn, ent.dn)) raise UnwillingToPerformError("Unable to delete %s, it is not a leaf" % ent.dn) else: for entry in ents: self.log.warning("Warning: %s (%s)" % (entry.dn, ent.dn)) self.conn.delete_s(ent.dn)
def create(self, suffix=None, bename=None, parent=None): ''' Create a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and that is stored in 'bename' backend. 'bename' backend must exist before creating the mapping tree entry. If a 'parent' is provided that means that we are creating a sub-suffix mapping tree. @param suffix - suffix mapped by this mapping tree entry. It will be the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param parent - if provided is a parent suffix of 'suffix' @return DN of the mapping tree entry @raise ldap.NO_SUCH_OBJECT - if the backend entry or parent mapping tree does not exist ValueError - if missing a parameter, ''' # Check suffix is provided if not suffix: raise ValueError("suffix is mandatory") else: nsuffix = normalizeDN(suffix) # Check backend name is provided if not bename: raise ValueError("backend name is mandatory") # Check that if the parent suffix is provided then # it exists a mapping tree for it if parent: nparent = normalizeDN(parent) filt = suffixfilt(parent) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) pass except NoSuchEntryError: raise ValueError("parent suffix has no mapping tree") else: nparent = "" # Check if suffix exists, return filt = suffixfilt(suffix) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) return entry except ldap.NO_SUCH_OBJECT: entry = None # # Now start the real work # # fix me when we can actually used escaped DNs dn = ','.join(('cn="%s"' % nsuffix, DN_MAPPING_TREE)) entry = Entry(dn) entry.update({ 'objectclass': ['top', 'extensibleObject', MT_OBJECTCLASS_VALUE], 'nsslapd-state': 'backend', # the value in the dn has to be DN escaped # internal code will add the quoted value - unquoted value is # useful for searching. MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]: nsuffix, MT_PROPNAME_TO_ATTRNAME[MT_BACKEND]: bename }) # possibly add the parent if parent: entry.setValues(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX], nparent) try: self.log.debug("Creating entry: %s", entry.dn) self.log.info("Entry %r", entry) self.conn.add_s(entry) except ldap.LDAPError as e: raise ldap.LDAPError("Error adding suffix entry " + dn, e) ret = self.conn._test_entry(dn, ldap.SCOPE_BASE) return ret
def getProperties(self, suffix=None, bename=None, name=None, properties=None): ''' Returns a dictionary of the requested properties. If properties is missing, it returns all the properties. The returned properties are those of the 'suffix' and that is stored in 'benamebase' backend. If 'name' is specified. It uses it to retrieve the mapping tree to delete Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to If 'name', 'benamebase' and 'suffix' are missing it raise an exception @param suffix - suffix mapped by this mapping tree entry. It is the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param name - DN of the mapping tree entry @param - properties - list of properties @return - returns a dictionary of the properties @raise ValueError - if some name of properties are not valid KeyError - if some name of properties are not valid ldap.NO_SUCH_OBJECT - if the mapping tree entry is not found ''' if name: filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE try: ent = self.conn.getEntry( name, ldap.SCOPE_BASE, filt, list(MT_PROPNAME_TO_ATTRNAME.values())) self.log.debug("delete: %s found by its DN", ent.dn) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) else: filt = None if suffix: filt = suffixfilt(suffix) if bename: if filt: filt = ( "(&(%s=%s)%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename, filt)) else: filt = ("(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename)) try: ent = self.conn.getEntry( DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt, list(MT_PROPNAME_TO_ATTRNAME.values())) self.log.debug("delete: %s found by with %s", ent.dn, filt) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) result = {} attrs = [] if properties: # # build the list of attributes we are looking for for prop_name in properties: prop_attr = MT_PROPNAME_TO_ATTRNAME[prop_name] if not prop_attr: raise ValueError("Improper property name: %s ", prop_name) self.log.debug("Look for attr %s (property: %s)", prop_attr, prop_name) attrs.append(prop_attr) # now look for each attribute from the MT entry for attr in ent.getAttrs(): # given an attribute name retrieve the property name props = [ k for k, v in MT_PROPNAME_TO_ATTRNAME.items() if v.lower() == attr.lower() ] # If this attribute is present in the MT properties and was # requested, adds it to result. if len(props) > 0: if len(attrs) > 0: if MT_PROPNAME_TO_ATTRNAME[props[0]] in attrs: # if the properties was requested self.log.debug("keep only attribute %s ", props[0]) result[props[0]] = ent.getValues(attr) else: result[props[0]] = ent.getValues(attr) return result
def delete(self, suffix=None, bename=None, name=None): ''' Delete a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and that is stored in 'benamebase' backend. 'benamebase' backend is not changed by the mapping tree deletion. If 'name' is specified. It uses it to retrieve the mapping tree to delete. Else if 'suffix'/'benamebase' are specified. It uses both to retrieve the mapping tree to delete @param suffix - suffix mapped by this mapping tree entry. It is the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param name - DN of the mapping tree entry @return None @raise ldap.NO_SUCH_OBJECT - the entry is not found KeyError if 'name', 'suffix' and 'benamebase' are missing UnwillingToPerformError - If the mapping tree has subordinates ''' if name: filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE try: ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt) self.log.debug("delete: %s found by its DN", ent.dn) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) else: filt = None if suffix: filt = suffixfilt(suffix) if bename: if filt: filt = ( "(&(%s=%s)%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename, filt)) else: filt = ("(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename)) try: ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL, filt) self.log.debug("delete: %s found by with %s", ent.dn, filt) except NoSuchEntryError: raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" % name) # # At this point 'ent' contains the mapping tree entry to delete # # First Check there is no child (replica, replica agreements) try: ents = self.conn.search_s(ent.dn, ldap.SCOPE_SUBTREE, "objectclass=*") except: raise if len(ents) != 1: for entry in ents: self.log.warning("Error: it exists %s under %s", entry.dn, ent.dn) raise ldap.UNWILLING_TO_PERFORM( "Unable to delete %s, it is not a leaf" % ent.dn) else: for entry in ents: self.log.warning("Warning: %s (%s)", entry.dn, ent.dn) self.conn.delete_s(ent.dn)