Repository: ansible/ansible

Issue:
Redis facts cache not compatible with Python 3
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
plugins/cache/redis.py

##### ANSIBLE VERSION
ansible 2.3.1.0
  config file = /home/petr/.config/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 3.6.1 (default, Mar 27 2017, 00:27:06) [GCC 6.3.1 20170306]

##### CONFIGURATION
[defaults]
gathering = smart
fact_caching = redis
fact_caching_timeout = 3600

##### OS / ENVIRONMENT
python 3.6

##### SUMMARY
It is not possible to run ansible with Python 3 and Redis facts cache.

There is comparision in CacheModule.contains (file ansible/plugins/cache/redis.py, line 87) which can be between None and 0 (if value is not in cache). The comparision works in python2 but not in python3:

```
petr@tabor ~> python2 -c 'value = None; print(value > 0)'
False
petr@tabor ~> python3 -c 'value = None; print(value > 0)'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: '>' not supported between instances of 'NoneType' and 'int'
petr@tabor ~> python3 -c 'value = None; print(value is not None and value > 0)'
False
```

##### STEPS TO REPRODUCE
```
redis-cli flushall
ansible -vvv localhost -a 'echo OK'
```

##### EXPECTED RESULTS

(With simple patch in CacheModule.contains.)

```
petr@tabor ~> redis-cli flushall
OK
petr@tabor ~> ansible -vvv localhost -a 'echo OK'
META: ran handlers
Using module file /home/petr/.local/lib/python3.6/site-packages/ansible/modules/commands/command.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: petr
<localhost> EXEC /bin/sh -c '/usr/bin/python2 && sleep 0'
localhost | SUCCESS | rc=0 >>
OK

META: ran handlers
META: ran handlers
```

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
petr@tabor ~> redis-cli flushall
OK
petr@tabor ~> ansible -vvv localhost -a 'echo OK'
Using /home/petr/.config/ansible/ansible.cfg as config file
ERROR! Unexpected Exception: '>=' not supported between instances of 'NoneType' and 'int'
the full traceback was:

Traceback (most recent call last):
  File "/home/petr/.local/bin/ansible", line 109, in <module>
    exit_code = cli.run()
  File "/home/petr/.local/lib/python3.6/site-packages/ansible/cli/adhoc.py", line 200, in run
    result = self._tqm.run(play)
  File "/home/petr/.local/lib/python3.6/site-packages/ansible/executor/task_queue_manager.py", line 264, in run
    start_at_done = self._start_at_done,
  File "/home/petr/.local/lib/python3.6/site-packages/ansible/executor/play_iterator.py", line 210, in __init__
    if host.name in variable_manager._fact_cache and variable_manager._fact_cache.get(host.name).get('module_setup', False):
  File "/home/petr/.local/lib/python3.6/site-packages/ansible/plugins/cache/__init__.py", line 57, in __contains__
    return self._plugin.contains(key)
  File "/home/petr/.local/lib/python3.6/site-packages/ansible/plugins/cache/redis.py", line 87, in contains
    return (self._cache.zrank(self._keys_set, key) >= 0)
TypeError: '>=' not supported between instances of 'NoneType' and 'int'
```



Discussion:

Resolving patch:
diff --git a/lib/ansible/plugins/cache/redis.py b/lib/ansible/plugins/cache/redis.py
--- a/lib/ansible/plugins/cache/redis.py
+++ b/lib/ansible/plugins/cache/redis.py
@@ -84,7 +84,7 @@ def keys(self):
 
     def contains(self, key):
         self._expire_keys()
-        return (self._cache.zrank(self._keys_set, key) >= 0)
+        return (self._cache.zrank(self._keys_set, key) is not None)
 
     def delete(self, key):
         self._cache.delete(self._make_key(key))


Test patch: