def PostProcess(self, data_map, source, search_filter, search_scope): """Perform some post-process of the data.""" if 'uniqueMember' in self.attrs: for gr in data_map: uidmembers = [] for member in gr.members: source.Search(search_base=member, search_filter='(objectClass=*)', search_scope=ldap.SCOPE_BASE, attrs=['uid']) for obj in source: if 'uid' in obj: uidmembers.extend(obj['uid']) del gr.members[:] gr.members.extend(uidmembers) _group_map = {i.name: i for i in data_map} def _expand_members(obj, visited=None): """Expand all subgroups recursively.""" for member_name in obj.groupmembers: if member_name in _group_map and member_name not in visited: gmember = _group_map[member_name] for member in gmember.members: if member not in obj.members: obj.members.append(member) for submember_name in gmember.groupmembers: if submember_name in _group_map and submember_name not in visited: visited.append(submember_name) _expand_members(_group_map[submember_name], visited) if self.conf.get("nested_groups"): self.log.info("Expanding nested groups") for gr in data_map: _expand_members(gr, [gr.name])
def PostProcess(self, data_map, source, search_filter, search_scope): """Perform some post-process of the data.""" if 'uniqueMember' in self.attrs: for gr in data_map: uidmembers=[] for member in gr.members: source.Search(search_base=member, search_filter='(objectClass=*)', search_scope=ldap.SCOPE_BASE, attrs=['uid']) for obj in source: if 'uid' in obj: uidmembers.extend(obj['uid']) del gr.members[:] gr.members.extend(uidmembers)
def GetUpdates(self, source, search_base, search_filter, search_scope, since): """Get updates from a source. Args: source: a data source search_base: the LDAP base of the tree search_filter: the LDAP object filter search_scope: the LDAP scope filter, one of 'base', 'one', or 'sub'. since: a timestamp to get updates since (None for 'get everything') Returns: a tuple containing the map of updates and a maximum timestamp Raises: error.ConfigurationError: scope is invalid ValueError: an object in the source map is malformed """ if self.conf.get('ad'): # AD attribute for modifyTimestamp is whenChanged self.attrs.append('whenChanged') else: self.attrs.append('modifyTimestamp') if since is not None: ts = self.FromTimestampToLdap(since) # since openldap disallows modifyTimestamp "greater than" we have to # increment by one second. if self.conf.get('ad'): ts = int(ts.rstrip('.0Z')) + 1 ts = '%s.0Z' % ts search_filter = ('(&%s(whenChanged>=%s))' % (search_filter, ts)) else: ts = int(ts.rstrip('Z')) + 1 ts = '%sZ' % ts search_filter = ('(&%s(modifyTimestamp>=%s))' % (search_filter, ts)) if search_scope == 'base': search_scope = ldap.SCOPE_BASE elif search_scope in ['one', 'onelevel']: search_scope = ldap.SCOPE_ONELEVEL elif search_scope in ['sub', 'subtree']: search_scope = ldap.SCOPE_SUBTREE else: raise error.ConfigurationError('Invalid scope: %s' % search_scope) source.Search(search_base=search_base, search_filter=search_filter, search_scope=search_scope, attrs=self.attrs) # Don't initialize with since, because we really want to get the # latest timestamp read, and if somehow a larger 'since' slips through # the checks in main(), we'd better catch it here. max_ts = None data_map = self.CreateMap() for obj in source: for field in self.essential_fields: if field not in obj: logging.warn('invalid object passed: %r not in %r', field, obj) raise ValueError('Invalid object passed: %r', obj) if self.conf.get('ad'): obj_ts = self.FromLdapToTimestamp(obj['whenChanged'][0]) else: try: obj_ts = self.FromLdapToTimestamp(obj['modifyTimestamp'][0]) except KeyError: obj_ts = self.FromLdapToTimestamp(obj['modifyTimeStamp'][0]) if max_ts is None or obj_ts > max_ts: max_ts = obj_ts try: if not data_map.Add(self.Transform(obj)): logging.info('could not add obj: %r', obj) except AttributeError as e: logging.warning('error %r, discarding malformed obj: %r', str(e), obj) # Perform some post processing on the data_map. self.PostProcess(data_map, source, search_filter, search_scope) data_map.SetModifyTimestamp(max_ts) return data_map