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-----