From 2031ed0d72680354d3363d9cf115ebf6f40a9b65 Mon Sep 17 00:00:00 2001 From: William Brown Date: Feb 18 2019 23:18:04 +0000 Subject: Ticket 50224 - warnings on deprecated API usage Bug Description: There have been many cases of incorrect and invalid api usage. As we go on, we can't allow more usage of these apis to be added as it only puts more work on us in the future to remove. Fix Description: Add deprecation warnings to these apis, telling people they will be removed, and where their faulty code is. https://pagure.io/389-ds-base/issue/50224 Author: William Brown Review by: mreynolds (Thanks!) --- diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py index 652129f..5b6b90e 100644 --- a/dirsrvtests/tests/suites/basic/basic_test.py +++ b/dirsrvtests/tests/suites/basic/basic_test.py @@ -50,9 +50,10 @@ def import_example_ldif(topology_st): ldif = '%s/dirsrv/data/Example.ldif' % topology_st.standalone.get_data_dir() import_ldif = topology_st.standalone.get_ldif_dir() + "/Example.ldif" shutil.copyfile(ldif, import_ldif) - topology_st.standalone.tasks.importLDIF(suffix=DEFAULT_SUFFIX, - input_file=import_ldif, - args={TASK_WAIT: True}) + + r = ImportTask(topology_st.standalone) + r.import_suffix_from_ldif(ldiffile=import_ldif, suffix=DEFAULT_SUFFIX) + r.wait() @pytest.fixture(params=ROOTDSE_DEF_ATTR_LIST) @@ -260,13 +261,9 @@ def test_basic_import_export(topology_st, import_example_ldif): dbgen(topology_st.standalone, 50000, import_ldif, DEFAULT_SUFFIX) # Online - try: - topology_st.standalone.tasks.importLDIF(suffix=DEFAULT_SUFFIX, - input_file=import_ldif, - args={TASK_WAIT: True}) - except ValueError: - log.fatal('test_basic_import_export: Online import failed') - assert False + r = ImportTask(topology_st.standalone) + r.import_suffix_from_ldif(ldiffile=import_ldif, suffix=DEFAULT_SUFFIX) + r.wait() # Offline topology_st.standalone.stop() @@ -281,13 +278,11 @@ def test_basic_import_export(topology_st, import_example_ldif): # Online export export_ldif = ldif_dir + '/export.ldif' - exportTask = Tasks(topology_st.standalone) - try: - args = {TASK_WAIT: True} - exportTask.exportLDIF(DEFAULT_SUFFIX, None, export_ldif, args) - except ValueError: - log.fatal('test_basic_import_export: Online export failed') - assert False + + + r = ExportTask(topology_st.standalone) + r.export_suffix_to_ldif(ldiffile=export_ldif, suffix=DEFAULT_SUFFIX) + r.wait() # Offline export topology_st.standalone.stop() @@ -304,13 +299,10 @@ def test_basic_import_export(topology_st, import_example_ldif): ldif = '%s/dirsrv/data/Example.ldif' % topology_st.standalone.get_data_dir() import_ldif = topology_st.standalone.get_ldif_dir() + "/Example.ldif" shutil.copyfile(ldif, import_ldif) - try: - topology_st.standalone.tasks.importLDIF(suffix=DEFAULT_SUFFIX, - input_file=import_ldif, - args={TASK_WAIT: True}) - except ValueError: - log.fatal('test_basic_import_export: Online import failed') - assert False + + r = ImportTask(topology_st.standalone) + r.import_suffix_from_ldif(ldiffile=import_ldif, suffix=DEFAULT_SUFFIX) + r.wait() log.info('test_basic_import_export: PASSED') diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py index 5e91dbc..1d0d693 100644 --- a/src/lib389/lib389/__init__.py +++ b/src/lib389/lib389/__init__.py @@ -58,6 +58,10 @@ import json from shutil import copy2 import six +# Deprecation +import warnings +import inspect + from ldap.ldapobject import SimpleLDAPObject from ldap.cidict import cidict from ldap import LDAPError @@ -105,6 +109,8 @@ RE_DBMONATTRSUN = re.compile(r'^([a-zA-Z]+)-([a-zA-Z]+)$') # This controls pyldap debug levels TRACE_LEVEL = 0 +DEBUGGING = os.getenv('DEBUGGING', default=False) + # My logger logger = logging.getLogger(__name__) @@ -131,6 +137,59 @@ def wrapper(f, name): extract the raw data from the entry object to pass in. """ def inner(*args, **kwargs): + if name in [ + 'add_s', + 'bind_s', + 'delete_s', + 'modify_s', + 'modrdn_s', + 'rename_s', + 'sasl_interactive_bind_s', + 'search_s', + 'search_ext_s', + 'simple_bind_s', + 'unbind_s', + 'getEntry', + ] and not ('escapehatch' in kwargs and kwargs['escapehatch'] == 'i am sure'): + c_stack = inspect.stack() + frame = c_stack[1] + + + warnings.warn(DeprecationWarning("Use of raw ldap function %s. This will removed in a future release. Found in: %s:%s" % (name, frame.filename, frame.lineno))) + if not DEBUGGING: + sys.stderr.write(""" +________________________________________ +/ YOU ARE USING A DEPRECATED AND INVALID \\ +| LIB389 API. YOU PROBABLY WANT A | +| DSLDAPOBJECT INSTEAD! | +| | +| IN THE FUTURE THIS WILL CRASH YOUR | +| APPLICATION | +| | +\\ %s found at %s:%s / + ---------------------------------------- + \\ / \ //\\ + \\ |\\___/| / \\// \\\\ + /0 0 \\__ / // | \\ \\ + / / \\/_/ // | \\ \\ + @_^_@'/ \\/_ // | \\ \\ + //_^_/ \\/_ // | \\ \\ + ( //) | \\/// | \\ \\ + ( / /) _|_ / ) // | \\ _\\ + ( // /) '/,_ _ _/ ( ; -. | _ _\\.-~ .-~~~^-. + (( / / )) ,-{ _ `-.|.-~-. .~ `. + (( // / )) '/\\ / ~-. _ .-~ .-~^-. \\ + (( /// )) `. { } / \\ \\ + (( / )) .----~-.\\ \\-' .~ \\ `. \\^-. + ///.----..> \\ _ -~ `. ^-` ^-_ + ///-._ _ _ _ _ _ _}^ - - - - ~ ~-- ,.-~ + /.-~ + """ % (name, frame.filename, frame.lineno)) + # Later, we will add a sleep here to make it even more painful. + # Finally, it will raise an exception. + elif 'escapehatch' in kwargs: + kwargs.pop('escapehatch') + if name == 'result': objtype, data = f(*args, **kwargs) # data is either a 2-tuple or a list of 2-tuples @@ -292,7 +351,7 @@ class DirSrv(SimpleLDAPObject, object): else: super(DirSrv, self).__init__(uri, trace_level=TRACE_LEVEL) # self.start_tls_s() - self.simple_bind_s(ensure_str(self.binddn), self.bindpw) + self.simple_bind_s(ensure_str(self.binddn), self.bindpw, escapehatch='i am sure') def __add_brookers__(self): from lib389.config import Config @@ -999,22 +1058,22 @@ class DirSrv(SimpleLDAPObject, object): self.set_option(ldap.OPT_X_TLS_NEWCTX, 0) if starttls and not uri.startswith('ldaps'): - self.start_tls_s() + self.start_tls_s(escapehatch='i am sure') if saslmethod and sasltoken is not None: # Just pass the sasltoken in! - self.sasl_interactive_bind_s("", sasltoken) + self.sasl_interactive_bind_s("", sasltoken, escapehatch='i am sure') elif saslmethod and saslmethod.lower() == 'gssapi': """ Perform kerberos/gssapi authentication """ sasl_auth = ldap.sasl.gssapi("") - self.sasl_interactive_bind_s("", sasl_auth) + self.sasl_interactive_bind_s("", sasl_auth, escapehatch='i am sure') elif saslmethod == 'EXTERNAL': # Do nothing. sasl_auth = ldap.sasl.external() - self.sasl_interactive_bind_s("", sasl_auth) + self.sasl_interactive_bind_s("", sasl_auth, escapehatch='i am sure') elif saslmethod: # Unknown or unsupported method self.log.debug('Unsupported SASL method: %s', saslmethod) @@ -1025,14 +1084,14 @@ class DirSrv(SimpleLDAPObject, object): # do nothing: the bind is complete. self.log.debug("open(): Using root autobind ...") sasl_auth = ldap.sasl.external() - self.sasl_interactive_bind_s("", sasl_auth) + self.sasl_interactive_bind_s("", sasl_auth, escapehatch='i am sure') else: """ Do a simple bind """ try: - self.simple_bind_s(ensure_str(self.binddn), self.bindpw) + self.simple_bind_s(ensure_str(self.binddn), self.bindpw, escapehatch='i am sure') except ldap.SERVER_DOWN as e: # TODO add server info in exception self.log.debug("Cannot connect to %r", uri) @@ -1064,7 +1123,7 @@ class DirSrv(SimpleLDAPObject, object): # check that DirSrv was in DIRSRV_STATE_ONLINE state if self.state == DIRSRV_STATE_ONLINE: # Don't raise an error. Just move the state and return - self.unbind_s() + self.unbind_s(escapehatch='i am sure') self.state = DIRSRV_STATE_OFFLINE @@ -3331,11 +3390,11 @@ class DirSrv(SimpleLDAPObject, object): return status def delete_branch_s(self, basedn, scope, filterstr="(objectclass=*)", serverctrls=None, clientctrls=None): - ents = self.search_s(basedn, scope, filterstr) + ents = self.search_s(basedn, scope, filterstr, escapehatch='i am sure') for ent in sorted(ents, key=lambda e: len(e.dn), reverse=True): self.log.debug("Delete entry children %s", ent.dn) - self.delete_ext_s(ent.dn, serverctrls=serverctrls, clientctrls=clientctrls) + self.delete_ext_s(ent.dn, serverctrls=serverctrls, clientctrls=clientctrls, escapehatch='i am sure') def backup_online(self, archive=None, db_type=None): """Creates a backup of the database""" diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py index 1dd8825..9c5e0bd 100644 --- a/src/lib389/lib389/_mapped_object.py +++ b/src/lib389/lib389/_mapped_object.py @@ -121,13 +121,13 @@ class DSLdapObject(DSLogging): def __str__(self): return self.__unicode__() - def raw_entry(self): + def _unsafe_raw_entry(self): """Get an Entry object :returns: Entry object """ - return self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*"], serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + return self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*"], serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] def exists(self): """Check if the entry exists @@ -136,7 +136,7 @@ class DSLdapObject(DSLogging): """ try: - self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls) + self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') except ldap.NO_SUCH_OBJECT: return False @@ -148,7 +148,7 @@ class DSLdapObject(DSLogging): :returns: LDIF formatted string """ - e = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*"], serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + e = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*"], serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] return e.__repr__() def display_attr(self, attr): @@ -225,7 +225,7 @@ class DSLdapObject(DSLogging): raise ValueError("Invalid state. Cannot get presence on instance that is not ONLINE") self._log.debug("%s present(%r) %s" % (self._dn, attr, value)) - e = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[attr, ], serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + e = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[attr, ], serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] values = self.get_attr_vals_bytes(attr) self._log.debug("%s contains %s" % (self._dn, values)) @@ -278,7 +278,7 @@ class DSLdapObject(DSLogging): else: value = [ensure_bytes(arg[1])] mods.append((ldap.MOD_REPLACE, ensure_str(arg[0]), value)) - return self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls) + return self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') # This needs to work on key + val, and key def remove(self, key, value): @@ -373,7 +373,7 @@ class DSLdapObject(DSLogging): value = [ensure_bytes(value)] return self._instance.modify_ext_s(self._dn, [(action, key, value)], - serverctrls=self._server_controls, clientctrls=self._client_controls) + serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') def apply_mods(self, mods): """Perform modification operation using several mods at once @@ -411,7 +411,7 @@ class DSLdapObject(DSLogging): else: # Error too many items raise ValueError('Too many arguments in the mod op') - return self._instance.modify_ext_s(self._dn, mod_list, serverctrls=self._server_controls, clientctrls=self._client_controls) + return self._instance.modify_ext_s(self._dn, mod_list, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') @classmethod def compare(cls, obj1, obj2): @@ -478,7 +478,7 @@ class DSLdapObject(DSLogging): raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE") else: # retrieving real(*) and operational attributes(+) - attrs_entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*", "+"], serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + attrs_entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*", "+"], serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] # getting dict from 'entry' object attrs_dict = attrs_entry.data return attrs_dict @@ -488,14 +488,14 @@ class DSLdapObject(DSLogging): if self._instance.state != DIRSRV_STATE_ONLINE: raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE") else: - entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys, serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] return entry.getValuesSet(keys) def get_attrs_vals_utf8(self, keys, use_json=False): self._log.debug("%s get_attrs_vals_utf8(%r)" % (self._dn, keys)) if self._instance.state != DIRSRV_STATE_ONLINE: raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE") - entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys, serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] vset = entry.getValuesSet(keys) r = {} for (k, vo) in vset.items(): @@ -513,7 +513,7 @@ class DSLdapObject(DSLogging): else: # It would be good to prevent the entry code intercepting this .... # We have to do this in this method, because else we ignore the scope base. - entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[key], serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[key], serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] vals = entry.getValues(key) if use_json: result = {key: []} @@ -531,7 +531,7 @@ class DSLdapObject(DSLogging): # In the future, I plan to add a mode where if local == true, we # can use get on dse.ldif to get values offline. else: - entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[key], serverctrls=self._server_controls, clientctrls=self._client_controls)[0] + entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[key], serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0] return entry.getValue(key) def get_attr_val_bytes(self, key, use_json=False): @@ -659,7 +659,7 @@ class DSLdapObject(DSLogging): # and the superior as the base (if it changed) if self._protected: return - self._instance.rename_s(self._dn, new_rdn, newsuperior, serverctrls=self._server_controls, clientctrls=self._client_controls) + self._instance.rename_s(self._dn, new_rdn, newsuperior, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') search_base = self._basedn if newsuperior != None: # Well, the new DN should be rdn + newsuperior. @@ -681,7 +681,7 @@ class DSLdapObject(DSLogging): self._log.debug("%s delete" % (self._dn)) if not self._protected: # Is there a way to mark this as offline and kill it - self._instance.delete_ext_s(self._dn, serverctrls=self._server_controls, clientctrls=self._client_controls) + self._instance.delete_ext_s(self._dn, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') def _validate(self, rdn, properties, basedn): """Used to validate a create request. @@ -767,7 +767,7 @@ class DSLdapObject(DSLogging): exists = False try: - self._instance.search_ext_s(dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls) + self._instance.search_ext_s(dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') exists = True except ldap.NO_SUCH_OBJECT: pass @@ -780,7 +780,7 @@ class DSLdapObject(DSLogging): mods = [] for k, v in list(valid_props.items()): mods.append((ldap.MOD_REPLACE, k, v)) - self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls) + self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') elif exists and not ensure: # raise "already exists." raise ldap.ALREADY_EXISTS("Entry %s already exists" % dn) @@ -791,7 +791,7 @@ class DSLdapObject(DSLogging): e.update(valid_props) # We rely on exceptions here to indicate failure to the parent. self._log.debug('Creating entry %s : %s' % (dn, e)) - self._instance.add_ext_s(e, serverctrls=self._server_controls, clientctrls=self._client_controls) + self._instance.add_ext_s(e, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') # If it worked, we need to fix our instance dn self._dn = dn return self @@ -918,7 +918,8 @@ class DSLdapObjects(DSLogging): scope=self._scope, filterstr=filterstr, attrlist=self._list_attrlist, - serverctrls=self._server_controls, clientctrls=self._client_controls + serverctrls=self._server_controls, clientctrls=self._client_controls, + escapehatch='i am sure' ) # def __init__(self, instance, dn=None): insts = [self._entry_to_instance(dn=r.dn, entry=r) for r in results] @@ -966,7 +967,8 @@ class DSLdapObjects(DSLogging): scope=ldap.SCOPE_BASE, filterstr=filterstr, attrlist=self._list_attrlist, - serverctrls=self._server_controls, clientctrls=self._client_controls + serverctrls=self._server_controls, clientctrls=self._client_controls, + escapehatch='i am sure' ) def _get_selector(self, selector): @@ -980,7 +982,8 @@ class DSLdapObjects(DSLogging): scope=self._scope, filterstr=filterstr, attrlist=self._list_attrlist, - serverctrls=self._server_controls, clientctrls=self._client_controls + serverctrls=self._server_controls, clientctrls=self._client_controls, + escapehatch='i am sure' ) def _validate(self, rdn, properties): diff --git a/src/lib389/lib389/idm/account.py b/src/lib389/lib389/idm/account.py index 5dd325b..729f0b4 100644 --- a/src/lib389/lib389/idm/account.py +++ b/src/lib389/lib389/idm/account.py @@ -59,7 +59,7 @@ class Account(DSLdapObject): :param password: An entry password :type password: str """ - self._instance.simple_bind_s(self.dn, password) + self._instance.simple_bind_s(self.dn, password, escapehatch='i am sure') def sasl_bind(self, *args, **kwargs): """Open a new connection and bind with the entry via SASL. @@ -140,7 +140,7 @@ class Account(DSLdapObject): # Please see _mapped_object.py and DSLdapObject for why this is structured # in this way re-controls. self._instance.passwd_s(self._dn, current_password, new_password, - serverctrls=self._server_controls, clientctrls=self._client_controls) + serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure') class Accounts(DSLdapObjects): """DSLdapObjects that represents Account entry diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py index daf3978..8878e51 100644 --- a/src/lib389/lib389/tasks.py +++ b/src/lib389/lib389/tasks.py @@ -38,11 +38,21 @@ class Task(DSLdapObject): self._protected = False self._exit_code = None + def status(self): + """Return the decoded status of the task + """ + return self.get_attr_val_utf8('nsTaskStatus') + def is_complete(self): """Return True if task is complete, else False.""" - self._exit_code = self.get_attr_val("nsTaskExitCode") - if not self.exists() or self._exit_code is not None: + self._exit_code = self.get_attr_val_utf8("nsTaskExitCode") + if not self.exists(): + self._log.debug("complete: task has self cleaned ...") + # The task cleaned it self up. + return True + elif self._exit_code is not None: + self._log.debug("complete status: %s -> %s" % (self._exit_code, self.status())) return True return False @@ -243,11 +253,24 @@ class ImportTask(Task): def __init__(self, instance, dn=None): self.cn = 'import_' + Task._get_task_date() - dn = "cn=" + self.cn + ",cn=import," + DN_TASKS + dn = "cn=%s,%s" % (self.cn, DN_IMPORT_TASK) self._properties = None super(ImportTask, self).__init__(instance, dn) + # We can add all the needed and valid option combos here. + def import_suffix_from_ldif(self, ldiffile, suffix): + # TODO: Check that the arguments we were given are valid combinations. + # Write out new ones. + _properties = { + 'nsFilename': ldiffile, + 'nsIncludeSuffix': suffix, + } + self.create(properties=_properties) + + # The correlating function would be import_backend_from_ldif which + # would list a bename not suffix + class ExportTask(Task): """Create the export to ldif task @@ -258,11 +281,18 @@ class ExportTask(Task): def __init__(self, instance, dn=None): self.cn = 'export_' + Task._get_task_date() - dn = "cn=" + self.cn + ",cn=export," + DN_TASKS + dn = "cn=%s,%s" % (self.cn, DN_EXPORT_TASK) self._properties = None super(ExportTask, self).__init__(instance, dn) + def export_suffix_to_ldif(self, ldiffile, suffix): + _properties = { + 'nsFilename': ldiffile, + 'nsIncludeSuffix': suffix, + } + self.create(properties=_properties) + class BackupTask(Task): """Create the backup DB task diff --git a/src/lib389/lib389/tombstone.py b/src/lib389/lib389/tombstone.py index 839fc3e..527f601 100644 --- a/src/lib389/lib389/tombstone.py +++ b/src/lib389/lib389/tombstone.py @@ -35,7 +35,7 @@ class Tombstone(DSLdapObject): # We need to always add this filter, else we won't see the ts self._object_filter = '(&(objectclass=nsTombStone)({}))'.format(self._entry_rdn) - def raw_entry(self): + def _unsafe_raw_entry(self): """Get an Entry object :returns: Entry object