Hello community,

here is the log from the commit of package python-aedir for openSUSE:Factory 
checked in at 2017-01-30 10:49:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-aedir (Old)
 and      /work/SRC/openSUSE:Factory/.python-aedir.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-aedir"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-aedir/python-aedir.changes        
2017-01-25 23:25:07.378605434 +0100
+++ /work/SRC/openSUSE:Factory/.python-aedir.new/python-aedir.changes   
2017-02-03 18:57:07.711804822 +0100
@@ -1,0 +2,11 @@
+Thu Jan 19 08:23:22 UTC 2017 - mich...@stroeder.com
+
+- update to 0.0.17
+- added PGP signature file and keyring
+
+-------------------------------------------------------------------
+Mon Jan 16 16:30:21 UTC 2017 - mich...@stroeder.com
+
+- update to 0.0.16
+
+-------------------------------------------------------------------

Old:
----
  aedir-0.0.15.tar.gz

New:
----
  aedir-0.0.17.tar.gz
  aedir-0.0.17.tar.gz.asc
  python-aedir.keyring

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-aedir.spec ++++++
--- /var/tmp/diff_new_pack.CUsgRx/_old  2017-02-03 18:57:08.051757081 +0100
+++ /var/tmp/diff_new_pack.CUsgRx/_new  2017-02-03 18:57:08.055756519 +0100
@@ -17,18 +17,21 @@
 
 
 Name:           python-aedir
-Version:        0.0.15
+Version:        0.0.17
 Release:        0
 Summary:        Python module for AE-DIR
 License:        Apache-2.0
 Group:          Development/Languages/Python
 Url:            https://www.ae-dir.com/python.html
-Source:         
https://files.pythonhosted.org/packages/source/a/aedir/aedir-%{version}.tar.gz
+Source0:        
https://files.pythonhosted.org/packages/source/a/aedir/aedir-%{version}.tar.gz
+Source1:        
https://files.pythonhosted.org/packages/source/a/aedir/aedir-%{version}.tar.gz.asc
+                # download key from 
https://stroeder.com/michael_at_stroeder.com-6A8BC938.asc
+Source2:        %{name}.keyring
 BuildRequires: python-devel
 BuildRequires: python-setuptools
 BuildRequires: python-ldap >= 2.4.28
 BuildRequires: python-pyasn1-modules
-Requires:       python-ldap
+Requires:       python-ldap >= 2.4.28
 Requires:       python-pyasn1-modules
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildArch:      noarch

++++++ aedir-0.0.15.tar.gz -> aedir-0.0.17.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aedir-0.0.15/PKG-INFO new/aedir-0.0.17/PKG-INFO
--- old/aedir-0.0.15/PKG-INFO   2017-01-14 14:53:06.000000000 +0100
+++ new/aedir-0.0.17/PKG-INFO   2017-01-18 22:56:52.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: aedir
-Version: 0.0.15
+Version: 0.0.17
 Summary: AE-DIR library
 Home-page: https://ae-dir.com/python.html
 Author: Michael Stroeder
@@ -26,5 +26,4 @@
 Classifier: Topic :: Internet
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Classifier: Topic :: System :: Systems Administration :: 
Authentication/Directory :: LDAP
-Requires: ldap(>=2.4.26)
-Provides: aedir (0.0.15)
+Requires: ldap
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aedir-0.0.15/aedir/__init__.py 
new/aedir-0.0.17/aedir/__init__.py
--- old/aedir-0.0.15/aedir/__init__.py  2017-01-13 22:56:39.000000000 +0100
+++ new/aedir-0.0.17/aedir/__init__.py  2017-01-17 12:09:26.000000000 +0100
@@ -33,7 +33,7 @@
 from ldap.controls.openldap import SearchNoOpMixIn
 from ldap.controls.readentry import PreReadControl
 
-__version__ = '0.0.15'
+__version__ = '0.0.17'
 __author__ = 'Michael Stroeder <mich...@stroeder.com>'
 __license__ = 'Apache License, Version 2.0'
 
@@ -350,16 +350,6 @@
         )
         return ldap_rootdse  # read_rootdse_s()
 
-    def get_naming_contexts(self):
-        """
-        returns all attribute values of namingContexts in rootDSE
-        if namingContexts is not present (not readable) then empty list is 
returned
-        """
-        return self.read_rootdse_s(
-            attrlist=['namingContexts']
-        ).get('namingContexts', [])
-
-
     def find_search_base(self):
         """
         Returns the aeRoot entry
@@ -368,6 +358,13 @@
             return self._aeroot_dn
         # read namingContexts from rootDSE
         naming_contexts = self.get_naming_contexts()
+        root_dse = self.read_rootdse_s(
+            attrlist=['namingContexts', 'defaultNamingContext', 'aeRoot']
+        )
+        aeroot_dn = root_dse.get('aeRoot', 
root_dse.get('defaultNamingContext', [None]))[0]
+        if aeroot_dn is not None:
+            self._aeroot_dn = aeroot_dn
+            return aeroot_dn
         while naming_contexts:
             # last element
             naming_context = naming_contexts.pop(-1)
@@ -468,7 +465,7 @@
             attrlist=attrlist,
         ) # get_zoneadmins()
 
-    def get_usergroups(self, uid, memberof_attr=None):
+    def get_user_groups(self, uid, memberof_attr=None):
         """
         Gets a set of DNs of aeGroup entries a AE-DIR user (aeUser or
         aeService) is member of
@@ -498,7 +495,7 @@
                 dn.lower()
                 for dn, _ in ldap_result
             ])
-        return memberof # get_usergroups()
+        return memberof # get_user_groups()
 
     def get_user_srvgroup_relations(
             self,
@@ -510,7 +507,7 @@
         Gets relationship between a aeUser and a aeSrvGroup object by
         simply returning the matching attributes of the aeSrvGroup entry
         """
-        aeuser_memberof = self.get_usergroups(uid)
+        aeuser_memberof = self.get_user_groups(uid)
         ref_attrs = ref_attrs or AESRVGROUP_GROUPREF_ATTRS
         aesrvgroup_entry = self.read_s(
             aesrvgroup_dn,
@@ -526,6 +523,18 @@
                         break
         return srvgroup_relations # get_user_srvgroup_relations()
 
+    def get_service_groups(self, service_dn):
+        """
+        returns DNs of all service groups the aeHost/aeService is member of
+        """
+        aeservice_entry = self.read_s(
+            service_dn,
+            attrlist=['aeSrvGroup']
+        ) or {}
+        aesrvgroup_dn_list = [','.join(ldap.explode_dn(service_dn)[1:])]
+        aesrvgroup_dn_list.extend(aeservice_entry.get('aeSrvGroup', []))
+        return aesrvgroup_dn_list
+
     def get_user_service_relations(
             self,
             uid,
@@ -538,21 +547,52 @@
 
         returns set of relationship attribute names
         """
-        aeservice_entry = self.read_s(
-            service_dn,
-            attrlist=['aeSrvGroup']
-        )
-        aesrvgroup_dn_list = [','.join(ldap.explode_dn(service_dn)[1:])]
-        aesrvgroup_dn_list.extend(aeservice_entry.get('aeSrvGroup', []))
+        aesrvgroup_dn_list = self.get_service_groups(service_dn)
         result = set()
         for aesrvgroup_dn in set(aesrvgroup_dn_list):
-            result.update(self.get_user_srvgroup_relations(
-                uid,
-                aesrvgroup_dn=aesrvgroup_dn,
-                ref_attrs=ref_attrs,
-            ))
+            result.update(
+                self.get_user_srvgroup_relations(
+                    uid,
+                    aesrvgroup_dn=aesrvgroup_dn,
+                    ref_attrs=ref_attrs,
+                )
+            )
         return result
 
+    def get_users(self, service_dn, attrlist=None, ref_attr='aeLoginGroups'):
+        """
+        returns all aeUser/aeService entries having the appropriate
+        relationship on given aeHost/aeService
+        """
+        aesrvgroup_dn_list = self.get_service_groups(service_dn)
+        srvgroup_filter = '(&{0}({1}=*))'.format(
+            '(|{0})'.format(''.join([
+                '(entryDN={0})'.format(dn)
+                for dn in aesrvgroup_dn_list
+            ])),
+            ref_attr,
+        )
+        srvgroups = self.search_ext_s(
+            self._aeroot_dn,
+            ldap.SCOPE_SUBTREE,
+            srvgroup_filter,
+            attrlist=[ref_attr],
+        ) or []
+        ref_attrs_groups = set()
+        for srvgroup_dn, srvgroup_entry in srvgroups:
+            ref_attrs_groups.update(map(str.lower, srvgroup_entry[ref_attr]))
+        user_group_filter = '(|{0})'.format(''.join([
+            '(memberOf={0})'.format(dn)
+            for dn in ref_attrs_groups
+        ]))
+        ae_user_entries = self.search_ext_s(
+            self._aeroot_dn,
+            ldap.SCOPE_SUBTREE,
+            user_group_filter,
+            attrlist=attrlist,
+        )
+        return ae_user_entries
+
     def get_cache_hit_ratio(self):
         """
         Returns percentage of cache hit ratio
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aedir-0.0.15/aedir/process.py 
new/aedir-0.0.17/aedir/process.py
--- old/aedir-0.0.15/aedir/process.py   2017-01-14 14:48:14.000000000 +0100
+++ new/aedir-0.0.17/aedir/process.py   2017-01-16 17:10:27.000000000 +0100
@@ -25,11 +25,12 @@
     """
     Base process class
     """
+    initial_state = None
     script_version = '(no version)'
     ldap_url = None
     pyldap_tracelevel = 0
 
-    def __init__(self, max_runs=1, run_sleep=60.0):
+    def __init__(self):
         self.script_name = os.path.basename(sys.argv[0])
         self.logger = aedir.init_logger(self.script_name)
         self.logger.debug('Starting %s %s', sys.argv[0], self.script_version)
@@ -40,22 +41,30 @@
             self.ldap_conn.ldap_url_obj.initializeUrl(),
             self.ldap_conn.whoami_s(),
         )
-        self.run_sleep = run_sleep
-        self.max_runs = max_runs
-        self.run_counter = 0
-        self._run()
-        self.exit()
+        # not really started yet
+        self.start_time = None
+        self.run_counter = None
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        try:
+            self.ldap_conn.unbind_s()
+        except ldap.LDAPError:
+            pass
 
     def get_state(self):
         """
         get current state (to be overloaded by derived classes)
         """
-        return None
+        return self.initial_state
 
     def set_state(self, state):
         """
         set current state (to be overloaded by derived classes)
         """
+        pass
 
     def run_worker(self, state):
         """
@@ -74,82 +83,77 @@
         """
         return
 
-    def _run(self):
+    def run(self, max_runs=1, run_sleep=60.0):
         """
         the main program
         """
+        self.start_time = time.time()
+        self.run_counter = 0
         try:
             # first run
             self.set_state(self.run_worker(self.get_state()))
             self.run_counter += 1
-            while self.run_counter < self.max_runs or self.max_runs is None:
+            while self.run_counter < max_runs or max_runs is None:
                 # further runs
                 self.set_state(self.run_worker(self.get_state()))
                 self.run_counter += 1
-                time.sleep(self.run_sleep)
-        finally:
-            try:
-                self.ldap_conn.unbind_s()
-            except ldap.LDAPError:
-                pass
+                time.sleep(run_sleep)
+        except KeyboardInterrupt:
+            self.logger.info('Exit on keyboard interrupt')
+            self.exit()
+        except Exception:
+            self.logger.error(
+                'Unhandled exception during processing request:',
+                exc_info=True
+            )
+        else:
+            self.exit()
         return # end of AEProcess.run()
 
 
 class TimestampStateMixin(object):
     """
-    Mix-in class for AEProcess which implements timestamp-based state in a file
+    Mix-in class for AEProcess which implements timestamp-based
+    state strings in a file
     """
+    initial_state = '19700101000000Z'
 
     def get_state(self):
         """
         Read the timestamp of last run from file `sync_state_filename'
         """
         try:
-            last_run_timestr = open(self.state_filename, 'rb').read().strip()
+            with open(self.state_filename, 'rb') as file_obj:
+                last_run_timestr = file_obj.read().strip() or 
self.initial_state
+            # check syntax by parsing the string
+            ldap.strp_secs(last_run_timestr)
         except CatchAllException, err:
             self.logger.warn(
-                'Error reading file %r: %s',
+                'Error reading timestamp from file %r: %s',
                 self.state_filename,
                 err
             )
-            last_run_timestr = None
+            last_run_timestr = self.initial_state
         else:
             self.logger.debug(
                 'Read last run timestamp %r from file %r',
                 last_run_timestr,
                 self.state_filename,
             )
-        last_run_timestr = last_run_timestr or None
-        last_run_time = 0
-        if last_run_timestr:
-            try:
-                last_run_time = ldap.strp_secs(last_run_timestr)
-            except ValueError, err:
-                self.logger.warn(
-                    'Error parsing timestamp %r: %s',
-                    last_run_timestr,
-                    err,
-                )
-        return last_run_time # end of get_state()
+        return last_run_timestr # end of get_state()
 
-    def set_state(self, current_time):
+    def set_state(self, current_time_str):
         """
         Write the current state
         """
-        current_time_str = ldap.strf_secs(current_time)
+        if not current_time_str:
+            current_time_str = self.initial_state
         try:
             # Write the last run timestamp
-            open(self.state_filename, 'wb').write(current_time_str)
+            with open(self.state_filename, 'wb') as file_obj:
+                file_obj.write(current_time_str)
         except CatchAllException, err:
-            self.logger.warn(
-                'Could not write %r: %s',
-                self.state_filename,
-                err,
-            )
+            self.logger.warn('Could not write %r: %s', self.state_filename, 
err)
         else:
-            self.logger.debug(
-                'Wrote %r to %r',
-                current_time_str,
-                self.state_filename,
-            )
+            self.logger.debug('Wrote %r to %r', current_time_str, 
self.state_filename)
         return # end of set_state()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aedir-0.0.15/setup.cfg new/aedir-0.0.17/setup.cfg
--- old/aedir-0.0.15/setup.cfg  2016-08-16 12:17:21.000000000 +0200
+++ new/aedir-0.0.17/setup.cfg  2017-01-18 15:10:41.000000000 +0100
@@ -4,9 +4,9 @@
 
 # Linux distributors/packagers should adjust these settings
 [bdist_rpm]
-vendor = ae-dir.org
+vendor = ae-dir.com
 provides = python-aedir
-requires = python python-ldap>=2.4.25
+requires = python python-ldap>=2.4.28
 # distribution_name = 
 release = 0
 packager = Michael Stroeder <mich...@stroeder.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aedir-0.0.15/setup.py new/aedir-0.0.17/setup.py
--- old/aedir-0.0.15/setup.py   2017-01-13 21:48:23.000000000 +0100
+++ new/aedir-0.0.17/setup.py   2017-01-18 22:56:47.000000000 +0100
@@ -31,8 +31,8 @@
     download_url='https://pypi.python.org/pypi/aedir',
     py_modules=['aedir', 'aedir.process'],
     keywords=['AE-DIR', 'LDAP', 'OpenLDAP'],
-    requires=['ldap(>=2.4.26)'],
-    provides=['aedir (%s)' % aedir.__version__],
+    requires=['ldap'],
+    #provides=['aedir (%s)' % aedir.__version__],
     classifiers=[
         'Development Status :: 5 - Production/Stable',
         'Environment :: No Input/Output (Daemon)',

++++++ python-aedir.keyring ++++++
pub   rsa2048 2016-03-07 [SC]
      43C8730E84A20E560722806C07DC7AE36A8BC938
uid           [ unknown] Michael Ströder <mich...@stroeder.com>
sub   rsa2048 2016-03-07 [E]

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBFbdnRoBCADj0vYA4aRwKJ6AE4mf8oElLgMT/1eLNKpJ2FYBWcwj9d8dTk5/
p9b8DRxyS/qQIUUZqt9xRFZwUCm0vFeQMRDeN9xzAKoRzrJifoDOacOjG1lhZTKY
vVZGgUT89Ao3QeHhQ7gPzcAKNoueoR2y3FXStOYuRrbk5PlSjVAITjsotgc7PWE9
mmVYpeu8a+byK/DBHKUyolOA1UXYvDa7MbPhMtdNm8qnwtKs1Vsyk1VkErM+5cIe
+zTT6WYQcmZMRjCtWGiFTzk9W6MdlskkWRTKhKNgokTsgcy1ecaCBUZWxv/SyXgD
81+rwRi9b8Px+1reg43ayxi8sV7jrI1feybbABEBAAG0J01pY2hhZWwgU3Ryw7Zk
ZXIgPG1pY2hhZWxAc3Ryb2VkZXIuY29tPokBNwQTAQgAIQUCVt2dGgIbAwULCQgH
AgYVCAkKCwIEFgIDAQIeAQIXgAAKCRAH3HrjaovJOFpTCACjO773gcmJKvzjiNpU
Fl/gANyaJgIq4VbMQ7VthRb1F9X6YbdJ6Z99ntyESjGFCpjofcSomr2vJDpv6ht+
lY33yo20YwsMpqe2OeId0jPybG+FtabKjgBNoAk7iqnBGUvE4t0dz0n1LQVCQR2j
xyTKmcNqOYpsRZ3H+6kWwJMuVgsNZglINVZ8JgV5QuLYN5jhYz+pOuFnU11bV6nW
REvzZXzebe7g7Zus6AsWjtJ0lDvgBNzLlF3/eFrVch6Bejs0SvuFseIdZQk+4YU6
Rb8xul/jDFXIfo7eTmijO3dVT5AmC1cUi8czncwpgAJnEH8vYv23RoN/aw2gSMCS
2huIuQENBFbdnRoBCAC7L1cTVBVZZuM/yxSUM5CsgGBlTD1Cr7C2ngZFsHSYXVLq
6NUB8GZA2iLK96CrwnFw4/Jjz4llOjc50iVRMQKLRyFWOJAMrpPq2ew5T+Uoo524
D//dwVbqkFVVuvM8NPiKIDyPGCjP+acM1D8hXwhOXgQ8Iz8Q3/GRSYjitn9JrkF0
ia2nhariznBKVu0LDffxF/hOCx45+QRR2/rYYlshfZMB7nEJX9P+hVfMCSzltz9Z
8CldeUbiJvnyrISReR2XBw9oh8JkIUP0BtpIaify9A7EfzOk+W9BUnWe+YwdSUsB
fJxOhSv+umyW5GMqZGFu+4oYnkzbe+1LUs1JarCtABEBAAGJAR8EGAEIAAkFAlbd
nRoCGwwACgkQB9x642qLyTjEUgf+JX6Atatl/QKe37yCj1OZYNPd3B0rPLJRF5mE
mrADRXLZC9+uFeDSWxxln040gnR6rjBHrRcvVmlTDiZY26iuL16+V+0/aZ9uyXNQ
Szk2cwDSiI/8gvr72Y+FN5fhcGXpeNHxHilYc9onzDhxyE76cwzqTKm4q2ULIH2u
9IHQ5O86Fv6nHPYhe2fy1bhQapNwi/Xl3G3i2WNH/w7m+1zWU1IddZOjmXzoxLT1
BATwXGa0Tt5RjVb2mM1Wg3Zj6kqFkF2vvKcvrwj0q0Ap5uyfN5m0uWzQMCMoaV9H
Qf7f5MkS1lnwBqDgnojjVAieX5uk7olUiRuPKHMfhvXulYP8AA==
=D+4K
-----END PGP PUBLIC KEY BLOCK-----

Reply via email to