This is an automated email from the git hooks/post-receive script.
firstyear pushed a commit to branch master
in repository lib389.
commit 2a50b9d0bdf9a7939916c6f6e127de58a3a6de97
Author: William Brown <firstyear(a)redhat.com>
Date: Mon Aug 7 15:53:13 2017 +1000
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: spichugi (Thank you!)
---
lib389/__init__.py | 50 ++++----
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 | 4 +-
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 +
13 files changed, 325 insertions(+), 65 deletions(-)
diff --git a/lib389/__init__.py b/lib389/__init__.py
index 4f6dafb..6a96089 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):
'''
@@ -3036,7 +3041,7 @@ class DirSrv(SimpleLDAPObject, object):
self.set_option(ldap.OPT_SERVER_CONTROLS, [])
return resp_data, decoded_resp_ctrls
- def buildLDIF(self, num, ldif_file, suffix='dc=example,dc=com'):
+ def buildLDIF(self, num, ldif_file, suffix='dc=example,dc=com',
pyinstall=False):
"""Generate a simple ldif file using the dbgen.pl script, and set
the
ownership and permissions to match the user that the server runs as.
@@ -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}(a)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..5de1294 100644
--- a/lib389/idm/group.py
+++ b/lib389/idm/group.py
@@ -7,7 +7,7 @@
# --- END COPYRIGHT BLOCK ---
from lib389._mapped_object import DSLdapObject, DSLdapObjects
-from lib389.utils import ds_is_older
+from lib389.utils import ds_is_older, ensure_str
MUST_ATTRIBUTES = [
'cn',
@@ -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):
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.