Repository: ansible/ansible-modules-extras

Issue:
mongodb_user works incorrectly with old pymongo
##### Issue Type: Bug report
##### Ansible Version: 1.7.1
##### Environment:

OSX 10.7 -> Ubuntu precise
##### Summary:

mongodb_user works incorrectly with old pymongo (~2.1). 
Tested with 2.7.2, work correctly.
##### Steps To Reproduce:
- Fresh mongo instance with auth enabled, no users
- ansible host  -m mongodb_user -a "database=admin user=test roles=root password=test state=present"
##### Expected Results:

Creates new user
##### Actual Results:

Changed = false

This code block supposed to fail on non-existant user:

```
        try:
           client[db_name].authenticate(user, password)
           if state == 'present':
              module.exit_json(changed=False, user=user)
        except OperationFailure:
           if state == 'absent':
              module.exit_json(changed=False, user=user)
```

But it is exiting correctly and continue. 
### Old issue

https://github.com/ansible/ansible/issues/8899



Discussion:
I am experiencing the same behavior on Debian 7.5 using python-pymongo install from apt. 

Ansible reports no change and no error and the user is not created. 

I was able to work around the issue by upgrading pymongo with pip. 

```
sudo apt-get install python-pip
sudo pip install --upgrade pymongo
```

we probably just need to add lib version detection and an alternate method

@senz @dopry Thanks for submitting this bug report. Apologies for taking so long to triage it. Since this bug has been open for a while, we would appreciate if you can verify if you are still seeing the reported behavior in the latest version.

If you are seeing the reported behavior, just let us know and we will leave the bug open and notify the module maintainer.

If you are no longer seeing the reported behavior, please let us know and we will close the bug report.

[module: database/misc/mongodb_user.py]


Resolving patch:
diff --git a/database/misc/mongodb_user.py b/database/misc/mongodb_user.py
--- a/database/misc/mongodb_user.py
+++ b/database/misc/mongodb_user.py
@@ -165,6 +165,17 @@
 # MongoDB module specific support methods.
 #
 
+def check_compatibility(module, client):
+    srv_info = client.server_info()
+    if LooseVersion(srv_info['version']) >= LooseVersion('3.2') and LooseVersion(PyMongoVersion) <= LooseVersion('3.2'):
+        module.fail_json(msg=' (Note: you must use pymongo 3.2+ with MongoDB >= 3.2)')
+    elif LooseVersion(srv_info['version']) >= LooseVersion('3.0') and LooseVersion(PyMongoVersion) <= LooseVersion('2.8'):
+        module.fail_json(msg=' (Note: you must use pymongo 2.8+ with MongoDB 3.0)')
+    elif LooseVersion(srv_info['version']) >= LooseVersion('2.6') and LooseVersion(PyMongoVersion) <= LooseVersion('2.7'):
+        module.fail_json(msg=' (Note: you must use pymongo 2.7+ with MongoDB 2.6)')
+    elif LooseVersion(PyMongoVersion) <= LooseVersion('2.5'):
+        module.fail_json(msg=' (Note: you must be on mongodb 2.4+ and pymongo 2.5+ to use the roles param)')
+
 def user_find(client, user, db_name):
     for mongo_user in client["admin"].system.users.find():
         if mongo_user['user'] == user and mongo_user['db'] == db_name:
@@ -183,8 +194,6 @@ def user_add(module, client, db_name, user, password, roles):
             db.add_user(user, password, None, roles=roles)
         except OperationFailure, e:
             err_msg = str(e)
-            if LooseVersion(PyMongoVersion) <= LooseVersion('2.5'):
-                err_msg = err_msg + ' (Note: you must be on mongodb 2.4+ and pymongo 2.5+ to use the roles param)'
             module.fail_json(msg=err_msg)
 
 def user_remove(module, client, db_name, user):
@@ -316,6 +325,8 @@ def main():
     except ConnectionFailure, e:
         module.fail_json(msg='unable to connect to database: %s' % str(e))
 
+    check_compatibility(module, client)
+
     if state == 'present':
         if password is None and update_password == 'always':
             module.fail_json(msg='password parameter required when adding a user unless update_password is set to on_create')


Test patch: