From d24a150f6c9d2ca228e81a6612949abb19fd5a4e Mon Sep 17 00:00:00 2001 From: William Brown Date: Mon, 7 Aug 2017 15:53:13 +1000 Subject: [PATCH] Ticket 88 - python install and remove for tests Bug Description: We need to be able to test instances with python and no perl tools. This will help us to progress and remove perl from the codebase, helping improve our portability. Fix Description: Add support to remove instances with python. Fix some setup python issues. Improve the lib389 test suite to handle some of the edge cases acound the changes. In general, this helps to improve our python 3 support across the board as this allows us to perform pure python 3 installs and tests. https://pagure.io/lib389/issue/88 Author: wibrown Review by: ??? --- lib389/__init__.py | 48 ++++---- lib389/_entry.py | 28 +++-- lib389/_mapped_object.py | 9 +- lib389/configurations/config_001003006.py | 5 +- lib389/configurations/sample.py | 4 +- lib389/dbgen.py | 191 ++++++++++++++++++++++++++++++ lib389/idm/group.py | 2 +- lib389/instance/remove.py | 54 +++++++++ lib389/instance/setup.py | 13 +- lib389/passwd.py | 2 +- lib389/paths.py | 17 ++- lib389/tasks.py | 10 +- lib389/tests/instance/setup_test.py | 3 + lib389/topologies.py | 1 + 14 files changed, 324 insertions(+), 63 deletions(-) create mode 100644 lib389/dbgen.py create mode 100644 lib389/instance/remove.py diff --git a/lib389/__init__.py b/lib389/__init__.py index 43ead6b..7e80dab 100644 --- a/lib389/__init__.py +++ b/lib389/__init__.py @@ -916,6 +916,7 @@ class DirSrv(SimpleLDAPObject, object): instance with the same 'serverid' """ # check that DirSrv was in DIRSRV_STATE_ALLOCATED state + self.log.debug("Server is in state %s" % self.state) if self.state != DIRSRV_STATE_ALLOCATED: raise ValueError("invalid state for calling create: %s" % self.state) @@ -927,14 +928,8 @@ class DirSrv(SimpleLDAPObject, object): if not self.serverid: raise ValueError("SER_SERVERID_PROP is missing, " + "it is required to create an instance") - - # Check how we want to be installed. - env_pyinstall = False - if os.getenv('PYINSTALL', False) is not False: - env_pyinstall = True # Time to create the instance and retrieve the effective sroot - - if (env_pyinstall or pyinstall): + if (not self.ds_paths.perl_enabled or pyinstall): self._createPythonDirsrv(version) else: self._createDirsrv() @@ -946,7 +941,7 @@ class DirSrv(SimpleLDAPObject, object): # Now the instance is created but DirSrv is not yet connected to it self.state = DIRSRV_STATE_OFFLINE - def delete(self): + def _deleteDirsrv(self): ''' Deletes the instance with the parameters sets in dirsrv The state changes -> DIRSRV_STATE_ALLOCATED @@ -997,6 +992,16 @@ class DirSrv(SimpleLDAPObject, object): self.state = DIRSRV_STATE_ALLOCATED + def delete(self, pyinstall=False): + # Time to create the instance and retrieve the effective sroot + if (not self.ds_paths.perl_enabled or pyinstall): + from lib389.instance.remove import remove_ds_instance + remove_ds_instance(self) + else: + self._deleteDirsrv() + # Now, we are still an allocated ds object so we can be re-installed + self.state = DIRSRV_STATE_ALLOCATED + def open(self, saslmethod=None, sasltoken=None, certdir=None, starttls=False, connOnly=False, reqcert=ldap.OPT_X_TLS_HARD, usercert=None, userkey=None): ''' @@ -3046,18 +3051,21 @@ class DirSrv(SimpleLDAPObject, object): @return - nothing @raise - OSError """ - try: - os.system('%s -s %s -n %d -o %s' % (os.path.join(self.ds_paths.bin_dir, 'dbgen.pl'), suffix, num, ldif_file)) - os.chmod(ldif_file, 0o644) - if os.getuid() == 0: - # root user - chown the ldif to the server user - uid = pwd.getpwnam(self.userid).pw_uid - gid = grp.getgrnam(self.userid).gr_gid - os.chown(ldif_file, uid, gid) - except OSError as e: - log.exception('Failed to create ldif file (%s): error %d - %s' % - (ldif_file, e.errno, e.strerror)) - raise e + if (not self.ds_paths.perl_enabled or pyinstall): + raise Exception("Perl tools disabled on this system. Try dbgen py module.") + else: + try: + os.system('%s -s %s -n %d -o %s' % (os.path.join(self.ds_paths.bin_dir, 'dbgen.pl'), suffix, num, ldif_file)) + os.chmod(ldif_file, 0o644) + if os.getuid() == 0: + # root user - chown the ldif to the server user + uid = pwd.getpwnam(self.userid).pw_uid + gid = grp.getgrnam(self.userid).gr_gid + os.chown(ldif_file, uid, gid) + except OSError as e: + log.exception('Failed to create ldif file (%s): error %d - %s' % + (ldif_file, e.errno, e.strerror)) + raise e def getConsumerMaxCSN(self, replica_entry): """ diff --git a/lib389/_entry.py b/lib389/_entry.py index cf04817..b8cb4c4 100644 --- a/lib389/_entry.py +++ b/lib389/_entry.py @@ -63,7 +63,6 @@ class Entry(object): If creating a new empty entry, data is the string DN. """ self.ref = None - self.data = None if entrydata: if isinstance(entrydata, tuple): if entrydata[0] is None: @@ -74,12 +73,11 @@ class Entry(object): elif isinstance(entrydata, six.string_types): if '=' not in entrydata: raise ValueError('Entry dn must contain "="') - self.dn = entrydata self.data = cidict() else: - self.dn = '' self.data = cidict() + self.dn = None def __bool__(self): """ @@ -134,7 +132,7 @@ class Entry(object): # We can't actually enforce this because cidict doesn't inherit Mapping # if not isinstance(self.data, collections.Mapping): # raise Exception('Invalid data type for Entry') - return name in self.data + return ensure_str(name) in self.data def __getitem__(self, name): # This should probably return getValues? @@ -234,15 +232,21 @@ class Entry(object): """ # For python3, we have to make sure EVERYTHING is a byte string. # Else everything EXPLODES - lt = list(self.data.items()) + lt = None if MAJOR >= 3: - ltnew = [] - for l in lt: - vals = [] - for v in l[1]: - vals.append(ensure_bytes(v)) - ltnew.append((l[0], vals)) - lt = ltnew + # This converts the dict to a list of tuples, + lt = [] + for k in self.data.keys(): + # l here is the + vals = None + if isinstance(self.data[k], list) or isinstance(self.data[k], tuple): + vals = ensure_list_bytes(self.data[k]) + else: + vals = ensure_list_bytes([self.data[k]]) + lt.append((k, vals)) + # lt is now complete. + else: + lt = list(self.data.items()) return lt def getref(self): diff --git a/lib389/_mapped_object.py b/lib389/_mapped_object.py index c98f1bc..d4bfd0a 100644 --- a/lib389/_mapped_object.py +++ b/lib389/_mapped_object.py @@ -88,7 +88,7 @@ class DSLdapObject(DSLogging): # This allows some factor objects to be overriden self._dn = None if dn is not None: - self._dn = dn + self._dn = ensure_str(dn) self._batch = batch self._protected = True @@ -440,13 +440,13 @@ class DSLdapObject(DSLogging): v = properties.get(self._rdn_attribute) rdn = ensure_str(v[0]) - erdn = ldap.dn.escape_dn_chars(rdn) + erdn = ensure_str(ldap.dn.escape_dn_chars(rdn)) self._log.debug("Using first property %s: %s as rdn" % (self._rdn_attribute, erdn)) # Now we compare. If we changed this value, we have to put it back to make the properties complete. if erdn != rdn: properties[self._rdn_attribute].append(erdn) - tdn = '%s=%s,%s' % (self._rdn_attribute, erdn, basedn) + tdn = ensure_str('%s=%s,%s' % (self._rdn_attribute, erdn, basedn)) # We may need to map over the data in the properties dict to satisfy python-ldap str_props = {} @@ -458,11 +458,12 @@ class DSLdapObject(DSLogging): def create(self, rdn=None, properties=None, basedn=None): assert(len(self._create_objectclasses) > 0) + basedn = ensure_str(basedn) self._log.debug('Creating "%s" under %s : %s' % (rdn, basedn, properties)) # Add the objectClasses to the properties (dn, valid_props) = self._validate(rdn, properties, basedn) # Check if the entry exists or not? .add_s is going to error anyway ... - self._log.debug('Validated %s : %s' % (dn, valid_props)) + self._log.debug('Validated dn %s : valid_props %s' % (dn, valid_props)) e = Entry(dn) e.update({'objectclass': ensure_list_bytes(self._create_objectclasses)}) diff --git a/lib389/configurations/config_001003006.py b/lib389/configurations/config_001003006.py index 1089dc7..8c2895f 100644 --- a/lib389/configurations/config_001003006.py +++ b/lib389/configurations/config_001003006.py @@ -25,8 +25,7 @@ class c001003006_sample_entries(sampleentries): # All the checks are done, apply them. def _apply(self): # Create the base domain object - domain = Domain(self._instance) - domain._dn = self._basedn + domain = Domain(self._instance, dn=self._basedn) # Explode the dn to get the first bit. avas = dn.str2dn(self._basedn) dc_ava = avas[0][0][1] @@ -111,7 +110,7 @@ class c001003006(baseconfig): super(c001003006, self).__init__(instance) self._operations = [ # Create plugin configs first - c001003006_whoami_plugin(self._instance) + # c001003006_whoami_plugin(self._instance) # Create our sample entries. # op001003006_sample_entries(self._instance), ] diff --git a/lib389/configurations/sample.py b/lib389/configurations/sample.py index d0fbd16..a2292f5 100644 --- a/lib389/configurations/sample.py +++ b/lib389/configurations/sample.py @@ -6,10 +6,12 @@ # See LICENSE for details. # --- END COPYRIGHT BLOCK --- +from lib389.utils import ensure_str + class sampleentries(object): def __init__(self, instance, basedn): self._instance = instance - self._basedn = basedn + self._basedn = ensure_str(basedn) self.description = None def apply(self): diff --git a/lib389/dbgen.py b/lib389/dbgen.py new file mode 100644 index 0000000..a0cda94 --- /dev/null +++ b/lib389/dbgen.py @@ -0,0 +1,191 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2017 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- + +# Replacement of the dbgen.pl utility + +import random +import os +import pwd +import grp + +DBGEN_POSITIONS = [ +"Accountant", +"Admin", +"Architect", +"Assistant", +"Artist", +"Consultant", +"Czar", +"Dictator", +"Director", +"Diva", +"Dreamer", +"Evangelist", +"Engineer", +"Figurehead", +"Fellow", +"Grunt", +"Guru", +"Janitor", +"Madonna", +"Manager", +"Pinhead", +"President", +"Punk", +"Sales Rep", +"Stooge", +"Visionary", +"Vice President", +"Writer", +"Warrior", +"Yahoo" +] + +DBGEN_TITLE_LEVELS = [ +"Senior", +"Master", +"Associate", +"Junior", +"Chief", +"Supreme", +"Elite" +] + +DBGEN_LOCATIONS = [ +"Mountain View", "Redmond", "Redwood Shores", "Armonk", +"Cambridge", "Santa Clara", "Sunnyvale", "Alameda", +"Cupertino", "Menlo Park", "Palo Alto", "Orem", +"San Jose", "San Francisco", "Milpitas", "Hartford", "Windsor", +"Boston", "New York", "Detroit", "Dallas", "Denver", "Brisbane", +] + +DBGEN_OUS = [ +"Accounting", +"Product Development", +"Product Testing", +"Human Resources", +"Payroll", +] + +DBGEN_TEMPLATE = """dn: {DN} +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +cn: {FIRST} {LAST} +sn: {LAST} +uid: {UID} +givenName: {FIRST} +description: 2;7613;CN=Red Hat CS 71GA Demo,O=Red Hat CS 71GA Demo,C=US;CN=RHCS Agent - admin01,UID=admin01,O=redhat,C=US [1] This is {FIRST} {LAST}'s description. +userPassword: {UID} +departmentNumber: 1230 +employeeType: Manager +homePhone: +1 303 937-6482 +initials: {INITIALS} +telephoneNumber: +1 303 573-9570 +facsimileTelephoneNumber: +1 415 408-8176 +mobile: +1 818 618-1671 +pager: +1 804 339-6298 +roomNumber: 5164 +carLicense: 21SJJAG +l: {LOCATION} +ou: {OU} +mail: {FIRST}.{LAST}@example.com +postalAddress: 518, Dept #851, Room#{OU} +title: {TITLE} +usercertificate;binary:: MIIBvjCCASegAwIBAgIBAjANBgkqhkiG9w0BAQQFADAnMQ8wDQYD + VQQDEwZjb25maWcxFDASBgNVBAMTC01NUiBDQSBDZXJ0MB4XDTAxMDQwNTE1NTEwNloXDTExMDcw + NTE1NTEwNlowIzELMAkGA1UEChMCZnIxFDASBgNVBAMTC01NUiBTMSBDZXJ0MIGfMA0GCSqGSIb3 + DQEBAQUAA4GNADCBiQKBgQDNlmsKEaPD+o3mAUwmW4E40MPs7aiui1YhorST3KzVngMqe5PbObUH + MeJN7CLbq9SjXvdB3y2AoVl/s5UkgGz8krmJ8ELfUCU95AQls321RwBdLRjioiQ3MGJiFjxwYRIV + j1CUTuX1y8dC7BWvZ1/EB0yv0QDtp2oVMUeoK9/9sQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBADev + hxY6QyDMK3Mnr7vLGe/HWEZCObF+qEo2zWScGH0Q+dAmhkCCkNeHJoqGN4NWjTdnBcGaAr5Y85k1 + o/vOAMBsZePbYx4SrywL0b/OkOmQX+mQwieC2IQzvaBRyaNMh309vrF4w5kExReKfjR/gXpHiWQz + GSxC5LeQG4k3IP34 + +""" + +DBGEN_HEADER = """dn: {SUFFIX} +objectClass: top +objectClass: domain +dc: example +aci: (target=ldap:///{SUFFIX})(targetattr=*)(version 3.0; acl "acl1"; allow(write) userdn = "ldap:///self";) +aci: (target=ldap:///{SUFFIX})(targetattr=*)(version 3.0; acl "acl2"; allow(write) groupdn = "ldap:///cn=Directory Administrators, {SUFFIX}";) +aci: (target=ldap:///{SUFFIX})(targetattr=*)(version 3.0; acl "acl3"; allow(read, search, compare) userdn = "ldap:///anyone";) + +dn: ou=Accounting,{SUFFIX} +objectClass: top +objectClass: organizationalUnit +ou: Accounting + +dn: ou=Product Development,{SUFFIX} +objectClass: top +objectClass: organizationalUnit +ou: Product Development + +dn: ou=Product Testing,{SUFFIX} +objectClass: top +objectClass: organizationalUnit +ou: Product Testing + +dn: ou=Human Resources,{SUFFIX} +objectClass: top +objectClass: organizationalUnit +ou: Human Resources + +dn: ou=Payroll,{SUFFIX} +objectClass: top +objectClass: organizationalUnit +ou: Payroll + +""" + +def dbgen(instance, number, ldif_file, suffix): + familyname_file = os.path.join(instance.ds_paths.data_dir, 'dirsrv/data/dbgen-FamilyNames') + givename_file = os.path.join(instance.ds_paths.data_dir, 'dirsrv/data/dbgen-GivenNames') + familynames = [] + givennames = [] + with open(familyname_file, 'r') as f: + familynames = [n.strip() for n in f] + with open(givename_file, 'r') as f: + givennames = [n.strip() for n in f] + + with open(ldif_file, 'w') as output: + output.write(DBGEN_HEADER.format(SUFFIX=suffix)) + for i in range(0, number): + # Pick a random ou + ou = random.choice(DBGEN_OUS) + first = random.choice(givennames) + last = random.choice(familynames) + # How do we subscript from a generator? + initials = "%s. %s" % (first[0], last[0]) + uid = "%s%s%s" % (first[0], last, i) + dn = "uid=%s,ou=%s,%s" % (uid, ou, suffix) + l = random.choice(DBGEN_LOCATIONS) + title = "%s %s" % (random.choice(DBGEN_TITLE_LEVELS), random.choice(DBGEN_POSITIONS)) + output.write(DBGEN_TEMPLATE.format( + DN=dn, + UID=uid, + FIRST=first, + LAST=last, + INITIALS=initials, + OU=ou, + LOCATION=l, + TITLE=title, + SUFFIX=suffix + )) + + # Make the file owned by dirsrv + os.chmod(ldif_file, 0o644) + if os.getuid() == 0: + # root user - chown the ldif to the server user + uid = pwd.getpwnam(instance.userid).pw_uid + gid = grp.getgrnam(instance.userid).gr_gid + os.chown(ldif_file, uid, gid) + + diff --git a/lib389/idm/group.py b/lib389/idm/group.py index bcb15ed..8d6e232 100644 --- a/lib389/idm/group.py +++ b/lib389/idm/group.py @@ -46,7 +46,7 @@ class Groups(DSLdapObjects): ] self._filterattrs = [RDN] self._childobject = Group - self._basedn = '{},{}'.format(rdn, basedn) + self._basedn = '{},{}'.format(ensure_str(rdn), ensure_str(basedn)) class UniqueGroup(DSLdapObject): # WARNING!!! diff --git a/lib389/instance/remove.py b/lib389/instance/remove.py new file mode 100644 index 0000000..689b5bd --- /dev/null +++ b/lib389/instance/remove.py @@ -0,0 +1,54 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2016 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- + +import os +import shutil + +def remove_ds_instance(dirsrv): + """ + This will delete the instance as it is define. This must be a local instance. + """ + _log = dirsrv.log.getChild('remove_ds') + _log.debug("Removing instance %s" % dirsrv.serverid) + # Stop the instance (if running) + _log.debug("Stopping instance %s" % dirsrv.serverid) + dirsrv.stop() + # Copy all the paths we are about to tamp with + remove_paths = {} + remove_paths['backup_dir'] = dirsrv.ds_paths.backup_dir + remove_paths['cert_dir'] = dirsrv.ds_paths.cert_dir + remove_paths['config_dir'] = dirsrv.ds_paths.config_dir + remove_paths['db_dir'] = dirsrv.ds_paths.db_dir + remove_paths['ldif_dir'] = dirsrv.ds_paths.ldif_dir + remove_paths['lock_dir'] = dirsrv.ds_paths.lock_dir + remove_paths['log_dir'] = dirsrv.ds_paths.log_dir + remove_paths['run_dir'] = dirsrv.ds_paths.run_dir + + marker_path = "%s/sysconfig/dirsrv-%s" % (dirsrv.ds_paths.sysconf_dir, dirsrv.serverid) + + # Check the marker exists. If it *does not* warn about this, and say that to + # force removal you should touch this file. + + _log.debug("Checking for instance marker at %s" % marker_path) + assert os.path.exists(marker_path) + + # Remove these paths: + # for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', + # 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'): + for path_k in remove_paths: + if os.path.exists(remove_paths[path_k]): + _log.debug("Removing %s" % remove_paths[path_k]) + shutil.rmtree(remove_paths[path_k]) + + # Finally remove the sysconfig marker. + os.remove(marker_path) + _log.debug("Removing %s" % marker_path) + + # Done! + _log.debug("Complete") + diff --git a/lib389/instance/setup.py b/lib389/instance/setup.py index f7468d1..cc94b48 100644 --- a/lib389/instance/setup.py +++ b/lib389/instance/setup.py @@ -376,7 +376,7 @@ class SetupDs(object): if self.verbose: self.log.info("ACTION: Creating dse.ldif") dse = "" - with open(os.path.join(slapd['data_dir'], 'dirsrv', 'data', 'template-dse-minimal.ldif')) as template_dse: + with open(os.path.join(slapd['data_dir'], 'dirsrv', 'data', 'template-dse.ldif')) as template_dse: for line in template_dse.readlines(): dse += line.replace('%', '{', 1).replace('%', '}', 1) @@ -452,14 +452,3 @@ class SetupDs(object): if self.containerised: ds_instance.stop() - def _remove_ds(self): - """ - The opposite of install: Removes an instance from the system. - This takes a backup of all relevant data, and removes the paths. - """ - # This probably actually would need to be able to read the ldif, to - # know what to remove ... - for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', - 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'): - print(path) - diff --git a/lib389/passwd.py b/lib389/passwd.py index 58d6637..f36d73e 100644 --- a/lib389/passwd.py +++ b/lib389/passwd.py @@ -35,7 +35,7 @@ PWSCHEMES = [ def password_hash(pw, scheme=BESTSCHEME, bin_dir='/bin'): # Check that the binary exists assert(scheme in PWSCHEMES) - pwdhashbin = os.path.join(bin_dir, 'pwdhash-bin') + pwdhashbin = os.path.join(bin_dir, 'pwdhash') assert(os.path.isfile(pwdhashbin)) h = subprocess.check_output([pwdhashbin, '-s', scheme, pw]).strip() return h.decode('utf-8') diff --git a/lib389/paths.py b/lib389/paths.py index f0a4c1b..cc2f6cd 100644 --- a/lib389/paths.py +++ b/lib389/paths.py @@ -139,6 +139,7 @@ class Paths(object): return True def __getattr__(self, name): + from lib389.utils import ensure_str if self._defaults_cached is False: self._read_defaults() self._validate_defaults() @@ -147,12 +148,12 @@ class Paths(object): # Get the online value. (dn, attr) = CONFIG_MAP[name] ent = self._instance.getEntry(dn, attrlist=[attr,]) - return ent.getValue(attr) + return ensure_str(ent.getValue(attr)) elif self._serverid is not None: - return self._config.get(SECTION, name).format(instance_name=self._serverid) + return ensure_str(self._config.get(SECTION, name).format(instance_name=self._serverid)) else: - return self._config.get(SECTION, name) + return ensure_str(self._config.get(SECTION, name)) @property def asan_enabled(self): @@ -173,3 +174,13 @@ class Paths(object): if self._config.get(SECTION, 'with_systemd') == '1': return True return False + + @property + def perl_enabled(self): + if self._defaults_cached is False: + self._read_defaults() + self._validate_defaults() + if self._config.has_option(SECTION, 'enable_perl'): + if self._config.get(SECTION, 'enable_perl') == 'no': + return False + return True diff --git a/lib389/tasks.py b/lib389/tasks.py index 2c62dce..7deb87b 100644 --- a/lib389/tasks.py +++ b/lib389/tasks.py @@ -18,7 +18,7 @@ from lib389.exceptions import Error from lib389._constants import ( DEFAULT_SUFFIX, DEFAULT_BENAME, DN_EXPORT_TASK, DN_BACKUP_TASK, DN_IMPORT_TASK, DN_RESTORE_TASK, DN_INDEX_TASK, DN_MBO_TASK, - DN_TOMB_FIXUP_TASK, DN_TASKS + DN_TOMB_FIXUP_TASK, DN_TASKS, DIRSRV_STATE_ONLINE ) from lib389.properties import ( TASK_WAIT, EXPORT_REPL_INFO, MT_PROPNAME_TO_ATTRNAME, MT_SUFFIX, @@ -153,6 +153,8 @@ class Tasks(object): @raise ValueError ''' + if self.conn.state != DIRSRV_STATE_ONLINE: + raise ValueError("Invalid Server State %s! Must be online" % self.conn.state) # Checking the parameters if not benamebase and not suffix: @@ -177,11 +179,7 @@ class Tasks(object): entry.setValues('nsIncludeSuffix', suffix) # start the task and possibly wait for task completion - try: - self.conn.add_s(entry) - except ldap.ALREADY_EXISTS: - self.log.error("Fail to add the import task of %s" % input_file) - return -1 + self.conn.add_s(entry) exitCode = 0 if args and args.get(TASK_WAIT, False): diff --git a/lib389/tests/instance/setup_test.py b/lib389/tests/instance/setup_test.py index 04ae34f..aa2d13b 100644 --- a/lib389/tests/instance/setup_test.py +++ b/lib389/tests/instance/setup_test.py @@ -12,6 +12,7 @@ import pytest from lib389 import DirSrv from lib389.cli_base import LogCapture from lib389.instance.setup import SetupDs +from lib389.instance.remove import remove_ds_instance from lib389.instance.options import General2Base, Slapd2Base from lib389._constants import * @@ -105,6 +106,8 @@ def test_setup_ds_minimal(topology): # Make sure we can start stop. topology.standalone.stop() topology.standalone.start() + # Okay, actually remove the instance + remove_ds_instance(topology.standalone) def test_setup_ds_inf_minimal(topology): diff --git a/lib389/topologies.py b/lib389/topologies.py index 19d121d..58e52c6 100644 --- a/lib389/topologies.py +++ b/lib389/topologies.py @@ -76,6 +76,7 @@ def topology_st(request): args_standalone = args_instance.copy() standalone.allocate(args_standalone) instance_standalone = standalone.exists() + standalone.log.debug("instance_standalone %s" % instance_standalone) if instance_standalone: standalone.delete() standalone.create() -- 1.8.3.1