diff --git a/changelogs/fragments/2579-redis-cache-ipv6.yml b/changelogs/fragments/2579-redis-cache-ipv6.yml new file mode 100644 index 0000000000..aaa5e78b34 --- /dev/null +++ b/changelogs/fragments/2579-redis-cache-ipv6.yml @@ -0,0 +1,2 @@ +bugfixes: + - redis cache - improved connection string parsing (https://github.com/ansible-collections/community.general/issues/497). diff --git a/plugins/cache/redis.py b/plugins/cache/redis.py index 7a376d6d7c..6af7c731e4 100644 --- a/plugins/cache/redis.py +++ b/plugins/cache/redis.py @@ -61,6 +61,7 @@ DOCUMENTATION = ''' type: integer ''' +import re import time import json @@ -91,6 +92,8 @@ class CacheModule(BaseCacheModule): performance. """ _sentinel_service_name = None + re_url_conn = re.compile(r'^([^:]+|\[[^]]+\]):(\d+):(\d+)(?::(.*))?$') + re_sent_conn = re.compile(r'^(.*):(\d+)$') def __init__(self, *args, **kwargs): uri = '' @@ -130,11 +133,18 @@ class CacheModule(BaseCacheModule): self._db = self._get_sentinel_connection(uri, kw) # normal connection else: - connection = uri.split(':') + connection = self._parse_connection(self.re_url_conn, uri) self._db = StrictRedis(*connection, **kw) display.vv('Redis connection: %s' % self._db) + @staticmethod + def _parse_connection(re_patt, uri): + match = re_patt.match(uri) + if not match: + raise AnsibleError("Unable to parse connection string") + return match.groups() + def _get_sentinel_connection(self, uri, kw): """ get sentinel connection details from _uri @@ -158,7 +168,7 @@ class CacheModule(BaseCacheModule): except IndexError: pass # password is optional - sentinels = [tuple(shost.split(':')) for shost in connections] + sentinels = [self._parse_connection(self.re_sent_conn, shost) for shost in connections] display.vv('\nUsing redis sentinels: %s' % sentinels) scon = Sentinel(sentinels, **kw) try: diff --git a/tests/unit/plugins/cache/test_redis.py b/tests/unit/plugins/cache/test_redis.py index e665826769..ee7e1f7913 100644 --- a/tests/unit/plugins/cache/test_redis.py +++ b/tests/unit/plugins/cache/test_redis.py @@ -23,10 +23,23 @@ import pytest pytest.importorskip('redis') +from ansible import constants as C from ansible.plugins.loader import cache_loader +from ansible.release import __version__ as ansible_version from ansible_collections.community.general.plugins.cache.redis import CacheModule as RedisCache def test_redis_cachemodule(): # The _uri option is required for the redis plugin - assert isinstance(cache_loader.get('community.general.redis', **{'_uri': '127.0.0.1:6379:1'}), RedisCache) + connection = '127.0.0.1:6379:1' + if ansible_version.startswith('2.9.'): + C.CACHE_PLUGIN_CONNECTION = connection + assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache) + + +def test_redis_cachemodule(): + # The _uri option is required for the redis plugin + connection = '[::1]:6379:1' + if ansible_version.startswith('2.9.'): + C.CACHE_PLUGIN_CONNECTION = connection + assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache)