Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR - Added python3 support and code fixes. [WIP] #3346

Closed
389-ds-bot opened this issue Sep 13, 2020 · 80 comments
Closed

PR - Added python3 support and code fixes. [WIP] #3346

389-ds-bot opened this issue Sep 13, 2020 · 80 comments
Labels
merged Migration flag - PR pr Migration flag - PR

Comments

@389-ds-bot
Copy link

389-ds-bot commented Sep 13, 2020

Cloned from Pagure Pull-Request: https://pagure.io/389-ds-base/pull-request/50287

  • Created at 2019-03-18 11:46:03 by aadhikari
  • Merged at 2019-08-13 15:28:46

Description: Added py3 support by explicitly changing strings to bytes.
Codes are fixed, which are stated in each commit.

Resolves: #2647

Reviewed by: ??

@389-ds-bot 389-ds-bot added merged Migration flag - PR pr Migration flag - PR labels Sep 13, 2020
@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:33:09

Don't duplicate this, use strcmdline = " ".join(cmdline) instead.

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:33:30

Sleep? Is there a better way?

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:34:13

Probably means you have a candidate for rewriting this modify to use the Plugin(DSldapObjects) api ....

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:34:19

And here.

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:34:26

And here.

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:34:56

Isn't there a "replication manager" dsldapobject you can use instead? IIRC I made one for the replication code a few years back.

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-19 01:36:26

In general, if you are going to port from py2 -> py3, that doesn't mean slap bytes on it, it means rewrite parts that need dsldapobjects instead.

I also would actually propose removing that crypto/tls cipher count test. It breaks every verison, it proves nothing, and generally is annoying to maintain in any capacity. I'd rather just remove it. @droideck may have a comment on that though ....

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 06:52:23

Isn't there a "replication manager" dsldapobject you can use instead? IIRC I made one for the replication code a few years back.

It is, but in the test, replication is actually working but giving an invalid credential error for replication manager. I could not access the service accounts, so I have created another manager.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 07:49:48

In general, if you are going to port from py2 -> py3, that doesn't mean slap bytes on it, it means rewrite parts that need dsldapobjects instead.
I also would actually propose removing that crypto/tls cipher count test. It breaks every verison, it proves nothing, and generally is annoying to maintain in any capacity. I'd rather just remove it.
+1
@droideck may have a comment on that though...

I agree, py2 -> py3 is not just adding bytes, but there are a lot of failures which needs to be fixed first so that build quality could be analyzed first. there are a lot of tests which are failing and we are unable to have a proper say on the builds. We actually wanna avoid it as much we can, anyways I will still see we can quickly remove this :)

@389-ds-bot
Copy link
Author

Comment from mhonek (@kenoh) at 2019-03-19 10:36:40

The associated commit message is entirely wrong.

EDIT: I meant the other one (3c7d46224 for dirsrvtests/tests/tickets/ticket48194_test.py).

@389-ds-bot
Copy link
Author

Comment from mhonek (@kenoh) at 2019-03-19 10:40:53

Please explain what and why this fixes. What's the actual error? This really needs a comprehensive commit message.

@389-ds-bot
Copy link
Author

Comment from mhonek (@kenoh) at 2019-03-19 10:44:32

Why this hardcoded value? Where does it come from? Cannot it be pulled in from anywhere?

@389-ds-bot
Copy link
Author

Comment from mhonek (@kenoh) at 2019-03-19 10:57:51

AFAICT this file's change effectively removes a test for a feature from cab38f9 introduced just a few weeks ago. What is the story here?

@389-ds-bot
Copy link
Author

Comment from mhonek (@kenoh) at 2019-03-19 10:59:35

This was introduced 3 weeks ago - why is this wrong? (not saying it is not, just need an explanation)

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 14:02:46

rebased onto 4737790b289136ab3d3e65dfa04626f09b28815d

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 14:41:23

1 new commit added

  • Revert "Description: Fixed the test by changing passwordInHistory value to 1,"

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 14:57:51

5 new commits added

  • Description: Added py3 support by explicitly changing strings to bytes.
  • Description: Fixed the test by removing "cn:RSA" entry from the test,
  • Description: Added py3 support by explicitly changing strings to bytes.
  • Description: Fixed the test by change replication manager's value.
  • Description: Fixed the test by changing passwordInHistory value to 1,

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 15:05:54

5 new commits added

  • Description: Description: Fixed the test by changing passwordInHistory value to 1,
  • Description: Fixed the test by removing "cn:RSA" entry from the test,
  • Description: Added py3 support by explicitly changing strings to bytes.
  • Description: Fixed the test by change replication manager's value.
  • Description: Fixed the test by changing passwordInHistory value to 1,

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 15:50:06

5 new commits added

  • Description: Fixed the test by removing "cn:RSA" entry from the second test,
  • Description: Fixed the test by removing "cn:RSA" entry from the test,
  • Description: Added py3 support by explicitly changing strings to bytes.
  • Description: Fixed the test by change replication manager's value.
  • Description: Fixed the test by changing passwordInHistory value to 1,

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 16:10:50

rebased onto 024aa5b302ffa054f65dc54520040f27517514fb

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 16:15:28

This was introduced 3 weeks ago - why is this wrong? (not saying it is not, just need an explanation)

Was having some merge conflict issue, resolved and fixed. also, meaningful commit message is been added.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 17:27:39

This was introduced 3 weeks ago - why is this wrong? (not saying it is not, just need an explanation)

Was having some merge conflict issue, resolved and fixed. also, meaningful commit message is been added.

@kenoh But I see them passing in the latest builds will remove it from the commit.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 18:07:34

rebased onto 8b7328b3d9947db82e8cbdba63cb1dd839c4a832

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-19 18:16:58

Please explain what and why this fixes. What's the actual error? This really needs a comprehensive commit message.

I will paste a complete output of the error, one was the cn=RSA entry which I removed. Will update with the error if the changes in the code are not done.

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-03-20 01:08:32

I think the openssl test is pretty bad anyway, like ... we are testing something that is really dynamic and fragile, and a bit, not our problem?

@389-ds-bot
Copy link
Author

Comment from mhonek (@kenoh) at 2019-03-20 01:54:12

@aadhikari Out of curiosity, what is the build you're testing?

In general, tests should definitely pass on master. If they don't pass on older builds then relevant fixes are welcome of course, but only those that don't break the tests on master. E.g. with pwp_history_test.py here, (it should have been done so before, but we can do it now, too) we can properly make the test conditional using ds_is_older or ds_is_newer so that it passes on versions without the new feature and those with it, too.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-03-20 08:32:50

@aadhikari Out of curiosity, what is the build you're testing?
In general, tests should definitely pass on master. If they don't pass on older builds then relevant fixes are welcome of course, but only those that don't break the tests on master. E.g. with pwp_history_test.py here, (it should have been done so before, but we can do it now, too) we can properly make the test conditional using ds_is_older or ds_is_newer so that it passes on versions without the new feature and those with it, too.

@kenoh I was testing on 389-ds-base: 1.4.0.21-1.fc29 and 389-ds-base: 1.4.1.1-20190320gitf16615485.fc29.

Also what I observed is the timing of the sleep. The same code may not Rework for the first time but can work for the second time.

Just for the clarification:
Result for build: 1.4.0.21-1.fc29 - https://paste.fedoraproject.org/paste/Xg3NZ61ilVgI0aT7Eej~iw
Result for build: 389-ds-base: 1.4.1.1-20190320gitf16615485.fc29 - https://paste.fedoraproject.org/paste/AJ~65WXImPX5ZDWZVeIqLw
Result form latest build: https://paste.fedoraproject.org/paste/KXRROyTs66LCS62hiHNBeg

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-06-11 11:28:17

setup-ds.pl is deprecated, and may cause this test to break. What does the update do that you require? Consider running your test with --disable-perl on ./configure, and youll see where perl breaks things. If anything we shouldn't use def runUpgrade as a result ....

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-12 06:38:44

Subprocess shouldn't need a "string", because it takes an array, so actually you would want "cmdline = strcmdline.split[" "]" and then give that to subprocess, and remove the "shell=True" option as it's insecure. nss_ssl.py has great examples of secure cli subprocess usage.

the strcmdline is just for printing what we are executing if you see the whole code will give a better idea, BTW this change is done by your suggestion only.

Don't duplicate this, use strcmdline = " ".join(cmdline) instead.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-12 06:39:59

What does this option do? Could be good to comment this ....

This is already being mentioned in the previous comments(At the start of the test), if that what you are asking?

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-12 06:54:50

setup-ds.pl is deprecated, and may cause this test to break. What does the update do that you require? Consider running your test with --disable-perl on ./configure, and youll see where perl breaks things. If anything we shouldn't use def runUpgrade as a result ....

@Firstyear I think, setup-ds.pl is deprecated but it is still consumed by RHEL 7 and many other OS and these will still be present for a very long time. Rather than using only the latest way, I think ds_older check can be used here but we still need to fix runUpgrade. Tell me a better way of doing this because we cannot ignore older versions. BTW is there anything similar to runUpgrade in lib389 for the the dscreate? because that can be used here with ds_check.
Thanks!

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-12 06:59:56

Have a look at the function definition in replica.py: def init(self, instance, dn='cn=replication manager,cn=config'):. You don't need "defaultProperties[...]". Remember, lots of parts of lib389 are made to "do the right thing, in the simplest way"!

Oops, fixing these changes right away!

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-12 08:04:43

I think you only need "userPassword" attribute here, no cn needs to be provided?

I think cn is needed, getting this: ldap.UNWILLING_TO_PERFORM: Attribute cn must not be None

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-12 08:23:18

rebased onto 96a37764e0267187f1ef10ae1e35b8fa61bc1ef8

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-06-12 09:33:39

setup-ds.pl is deprecated, and may cause this test to break. What does the update do that you require? Consider running your test with --disable-perl on ./configure, and youll see where perl breaks things. If anything we shouldn't use def runUpgrade as a result ....

Should we have a version check in runUpgrade then to check if it's 1.3.x or lower?

@Firstyear I think, setup-ds.pl is deprecated but it is still consumed by RHEL 7 and many other OS and these will still be present for a very long time. Rather than using only the latest way, I think ds_older check can be used here but we still need to fix runUpgrade. Tell me a better way of doing this because we cannot ignore older versions. BTW is there anything similar to runUpgrade in lib389 for the the dscreate? because that can be used here with ds_check.
Thanks!

1.4.x, upgrades should be done "inside the server" at startup, else we fail to work with docker. Today, I don't think we have a fully agreed mechanism for this, but there is inplace an internal upgrade system already in ns-slapd so simply restarting is sufficient. But we may need to discuss and clarify this as a team to be completely sure.

As for the cn being needed, yep, ignore my comment then :) I always thought that interface was simpler to use, so may I have forgotten something.

And I think you answered my other questions. Thanks!

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-17 09:10:15

setup-ds.pl is deprecated, and may cause this test to break. What does the update do that you require? Consider running your test with --disable-perl on ./configure, and youll see where perl breaks things. If anything we shouldn't use def runUpgrade as a result ....

Should we have a version check in runUpgrade then to check if it's 1.3.x or lower?

Correct a check in the upgrade like if it is 1.3.x then do the things else just pass? Do you think that is fine? But in that case also we need to fix the byte issue inside runUpgrade correct?

@Firstyear I think, setup-ds.pl is deprecated but it is still consumed by RHEL 7 and many other OS and these will still be present for a very long time. Rather than using only the latest way, I think ds_older check can be used here but we still need to fix runUpgrade. Tell me a better way of doing this because we cannot ignore older versions. BTW is there anything similar to runUpgrade in lib389 for the the dscreate? because that can be used here with ds_check.
Thanks!

1.4.x, upgrades should be done "inside the server" at startup, else we fail to work with docker. Today, I don't think we have a fully agreed mechanism for this, but there is inplace an internal upgrade system already in ns-slapd so simply restarting is sufficient. But we may need to discuss and clarify this as a team to be completely sure.
As for the cn being needed, yep, ignore my comment then :) I always thought that interface was simpler to use, so may I have forgotten something.
And I think you answered my other questions. Thanks!

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-06-18 09:01:17

Correct a check in the upgrade like if it is 1.3.x then do the things else just pass? Do you think that is fine? But in that case also we need to fix the byte issue inside runUpgrade correct?

Yes I think that would be fine.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-19 11:40:36

rebased onto 570a2d12281884b023b4a43f404fff9d436174ed

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-19 11:46:18

@Firstyear ds_is_older('1.4.0') is added so that all older version of DS can use the script, not sure in which version exactly it will be removed, as I see 1.4 version have a legacy tool package which can be used as if now, but it will be removed in future. So should we do this in this way or make it work specifically in 1.3.x or lower?

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-06-19 14:15:06

No - you may not call any perl tool from lib389 for 1.4.x. There is a "--disable-perl" flag in the ./configure, and no pl tools will be generated or emited. You must assume all 1.4.x installs run with this setting, and the pl tools as "legacy" are just for installing/removing/admin tools.

So it must only call any pl tools with 1.3.x or lower.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-19 15:24:11

No - you may not call any perl tool from lib389 for 1.4.x. There is a "--disable-perl" flag in the ./configure, and no pl tools will be generated or emited. You must assume all 1.4.x installs run with this setting, and the pl tools as "legacy" are just for installing/removing/admin tools.
So it must only call any pl tools with 1.3.x or lower.

@Firstyear I did ds_is_older('1.4.0') that means it cover our requirement correct?

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-19 15:24:44

@Firstyear for 1.4.x it won't run the script.

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-06-19 15:47:19

Great! that's what I wanted to hear.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-20 11:01:52

@Firstyear So everything is good in the patch?

BTW, new findings, I ran the tests on a machine having 1.4 just to be sure, so it didn't run the update script as expected but the test failed. Seems like the internal upgrade system in ns-slapd is not working, I have restarted the server as mentioned by you. Any idea?

@389-ds-bot
Copy link
Author

Comment from firstyear (@Firstyear) at 2019-06-20 11:38:48

@aadhikari The internal upgrade does work, if you are finding something missing, then it means we need to port/add the upgrade requirements to the server core. So you'll need to report what the upgrade is meant to do, and how it's meant to work into an issue so we can implement it in the main server code.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-24 09:50:11

@Firstyear Here is the trace log and the whole run of the test, it failed to find AES plugin: No such object

[root@fedora29-aadhikar1 389-ds-base]# py.test-3 -v dirsrvtests/tests/tickets/ticket47462_test.py 
============================================================================ test session starts ============================================================================
platform linux -- Python 3.7.3, pytest-3.6.4, py-1.5.4, pluggy-0.6.0 -- /usr/bin/python3
cachedir: dirsrvtests/.pytest_cache
metadata: {'Python': '3.7.3', 'Platform': 'Linux-4.18.16-300.fc29.x86_64-x86_64-with-fedora-29-Twenty_Nine', 'Packages': {'pytest': '3.6.4', 'py': '1.5.4', 'pluggy': '0.6.0'}, 'Plugins': {'metadata': '1.8.0', 'html': '1.20.0'}}
389-ds-base: 1.4.0.23-1.fc29
nss: 3.44.0-2.fc29
nspr: 4.21.0-1.fc29
openldap: 2.4.46-10.fc29
cyrus-sasl: not installed
FIPS: disabled
rootdir: /root/389-ds-base/dirsrvtests, inifile: pytest.ini
plugins: metadata-1.8.0, html-1.20.0
collected 1 item                                                                                                                                                            

dirsrvtests/tests/tickets/ticket47462_test.py::test_ticket47462 FAILED                                                                                                [100%]

================================================================================= FAILURES ==================================================================================
_____________________________________________________________________________ test_ticket47462 ______________________________________________________________________________

topology_m2 = <lib389.topologies.TopologyMain object at 0x7fec22c603c8>

    def test_ticket47462(topology_m2):
        """
            Test that AES properly replaces DES during an update/restart, and that
            replication also works correctly.
        """
    
        #
        # First set config as if it's an older version.  Set DES to use
        # libdes-plugin, MMR to depend on DES, delete the existing AES plugin,
        # and set a DES password for the replication agreement.
        #
        # Add an extra attribute to the DES plugin args
        #
        plugin_des = Plugin(topology_m2.ms["master1"], DES_PLUGIN)
        plugin_des.set('nsslapd-pluginEnabled', 'on')
        plugin_des.set('nsslapd-pluginarg2', 'description')
    
        plugin_mmr = Plugin(topology_m2.ms["master1"], MMR_PLUGIN)
        plugin_mmr.remove('nsslapd-plugin-depends-on-named', 'AES')
        #
        # Delete the AES plugin
        #
        topology_m2.ms["master1"].delete_s(AES_PLUGIN)
        # restart the server so we must use DES plugin
        topology_m2.ms["master1"].restart(timeout=10)
    
        manager = BootstrapReplicationManager(topology_m2.ms["master2"])
    
        manager.create(properties={
                    'cn': 'replication manager',
                    'userPassword': 'password'
        })
    
        DN = topology_m2.ms["master2"].replica._get_mt_entry(DEFAULT_SUFFIX)
    
        topology_m2.ms["master2"].modify_s(DN, [(ldap.MOD_REPLACE,
                                                 'nsDS5ReplicaBindDN', ensure_bytes(defaultProperties[REPLICATION_BIND_DN]))])
        #
        # Create repl agreement from the newly promoted master to master1
    
        properties = {RA_NAME: 'meTo_{}:{}'.format(topology_m2.ms["master2"].host,
                                                   str(topology_m2.ms["master2"].port)),
                      RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
                      RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
                      RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
                      RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
        topology_m2.ms["master1"].agreement.create(suffix=SUFFIX,
                                                   host=topology_m2.ms["master2"].host,
                                                   port=topology_m2.ms["master2"].port,
                                                   properties=properties)
        #
        # Check replication works with the new DES password
        #
        try:
            topology_m2.ms["master1"].add_s(Entry((USER1_DN,
                                                   {'objectclass': "top person".split(),
                                                    'sn': 'sn',
                                                    'description': 'DES value to convert',
                                                    'cn': 'test_user'})))
            loop = 0
            ent = None
            while loop <= 10:
                try:
                    ent = topology_m2.ms["master2"].getEntry(USER1_DN, ldap.SCOPE_BASE,
                                                             "(objectclass=*)")
                    break
                except ldap.NO_SUCH_OBJECT:
                    time.sleep(1)
                    loop += 1
            if not ent:
                log.fatal('Replication test failed fo user1!')
                assert False
            else:
                log.info('Replication test passed')
        except ldap.LDAPError as e:
            log.fatal('Failed to add test user: ' + e.args[0]['desc'])
            assert False
    
        #
        # Add a backend (that has no entries)
        #
        try:
            topology_m2.ms["master1"].backend.create("o=empty", {BACKEND_NAME: "empty"})
        except ldap.LDAPError as e:
            log.fatal('Failed to create extra/empty backend: ' + e.args[0]['desc'])
            assert False
    
        #
        # Run the upgrade...
        #
        topology_m2.ms["master1"].stop()
        topology_m2.ms["master2"].stop()
        #import pdb;pdb.set_trace()
        topology_m2.ms["master1"].upgrade('offline')
        topology_m2.ms["master1"].restart()
        topology_m2.ms["master2"].restart()
    
        #
        # Check that the restart converted existing DES credentials
        #
        try:
            entry = topology_m2.ms["master1"].search_s('cn=config', ldap.SCOPE_SUBTREE,
                                                       'nsDS5ReplicaCredentials=*')
            if entry:
                val = entry[0].getValue('nsDS5ReplicaCredentials')
                if val.startswith(b'{AES-'):
                    log.info('The DES credentials have been converted to AES')
                else:
                    log.fatal('Failed to convert credentials from DES to AES!')
                    assert False
            else:
                log.fatal('Failed to find entries with nsDS5ReplicaCredentials')
                assert False
        except ldap.LDAPError as e:
            log.fatal('Failed to search for replica credentials: ' +
                      e.args[0]['desc'])
            assert False
    
        #
        # Check that the AES plugin exists, and has all the attributes listed in
        # DES plugin.  The attributes might not be in the expected order so check
        # all the attributes.
        #
        try:
            entry = topology_m2.ms["master1"].search_s(AES_PLUGIN, ldap.SCOPE_BASE,
>                                                      'objectclass=*')

dirsrvtests/tests/tickets/ticket47462_test.py:162: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = ('cn=AES,cn=Password Storage Schemes,cn=plugins,cn=config', 0, 'objectclass=*'), kwargs = {}

    def inner(*args, **kwargs):
        if name == 'result':
            objtype, data = f(*args, **kwargs)
            # data is either a 2-tuple or a list of 2-tuples
            # print data
            if data:
                if isinstance(data, tuple):
                    return objtype, Entry(data)
                elif isinstance(data, list):
                    # AD sends back these search references
                    # if objtype == ldap.RES_SEARCH_RESULT and \
                    #    isinstance(data[-1],tuple) and \
                    #    not data[-1][0]:
                    #     print "Received search reference: "
                    #     pprint.pprint(data[-1][1])
                    #     data.pop() # remove the last non-entry element
    
                    return objtype, [Entry(x) for x in data]
                else:
                    raise TypeError("unknown data type %s returned by result" %
                                    type(data))
            else:
                return objtype, data
        elif name.startswith('add'):
            # the first arg is self
            # the second and third arg are the dn and the data to send
            # We need to convert the Entry into the format used by
            # python-ldap
            ent = args[0]
            if isinstance(ent, Entry):
                return f(ent.dn, ent.toTupleList(), *args[2:])
            else:
                return f(*args, **kwargs)
        else:
>           return f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:167: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, base = 'cn=AES,cn=Password Storage Schemes,cn=plugins,cn=config', scope = 0, filterstr = 'objectclass=*', attrlist = None
attrsonly = 0

    def search_s(self,base,scope,filterstr=None,attrlist=None,attrsonly=0):
>     return self.search_ext_s(base,scope,filterstr,attrlist,attrsonly,None,None,timeout=self.timeout)

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:852: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = ('cn=AES,cn=Password Storage Schemes,cn=plugins,cn=config', 0, 'objectclass=*', None, 0, None, ...), kwargs = {'timeout': -1}

    def inner(*args, **kwargs):
        if name == 'result':
            objtype, data = f(*args, **kwargs)
            # data is either a 2-tuple or a list of 2-tuples
            # print data
            if data:
                if isinstance(data, tuple):
                    return objtype, Entry(data)
                elif isinstance(data, list):
                    # AD sends back these search references
                    # if objtype == ldap.RES_SEARCH_RESULT and \
                    #    isinstance(data[-1],tuple) and \
                    #    not data[-1][0]:
                    #     print "Received search reference: "
                    #     pprint.pprint(data[-1][1])
                    #     data.pop() # remove the last non-entry element
    
                    return objtype, [Entry(x) for x in data]
                else:
                    raise TypeError("unknown data type %s returned by result" %
                                    type(data))
            else:
                return objtype, data
        elif name.startswith('add'):
            # the first arg is self
            # the second and third arg are the dn and the data to send
            # We need to convert the Entry into the format used by
            # python-ldap
            ent = args[0]
            if isinstance(ent, Entry):
                return f(ent.dn, ent.toTupleList(), *args[2:])
            else:
                return f(*args, **kwargs)
        else:
>           return f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:167: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, base = 'cn=AES,cn=Password Storage Schemes,cn=plugins,cn=config', scope = 0, filterstr = 'objectclass=*', attrlist = None
attrsonly = 0, serverctrls = None, clientctrls = None, timeout = -1, sizelimit = 0

    def search_ext_s(self,base,scope,filterstr=None,attrlist=None,attrsonly=0,serverctrls=None,clientctrls=None,timeout=-1,sizelimit=0):
      msgid = self.search_ext(base,scope,filterstr,attrlist,attrsonly,serverctrls,clientctrls,timeout,sizelimit)
>     return self.result(msgid,all=1,timeout=timeout)[1]

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:846: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = (3,), kwargs = {'all': 1, 'timeout': -1}

    def inner(*args, **kwargs):
        if name == 'result':
>           objtype, data = f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:135: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, msgid = 3, all = 1, timeout = -1

    def result(self,msgid=ldap.RES_ANY,all=1,timeout=None):
      """
        result([msgid=RES_ANY [,all=1 [,timeout=None]]]) -> (result_type, result_data)
    
            This method is used to wait for and return the result of an
            operation previously initiated by one of the LDAP asynchronous
            operation routines (e.g. search(), modify(), etc.) They all
            returned an invocation identifier (a message id) upon successful
            initiation of their operation. This id is guaranteed to be
            unique across an LDAP session, and can be used to request the
            result of a specific operation via the msgid parameter of the
            result() method.
    
            If the result of a specific operation is required, msgid should
            be set to the invocation message id returned when the operation
            was initiated; otherwise RES_ANY should be supplied.
    
            The all parameter only has meaning for search() responses
            and is used to select whether a single entry of the search
            response should be returned, or to wait for all the results
            of the search before returning.
    
            A search response is made up of zero or more search entries
            followed by a search result. If all is 0, search entries will
            be returned one at a time as they come in, via separate calls
            to result(). If all is 1, the search response will be returned
            in its entirety, i.e. after all entries and the final search
            result have been received.
    
            For all set to 0, result tuples
            trickle in (with the same message id), and with the result type
            RES_SEARCH_ENTRY, until the final result which has a result
            type of RES_SEARCH_RESULT and a (usually) empty data field.
            When all is set to 1, only one result is returned, with a
            result type of RES_SEARCH_RESULT, and all the result tuples
            listed in the data field.
    
            The method returns a tuple of the form (result_type,
            result_data).  The result_type is one of the constants RES_*.
    
            See search() for a description of the search result's
            result_data, otherwise the result_data is normally meaningless.
    
            The result() method will block for timeout seconds, or
            indefinitely if timeout is negative.  A timeout of 0 will effect
            a poll. The timeout can be expressed as a floating-point value.
            If timeout is None the default in self.timeout is used.
    
            If a timeout occurs, a TIMEOUT exception is raised, unless
            polling (timeout = 0), in which case (None, None) is returned.
        """
>     resp_type, resp_data, resp_msgid = self.result2(msgid,all,timeout)

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:738: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = (3, 1, -1), kwargs = {}

    def inner(*args, **kwargs):
        if name == 'result':
            objtype, data = f(*args, **kwargs)
            # data is either a 2-tuple or a list of 2-tuples
            # print data
            if data:
                if isinstance(data, tuple):
                    return objtype, Entry(data)
                elif isinstance(data, list):
                    # AD sends back these search references
                    # if objtype == ldap.RES_SEARCH_RESULT and \
                    #    isinstance(data[-1],tuple) and \
                    #    not data[-1][0]:
                    #     print "Received search reference: "
                    #     pprint.pprint(data[-1][1])
                    #     data.pop() # remove the last non-entry element
    
                    return objtype, [Entry(x) for x in data]
                else:
                    raise TypeError("unknown data type %s returned by result" %
                                    type(data))
            else:
                return objtype, data
        elif name.startswith('add'):
            # the first arg is self
            # the second and third arg are the dn and the data to send
            # We need to convert the Entry into the format used by
            # python-ldap
            ent = args[0]
            if isinstance(ent, Entry):
                return f(ent.dn, ent.toTupleList(), *args[2:])
            else:
                return f(*args, **kwargs)
        else:
>           return f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:167: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, msgid = 3, all = 1, timeout = -1

    def result2(self,msgid=ldap.RES_ANY,all=1,timeout=None):
>     resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all,timeout)

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:742: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = (3, 1, -1), kwargs = {}

    def inner(*args, **kwargs):
        if name == 'result':
            objtype, data = f(*args, **kwargs)
            # data is either a 2-tuple or a list of 2-tuples
            # print data
            if data:
                if isinstance(data, tuple):
                    return objtype, Entry(data)
                elif isinstance(data, list):
                    # AD sends back these search references
                    # if objtype == ldap.RES_SEARCH_RESULT and \
                    #    isinstance(data[-1],tuple) and \
                    #    not data[-1][0]:
                    #     print "Received search reference: "
                    #     pprint.pprint(data[-1][1])
                    #     data.pop() # remove the last non-entry element
    
                    return objtype, [Entry(x) for x in data]
                else:
                    raise TypeError("unknown data type %s returned by result" %
                                    type(data))
            else:
                return objtype, data
        elif name.startswith('add'):
            # the first arg is self
            # the second and third arg are the dn and the data to send
            # We need to convert the Entry into the format used by
            # python-ldap
            ent = args[0]
            if isinstance(ent, Entry):
                return f(ent.dn, ent.toTupleList(), *args[2:])
            else:
                return f(*args, **kwargs)
        else:
>           return f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:167: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, msgid = 3, all = 1, timeout = -1, resp_ctrl_classes = None

    def result3(self,msgid=ldap.RES_ANY,all=1,timeout=None,resp_ctrl_classes=None):
      resp_type, resp_data, resp_msgid, decoded_resp_ctrls, retoid, retval = self.result4(
        msgid,all,timeout,
        add_ctrls=0,add_intermediates=0,add_extop=0,
>       resp_ctrl_classes=resp_ctrl_classes
      )

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:749: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = (3, 1, -1), kwargs = {'add_ctrls': 0, 'add_extop': 0, 'add_intermediates': 0, 'resp_ctrl_classes': None}

    def inner(*args, **kwargs):
        if name == 'result':
            objtype, data = f(*args, **kwargs)
            # data is either a 2-tuple or a list of 2-tuples
            # print data
            if data:
                if isinstance(data, tuple):
                    return objtype, Entry(data)
                elif isinstance(data, list):
                    # AD sends back these search references
                    # if objtype == ldap.RES_SEARCH_RESULT and \
                    #    isinstance(data[-1],tuple) and \
                    #    not data[-1][0]:
                    #     print "Received search reference: "
                    #     pprint.pprint(data[-1][1])
                    #     data.pop() # remove the last non-entry element
    
                    return objtype, [Entry(x) for x in data]
                else:
                    raise TypeError("unknown data type %s returned by result" %
                                    type(data))
            else:
                return objtype, data
        elif name.startswith('add'):
            # the first arg is self
            # the second and third arg are the dn and the data to send
            # We need to convert the Entry into the format used by
            # python-ldap
            ent = args[0]
            if isinstance(ent, Entry):
                return f(ent.dn, ent.toTupleList(), *args[2:])
            else:
                return f(*args, **kwargs)
        else:
>           return f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:167: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, msgid = 3, all = 1, timeout = -1, add_ctrls = 0, add_intermediates = 0, add_extop = 0, resp_ctrl_classes = None

    def result4(self,msgid=ldap.RES_ANY,all=1,timeout=None,add_ctrls=0,add_intermediates=0,add_extop=0,resp_ctrl_classes=None):
      if timeout is None:
        timeout = self.timeout
>     ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop)

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:756: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = (<built-in method result4 of LDAP object at 0x7fec22d8cd50>, 3, 1, -1, 0, 0, ...), kwargs = {}

    def inner(*args, **kwargs):
        if name == 'result':
            objtype, data = f(*args, **kwargs)
            # data is either a 2-tuple or a list of 2-tuples
            # print data
            if data:
                if isinstance(data, tuple):
                    return objtype, Entry(data)
                elif isinstance(data, list):
                    # AD sends back these search references
                    # if objtype == ldap.RES_SEARCH_RESULT and \
                    #    isinstance(data[-1],tuple) and \
                    #    not data[-1][0]:
                    #     print "Received search reference: "
                    #     pprint.pprint(data[-1][1])
                    #     data.pop() # remove the last non-entry element
    
                    return objtype, [Entry(x) for x in data]
                else:
                    raise TypeError("unknown data type %s returned by result" %
                                    type(data))
            else:
                return objtype, data
        elif name.startswith('add'):
            # the first arg is self
            # the second and third arg are the dn and the data to send
            # We need to convert the Entry into the format used by
            # python-ldap
            ent = args[0]
            if isinstance(ent, Entry):
                return f(ent.dn, ent.toTupleList(), *args[2:])
            else:
                return f(*args, **kwargs)
        else:
>           return f(*args, **kwargs)

/usr/lib/python3.7/site-packages/lib389/__init__.py:167: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, func = <built-in method result4 of LDAP object at 0x7fec22d8cd50>, args = (3, 1, -1, 0, 0, 0), kwargs = {}
diagnostic_message_success = None, exc_type = None, exc_value = None, exc_traceback = None

    def _ldap_call(self,func,*args,**kwargs):
      """
        Wrapper method mainly for serializing calls into OpenLDAP libs
        and trace logs
        """
      self._ldap_object_lock.acquire()
      if __debug__:
        if self._trace_level>=1:
          self._trace_file.write('*** %s %s - %s\n%s\n' % (
            repr(self),
            self._uri,
            '.'.join((self.__class__.__name__,func.__name__)),
            pprint.pformat((args,kwargs))
          ))
          if self._trace_level>=9:
            traceback.print_stack(limit=self._trace_stack_limit,file=self._trace_file)
      diagnostic_message_success = None
      try:
        try:
          result = func(*args,**kwargs)
          if __debug__ and self._trace_level>=2:
            if func.__name__!="unbind_ext":
              diagnostic_message_success = self._l.get_option(ldap.OPT_DIAGNOSTIC_MESSAGE)
        finally:
          self._ldap_object_lock.release()
      except LDAPError as e:
        exc_type,exc_value,exc_traceback = sys.exc_info()
        try:
          if 'info' not in e.args[0] and 'errno' in e.args[0]:
            e.args[0]['info'] = strerror(e.args[0]['errno'])
        except IndexError:
          pass
        if __debug__ and self._trace_level>=2:
          self._trace_file.write('=> LDAPError - %s: %s\n' % (e.__class__.__name__,str(e)))
        try:
>         reraise(exc_type, exc_value, exc_traceback)

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:329: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

exc_type = <class 'ldap.NO_SUCH_OBJECT'>, exc_value = NO_SUCH_OBJECT({'desc': 'No such object'}), exc_traceback = <traceback object at 0x7fec22c0d648>

    def reraise(exc_type, exc_value, exc_traceback):
        """Re-raise an exception given information from sys.exc_info()
    
            Note that unlike six.reraise, this does not support replacing the
            traceback. All arguments must come from a single sys.exc_info() call.
            """
        # In Python 3, all exception info is contained in one object.
>       raise exc_value

/usr/lib64/python3.7/site-packages/ldap/compat.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <lib389.DirSrv object at 0x7fec22d1a358>, func = <built-in method result4 of LDAP object at 0x7fec22d8cd50>, args = (3, 1, -1, 0, 0, 0), kwargs = {}
diagnostic_message_success = None, exc_type = None, exc_value = None, exc_traceback = None

    def _ldap_call(self,func,*args,**kwargs):
      """
        Wrapper method mainly for serializing calls into OpenLDAP libs
        and trace logs
        """
      self._ldap_object_lock.acquire()
      if __debug__:
        if self._trace_level>=1:
          self._trace_file.write('*** %s %s - %s\n%s\n' % (
            repr(self),
            self._uri,
            '.'.join((self.__class__.__name__,func.__name__)),
            pprint.pformat((args,kwargs))
          ))
          if self._trace_level>=9:
            traceback.print_stack(limit=self._trace_stack_limit,file=self._trace_file)
      diagnostic_message_success = None
      try:
        try:
>         result = func(*args,**kwargs)
E         ldap.NO_SUCH_OBJECT: {'desc': 'No such object'}

/usr/lib64/python3.7/site-packages/ldap/ldapobject.py:313: NO_SUCH_OBJECT

During handling of the above exception, another exception occurred:

topology_m2 = <lib389.topologies.TopologyMain object at 0x7fec22c603c8>

    def test_ticket47462(topology_m2):
        """
            Test that AES properly replaces DES during an update/restart, and that
            replication also works correctly.
        """
    
        #
        # First set config as if it's an older version.  Set DES to use
        # libdes-plugin, MMR to depend on DES, delete the existing AES plugin,
        # and set a DES password for the replication agreement.
        #
        # Add an extra attribute to the DES plugin args
        #
        plugin_des = Plugin(topology_m2.ms["master1"], DES_PLUGIN)
        plugin_des.set('nsslapd-pluginEnabled', 'on')
        plugin_des.set('nsslapd-pluginarg2', 'description')
    
        plugin_mmr = Plugin(topology_m2.ms["master1"], MMR_PLUGIN)
        plugin_mmr.remove('nsslapd-plugin-depends-on-named', 'AES')
        #
        # Delete the AES plugin
        #
        topology_m2.ms["master1"].delete_s(AES_PLUGIN)
        # restart the server so we must use DES plugin
        topology_m2.ms["master1"].restart(timeout=10)
    
        manager = BootstrapReplicationManager(topology_m2.ms["master2"])
    
        manager.create(properties={
                    'cn': 'replication manager',
                    'userPassword': 'password'
        })
    
        DN = topology_m2.ms["master2"].replica._get_mt_entry(DEFAULT_SUFFIX)
    
        topology_m2.ms["master2"].modify_s(DN, [(ldap.MOD_REPLACE,
                                                 'nsDS5ReplicaBindDN', ensure_bytes(defaultProperties[REPLICATION_BIND_DN]))])
        #
        # Create repl agreement from the newly promoted master to master1
    
        properties = {RA_NAME: 'meTo_{}:{}'.format(topology_m2.ms["master2"].host,
                                                   str(topology_m2.ms["master2"].port)),
                      RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
                      RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
                      RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
                      RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
        topology_m2.ms["master1"].agreement.create(suffix=SUFFIX,
                                                   host=topology_m2.ms["master2"].host,
                                                   port=topology_m2.ms["master2"].port,
                                                   properties=properties)
        #
        # Check replication works with the new DES password
        #
        try:
            topology_m2.ms["master1"].add_s(Entry((USER1_DN,
                                                   {'objectclass': "top person".split(),
                                                    'sn': 'sn',
                                                    'description': 'DES value to convert',
                                                    'cn': 'test_user'})))
            loop = 0
            ent = None
            while loop <= 10:
                try:
                    ent = topology_m2.ms["master2"].getEntry(USER1_DN, ldap.SCOPE_BASE,
                                                             "(objectclass=*)")
                    break
                except ldap.NO_SUCH_OBJECT:
                    time.sleep(1)
                    loop += 1
            if not ent:
                log.fatal('Replication test failed fo user1!')
                assert False
            else:
                log.info('Replication test passed')
        except ldap.LDAPError as e:
            log.fatal('Failed to add test user: ' + e.args[0]['desc'])
            assert False
    
        #
        # Add a backend (that has no entries)
        #
        try:
            topology_m2.ms["master1"].backend.create("o=empty", {BACKEND_NAME: "empty"})
        except ldap.LDAPError as e:
            log.fatal('Failed to create extra/empty backend: ' + e.args[0]['desc'])
            assert False
    
        #
        # Run the upgrade...
        #
        topology_m2.ms["master1"].stop()
        topology_m2.ms["master2"].stop()
        #import pdb;pdb.set_trace()
        topology_m2.ms["master1"].upgrade('offline')
        topology_m2.ms["master1"].restart()
        topology_m2.ms["master2"].restart()
    
        #
        # Check that the restart converted existing DES credentials
        #
        try:
            entry = topology_m2.ms["master1"].search_s('cn=config', ldap.SCOPE_SUBTREE,
                                                       'nsDS5ReplicaCredentials=*')
            if entry:
                val = entry[0].getValue('nsDS5ReplicaCredentials')
                if val.startswith(b'{AES-'):
                    log.info('The DES credentials have been converted to AES')
                else:
                    log.fatal('Failed to convert credentials from DES to AES!')
                    assert False
            else:
                log.fatal('Failed to find entries with nsDS5ReplicaCredentials')
                assert False
        except ldap.LDAPError as e:
            log.fatal('Failed to search for replica credentials: ' +
                      e.args[0]['desc'])
            assert False
    
        #
        # Check that the AES plugin exists, and has all the attributes listed in
        # DES plugin.  The attributes might not be in the expected order so check
        # all the attributes.
        #
        try:
            entry = topology_m2.ms["master1"].search_s(AES_PLUGIN, ldap.SCOPE_BASE,
                                                       'objectclass=*')
            if not entry[0].hasValue('nsslapd-pluginarg0', 'description') and \
                    not entry[0].hasValue('nsslapd-pluginarg1', 'description') and \
                    not entry[0].hasValue('nsslapd-pluginarg2', 'description'):
                log.fatal('The AES plugin did not have the DES attribute copied ' +
                          'over correctly')
                assert False
            else:
                log.info('The AES plugin was correctly setup')
        except ldap.LDAPError as e:
            log.fatal('Failed to find AES plugin: ' + e.args[0]['desc'])
>           assert False
E           assert False

dirsrvtests/tests/tickets/ticket47462_test.py:173: AssertionError
--------------------------------------------------------------------------- Captured stdout setup ---------------------------------------------------------------------------
Instance slapd-master1 removed.
Instance slapd-master2 removed.
--------------------------------------------------------------------------- Captured stderr setup ---------------------------------------------------------------------------
INFO:lib389.topologies:Instance with parameters {'ldap-port': 39001, 'ldap-secureport': 63701, 'server-id': 'master1', 'suffix': 'dc=example,dc=com'} was created.
INFO:lib389.topologies:Instance with parameters {'ldap-port': 39002, 'ldap-secureport': 63702, 'server-id': 'master2', 'suffix': 'dc=example,dc=com'} was created.
INFO:lib389.topologies:Creating replication topology.
INFO:lib389.topologies:Joining master master2 to master1 ...
INFO:lib389.replica:SUCCESS: bootstrap to ldap://fedora29-aadhikar1:39002 completed
INFO:lib389.replica:SUCCESS: Agreement from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002 is was created
INFO:lib389.replica:SUCCESS: Agreement from ldap://fedora29-aadhikar1:39002 to ldap://fedora29-aadhikar1:39001 is was created
INFO:lib389.replica:SUCCESS: Replication from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002 is working
INFO:lib389.replica:SUCCESS: Replication from ldap://fedora29-aadhikar1:39002 to ldap://fedora29-aadhikar1:39001 is working
INFO:lib389.replica:SUCCESS: joined master from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002
INFO:lib389.topologies:Ensuring master master1 to master2 ...
INFO:lib389.replica:SUCCESS: Agreement from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002 already exists
INFO:lib389.topologies:Ensuring master master2 to master1 ...
INFO:lib389.replica:SUCCESS: Agreement from ldap://fedora29-aadhikar1:39002 to ldap://fedora29-aadhikar1:39001 already exists
---------------------------------------------------------------------------- Captured log setup -----------------------------------------------------------------------------
topologies.py              106 INFO     Instance with parameters {'ldap-port': 39001, 'ldap-secureport': 63701, 'server-id': 'master1', 'suffix': 'dc=example,dc=com'} was created.
topologies.py              106 INFO     Instance with parameters {'ldap-port': 39002, 'ldap-secureport': 63702, 'server-id': 'master2', 'suffix': 'dc=example,dc=com'} was created.
topologies.py              139 INFO     Creating replication topology.
topologies.py              153 INFO     Joining master master2 to master1 ...
replica.py                1533 INFO     SUCCESS: bootstrap to ldap://fedora29-aadhikar1:39002 completed
replica.py                1814 INFO     SUCCESS: Agreement from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002 is was created
replica.py                1814 INFO     SUCCESS: Agreement from ldap://fedora29-aadhikar1:39002 to ldap://fedora29-aadhikar1:39001 is was created
replica.py                1945 INFO     SUCCESS: Replication from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002 is working
replica.py                1945 INFO     SUCCESS: Replication from ldap://fedora29-aadhikar1:39002 to ldap://fedora29-aadhikar1:39001 is working
replica.py                1602 INFO     SUCCESS: joined master from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002
topologies.py              161 INFO     Ensuring master master1 to master2 ...
replica.py                1787 INFO     SUCCESS: Agreement from ldap://fedora29-aadhikar1:39001 to ldap://fedora29-aadhikar1:39002 already exists
topologies.py              161 INFO     Ensuring master master2 to master1 ...
replica.py                1787 INFO     SUCCESS: Agreement from ldap://fedora29-aadhikar1:39002 to ldap://fedora29-aadhikar1:39001 already exists
--------------------------------------------------------------------------- Captured stderr call ----------------------------------------------------------------------------
INFO:dirsrvtests.tests.tickets.ticket47462_test:Replication test passed
INFO:lib389:List backend with suffix=o=empty
INFO:lib389:Creating a local backend
INFO:lib389:List backend cn=empty,cn=ldbm database,cn=plugins,cn=config
INFO:lib389:Found entry dn: cn=empty,cn=ldbm database,cn=plugins,cn=config
cn: empty
nsslapd-cachememsize: 512000
nsslapd-cachesize: -1
nsslapd-directory: /var/lib/dirsrv/slapd-master1/db/empty
nsslapd-dncachememsize: 16777216
nsslapd-readonly: off
nsslapd-require-index: off
nsslapd-suffix: o=empty
objectClass: top
objectClass: extensibleObject
objectClass: nsBackendInstance


INFO:dirsrvtests.tests.tickets.ticket47462_test:The DES credentials have been converted to AES
CRITICAL:dirsrvtests.tests.tickets.ticket47462_test:Failed to find AES plugin: No such object
----------------------------------------------------------------------------- Captured log call -----------------------------------------------------------------------------
ticket47462_test.py        110 INFO     Replication test passed
backend.py                  76 INFO     List backend with suffix=o=empty
backend.py                 286 INFO     Creating a local backend
backend.py                  72 INFO     List backend cn=empty,cn=ldbm database,cn=plugins,cn=config
__init__.py               1833 INFO     Found entry dn: cn=empty,cn=ldbm database,cn=plugins,cn=config
cn: empty
nsslapd-cachememsize: 512000
nsslapd-cachesize: -1
nsslapd-directory: /var/lib/dirsrv/slapd-master1/db/empty
nsslapd-dncachememsize: 16777216
nsslapd-readonly: off
nsslapd-require-index: off
nsslapd-suffix: o=empty
objectClass: top
objectClass: extensibleObject
objectClass: nsBackendInstance


ticket47462_test.py        143 INFO     The DES credentials have been converted to AES
ticket47462_test.py        172 CRITICAL Failed to find AES plugin: No such object
------------------------------------------------------------------------- Captured stdout teardown --------------------------------------------------------------------------
Instance slapd-master1 removed.
Instance slapd-master2 removed.
========================================================================= 1 failed in 38.89 seconds =========================================================================

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-06-24 14:22:55

rebased onto 1afde987e7aa931140f47ceb7e8c4e063d70299e

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-07-09 09:11:02

rebased onto 4dbdbfac1ddb5e2db96d0b7024e2190dd41ef4e2

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-07-09 09:21:30

A better reason message can be suggested.

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-07-09 09:22:50

2 new commits added

  • Description: Explicitly changed strings to bytes in upgrade-script(tools.py)
  • Description: Fixed the failure by adding server version check,

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-08-13 12:32:00

rebased onto 55112be2da7eda254f080d5657d440c87f22f573

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-08-13 15:09:21

rebased onto ca5f54bf78bd6c5c89e73f44ece460d50835042c

@389-ds-bot
Copy link
Author

Comment from aadhikari at 2019-08-13 15:22:18

rebased onto 7a24286

@389-ds-bot
Copy link
Author

Comment from vashirov (@vashirov) at 2019-08-13 15:28:47

Pull-Request has been merged by vashirov

@389-ds-bot
Copy link
Author

Patch
50287.patch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged Migration flag - PR pr Migration flag - PR
Projects
None yet
Development

No branches or pull requests

1 participant