This is an automated email from the ASF dual-hosted git repository. gstein pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/steve.git
commit 7ab0692c38f1996d714252cc91e458b793a1cb6a Author: Greg Stein <[email protected]> AuthorDate: Fri Oct 3 20:52:55 2025 -0500 Load ASF users into the "person" database. ASF-specific. Populate the "person" database. Useful as a template for mapping $your users into the persondb. --- v3/.gitignore | 1 + v3/pyproject.toml | 3 ++ v3/server/bin/asf-load-ldap.py | 77 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/v3/.gitignore b/v3/.gitignore index de50c4d..233cc0e 100644 --- a/v3/.gitignore +++ b/v3/.gitignore @@ -1,6 +1,7 @@ poetry.lock server/bin/bs.zip +server/bin/bind.txt server/config.yaml server/apptoken.txt diff --git a/v3/pyproject.toml b/v3/pyproject.toml index 14dcd58..59ea29b 100644 --- a/v3/pyproject.toml +++ b/v3/pyproject.toml @@ -27,6 +27,9 @@ types-aiofiles = "^24.1.0" [tool.poetry.group.server.dependencies] asfquart = ">=0.1.12" +### not sure about this. not needed for server operation. +### let the import fail, and the user can do a pip install. +#python-ldap = "^3.0.0" [tool.poetry.extras] server = ["asfquart", ] # Core dependencies for apache-steve[server] diff --git a/v3/server/bin/asf-load-ldap.py b/v3/server/bin/asf-load-ldap.py new file mode 100755 index 0000000..3c4d04c --- /dev/null +++ b/v3/server/bin/asf-load-ldap.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import pathlib +import logging + +import ldap # pip3 install python-ldap +import asfpy.db +import asfpy.stopwatch +from easydict import EasyDict as edict + +_LOGGER = logging.getLogger(__name__) + +THIS_DIR = pathlib.Path(__file__).resolve().parent +DB_FNAME = THIS_DIR.parent / 'steve.db' + +sys.path.insert(0, str(THIS_DIR.parent.parent)) +import steve.persondb + +# The ASF's LDAP server, available for read-only for finding potential voters. +LDAP_URL = 'ldaps://ldap-us.apache.org/' +LDAP_DN = 'ou=people,dc=apache,dc=org' +LDAP_ATTR = 'memberUid' + + [email protected]() +def main(): + pdb = steve.persondb.PersonDB(DB_FNAME) + # Reach into PDB for the CONN, and start a transaction for all + # of the inserts we will perform. (rather than default auto-commit) + pdb.db.conn.execute('BEGIN TRANSACTION') + + client = ldap.initialize(LDAP_URL) + binddn, bindpw = [ s.strip() + for s in open(THIS_DIR / 'bind.txt').readlines()[:2] ] + #print('BIND:', binddn, bindpw) + client.simple_bind_s(binddn, bindpw) + + with asfpy.stopwatch.Stopwatch('run LDAP full scan'): + results = client.search_s(LDAP_DN, ldap.SCOPE_SUBTREE, 'uid=*', attrlist=None) #[LDAP_ATTR,]) + + count = 0 + for r in results: + # r[0] is the CN(?) ... not needed + # r[1] is the {attr:[values..]} dict + entry = edict(r[1]) + + uid = entry.uid[0].decode('utf-8') + visname = entry.cn[0].decode('utf-8') + email = entry['asf-committer-email'][0].decode('utf-8') + + pdb.add_person(uid, visname, email) + count += 1 + + # Reach into the CONN and do the commit. + pdb.db.conn.execute('COMMIT') + + _LOGGER.info(f'Loaded {count} persons into {DB_FNAME}') + + +if __name__ == '__main__': + logging.basicConfig(level=logging.INFO) + main()
