Merge pull request #5 from apache/detect-request-failure

Detect failed requests
diff --git a/authz.py b/authz.py
index cceee44..c9167f5 100755
--- a/authz.py
+++ b/authz.py
@@ -200,6 +200,8 @@
 
     # When testing, always produce some of the basic debug output.
     if args.test:
+        # Switch the root logger to DEBUG.
+        logging.getLogger().setLevel(logging.DEBUG)
         args.verbose = max(1, args.verbose)
 
     main(args)
diff --git a/gen.py b/gen.py
index 22c53b5..2048cc0 100755
--- a/gen.py
+++ b/gen.py
@@ -20,7 +20,13 @@
 import time
 
 import ldap
-import ezt
+
+# functools.cache was introduced in 3.9. Use it if available.
+try:
+    from functools import cache as maybe_cache
+except ImportError:
+    maybe_cache = lambda func: func
+
 
 ### move this to the config file, or LDAP
 SVN_ADMINS = 'gmcdonald,humbedooh,cml,christ,dfoulks,gstein,iroh'
@@ -36,7 +42,7 @@
     'commons',
     'couchdb',
     'lucene',
-    'solr'
+    'solr',
     'trafficcontrol',
     'zookeeper',
     }
@@ -53,10 +59,6 @@
     # Extract UIDs from an LDAP response.
     UID_RE = re.compile(rb'^uid=([^,]*),.*')
 
-    # Disable cert check. The self-signed cert throws off python-ldap.
-    ### global option, not per connection? ugh.
-    ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
-
     def __init__(self, url, binddn, bindpw):
         # Easy to front-load client handle creation. It will lazy connect.
         self.handle = ldap.initialize(url)
@@ -109,6 +111,7 @@
         self.special = special
         self.explicit = explicit
 
+    @maybe_cache
     def group_members(self, group):
         "Given an authz @GROUP, return its members."
 
@@ -159,6 +162,22 @@
                     subdirs = [ line[10:] ]
                 for s in subdirs:
                     new_z.append(f'[{s}]\n* = r')
+            elif line.startswith('LDAP'):
+                # Define a group using LDAP information.
+                # Line format:
+                # LDAP(+PMC): $TLPNAME
+                ### NOTE: we place this authz at this specific point in
+                ### the authz file, and do "group" and "group-pmc" in this
+                ### order to maintain backwards-compat identical generation
+                ### of the file. In the future, simplification will be
+                ### possible once we decide to trust a major change in
+                ### the authz files.
+                group = line.split(':')[1].strip()
+                members = self.group_members(group)
+                new_z.append(f'{group}={",".join(members)}')
+                if line.startswith('LDAP+PMC'):
+                    members = self.group_members(group + '-pmc')
+                    new_z.append(f'{group}-pmc={",".join(members)}')
             elif line.startswith('#') or '={' not in line:
                 new_z.append(line)
             else: