Repository: ansible/ansible

Issue:
Failure while using htpasswd module
_From @apolatynski on December 4, 2016 15:42_

<!--- Verify first that your issue/request is not already reported in GitHub -->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
htpasswd

##### ANSIBLE VERSION
```
ansible 2.2.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
Default

##### OS / ENVIRONMENT
ArchLinux

##### SUMMARY
htpasswd module fails with message: `invalid version number '1.7.0.post20161124160753`
Looks like it's related to `python2-passlib` package (installed from archlinux repository).

##### STEPS TO REPRODUCE
Using a role with a task like below

```
htpasswd:
  path=/etc/app/auth/htpasswd
  name=someuser
  crypt_scheme=bcrypt
  password={{ password }}
  owner=root
  mode=0640
```

##### EXPECTED RESULTS
User entry added to htpasswd file.

##### ACTUAL RESULTS
Task failure.

<!--- Paste verbatim command output between quotes below -->
```
fatal: [host]: FAILED! => {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "backup": null,
            "content": null,
            "create": true,
            "crypt_scheme": "bcrypt",
            "delimiter": null,
            "directory_mode": null,
            "follow": false,
            "force": null,
            "group": null,
            "mode": "0640",
            "name": "someuser",
            "owner": "root",
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "path": "/etc/app/auth/htpasswd",
            "regexp": null,
            "remote_src": null,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": null,
            "state": "present",
            "unsafe_writes": null
        },
        "module_name": "htpasswd"
    },
    "msg": "invalid version number '1.7.0.post20161124160753'"
}
```


_Copied from original issue: ansible/ansible-modules-core#5816_


Discussion:
_From @ansibot on December 4, 2016 16:2_

<!-- @apolatynski: Thanks for filing this bug report! -->
@ansible ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: issue_bug_new --->
_From @ansibot on December 9, 2016 19:46_

This repository has been locked. All new issues and pull requests should be filed in https://github.com/ansible/ansible

Please read through the <a href="http://docs.ansible.com/ansible/dev_guide/repomerge.html#move-issues-and-prs-to-new-repo">repomerge</a> page in the dev guide. The guide contains links to tools which automatically move your issue or pull request to the ansible/ansible repo.

<!-- boilerplate: repomerge -->

Resolving patch:
diff --git a/lib/ansible/modules/web_infrastructure/htpasswd.py b/lib/ansible/modules/web_infrastructure/htpasswd.py
--- a/lib/ansible/modules/web_infrastructure/htpasswd.py
+++ b/lib/ansible/modules/web_infrastructure/htpasswd.py
@@ -104,7 +104,7 @@
 
 import os
 import tempfile
-from distutils.version import StrictVersion
+from distutils.version import LooseVersion
 
 try:
     from passlib.apache import HtpasswdFile, htpasswd_context
@@ -138,7 +138,7 @@ def present(dest, username, password, crypt_scheme, create, check_mode):
         if check_mode:
             return ("Create %s" % dest, True)
         create_missing_directories(dest)
-        if StrictVersion(passlib.__version__) >= StrictVersion('1.6'):
+        if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
             ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme, context=context)
         else:
             ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme, context=context)
@@ -149,7 +149,7 @@ def present(dest, username, password, crypt_scheme, create, check_mode):
         ht.save()
         return ("Created %s and added %s" % (dest, username), True)
     else:
-        if StrictVersion(passlib.__version__) >= StrictVersion('1.6'):
+        if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
             ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme, context=context)
         else:
             ht = HtpasswdFile(dest, default=crypt_scheme, context=context)
@@ -176,7 +176,7 @@ def absent(dest, username, check_mode):
     """ Ensures user is absent
 
     Returns (msg, changed) """
-    if StrictVersion(passlib.__version__) >= StrictVersion('1.6'):
+    if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
         ht = HtpasswdFile(dest, new=False)
     else:
         ht = HtpasswdFile(dest)


Test patch: