From f01b66e5ed26b2a80c6c1010f249241100354d50 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Dec 2017 08:57:59 +0100 Subject: [PATCH] Use PATH to lookup test binaries Instead of hard-coded paths /usr/bin and /usr/sbin, the SlapdObject test helper now uses PATH env var to find test binaries. For slapd server binary, sbin paths are automatically added to lookup PATH in case they are missing. Signed-off-by: Christian Heimes --- Lib/slapdtest/_slapdtest.py | 77 +++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/Lib/slapdtest/_slapdtest.py b/Lib/slapdtest/_slapdtest.py index 09ec154..ebc5441 100644 --- a/Lib/slapdtest/_slapdtest.py +++ b/Lib/slapdtest/_slapdtest.py @@ -9,6 +9,7 @@ import os import socket +import sys import time import subprocess import logging @@ -109,6 +110,46 @@ def requires_ldapi(): return identity +def _which(cmd): + """Specialized which command based on shutil.which() from Python 3.6. + + * simplified + * always adds /sbin directories to path + """ + + def _access_check(fn): + return (os.path.exists(fn) and os.access(fn, os.F_OK | os.X_OK) + and not os.path.isdir(fn)) + + # Path with directory part skips PATH lookup. + if os.path.dirname(cmd): + if _access_check(cmd): + return cmd + return None + + path = os.environ.get("PATH", os.defpath).split(os.pathsep) + + if sys.platform == 'win32': + if os.curdir not in path: + path.insert(0, os.curdir) + # include path extension (.exe) + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + files = [cmd + ext for ext in pathext] + else: + # always include sbin for slapd binary + for sbin in ['/usr/local/sbin', '/sbin', '/usr/sbin']: + if sbin not in path: + path.append(sbin) + files = [cmd] + + for directory in path: + for name in files: + name = os.path.join(directory, name) + if _access_check(name): + return name + return None + + def combined_logger( log_name, log_level=logging.WARN, @@ -172,8 +213,6 @@ class SlapdObject(object): ) TMPDIR = os.environ.get('TMP', os.getcwd()) - SBINDIR = os.environ.get('SBIN', '/usr/sbin') - BINDIR = os.environ.get('BIN', '/usr/bin') if 'SCHEMA' in os.environ: SCHEMADIR = os.environ['SCHEMA'] elif os.path.isdir("/etc/openldap/schema"): @@ -182,12 +221,14 @@ class SlapdObject(object): SCHEMADIR = "/etc/ldap/schema" else: SCHEMADIR = None - PATH_LDAPADD = os.path.join(BINDIR, 'ldapadd') - PATH_LDAPDELETE = os.path.join(BINDIR, 'ldapdelete') - PATH_LDAPMODIFY = os.path.join(BINDIR, 'ldapmodify') - PATH_LDAPWHOAMI = os.path.join(BINDIR, 'ldapwhoami') - PATH_SLAPD = os.environ.get('SLAPD', os.path.join(SBINDIR, 'slapd')) - PATH_SLAPTEST = os.path.join(SBINDIR, 'slaptest') + # _check_requirements turns paths into absolute paths + PATH_LDAPADD = 'ldapadd' + PATH_LDAPDELETE = 'ldapdelete' + PATH_LDAPMODIFY = 'ldapmodify' + PATH_LDAPWHOAMI = 'ldapwhoami' + # The following two binaries are usually in /usr/sbin. + PATH_SLAPD = os.environ.get('SLAPD', 'slapd') + PATH_SLAPTEST = 'slaptest' # time in secs to wait before trying to access slapd via LDAP (again) _start_sleep = 1.5 @@ -223,13 +264,19 @@ def __init__(self): self.clientkey = os.path.join(HERE, 'certs/client.key') def _check_requirements(self): - binaries = [ - self.PATH_LDAPADD, self.PATH_LDAPMODIFY, self.PATH_LDAPWHOAMI, - self.PATH_SLAPD, self.PATH_SLAPTEST + names = [ + "PATH_LDAPADD", "PATH_LDAPMODIFY", "PATH_LDAPDELETE", + "PATH_LDAPWHOAMI", "PATH_SLAPD", "PATH_SLAPTEST", ] - for binary in binaries: - if not os.path.isfile(binary): - raise ValueError('Binary {} is missing.'.format(binary)) + for name in names: + value = getattr(self, name) + binary = _which(value) + if binary is None: + raise ValueError( + "Command '{}' not found in PATH".format(value) + ) + else: + setattr(self, name, binary) if self.SCHEMADIR is None: raise ValueError('SCHEMADIR is None, ldap schemas are missing.') @@ -359,7 +406,7 @@ def _start_slapd(self): self.PATH_SLAPD, '-f', self._slapd_conf, '-F', self.testrundir, - '-h', '%s' % ' '.join(urls), + '-h', ' '.join(urls), ] if self._log.isEnabledFor(logging.DEBUG): slapd_args.extend(['-d', '-1'])