diff --git a/docs/my-website/docs/proxy/caching.md b/docs/my-website/docs/proxy/caching.md index 617609cf08..9cfd796d90 100644 --- a/docs/my-website/docs/proxy/caching.md +++ b/docs/my-website/docs/proxy/caching.md @@ -278,6 +278,8 @@ Set either `REDIS_URL` or the `REDIS_HOST` in your os environment, to enable cac REDIS_HOST = "" # REDIS_HOST='redis-18841.c274.us-east-1-3.ec2.cloud.redislabs.com' REDIS_PORT = "" # REDIS_PORT='18841' REDIS_PASSWORD = "" # REDIS_PASSWORD='liteLlmIsAmazing' + REDIS_USERNAME = "" # REDIS_USERNAME='my-redis-username' [OPTIONAL] if your redis server requires a username + REDIS_SSL = "True" # REDIS_SSL='True' to enable SSL by default is False ``` **Additional kwargs** diff --git a/litellm/_redis.py b/litellm/_redis.py index bcb305985f..e6ac323ff5 100644 --- a/litellm/_redis.py +++ b/litellm/_redis.py @@ -177,14 +177,21 @@ def get_redis_url_from_environment(): raise ValueError( "Either 'REDIS_URL' or both 'REDIS_HOST' and 'REDIS_PORT' must be specified for Redis." ) - - if "REDIS_PASSWORD" in os.environ: - redis_password = f":{os.environ['REDIS_PASSWORD']}@" + + if "REDIS_SSL" in os.environ and os.environ["REDIS_SSL"].lower() == "true": + redis_protocol = "rediss" else: - redis_password = "" - + redis_protocol = "redis" + + # Build authentication part of URL + auth_part = "" + if "REDIS_USERNAME" in os.environ and "REDIS_PASSWORD" in os.environ: + auth_part = f"{os.environ['REDIS_USERNAME']}:{os.environ['REDIS_PASSWORD']}@" + elif "REDIS_PASSWORD" in os.environ: + auth_part = f"{os.environ['REDIS_PASSWORD']}@" + return ( - f"redis://{redis_password}{os.environ['REDIS_HOST']}:{os.environ['REDIS_PORT']}" + f"{redis_protocol}://{auth_part}{os.environ['REDIS_HOST']}:{os.environ['REDIS_PORT']}" ) diff --git a/tests/test_litellm/test_redis.py b/tests/test_litellm/test_redis.py new file mode 100644 index 0000000000..991126c2fe --- /dev/null +++ b/tests/test_litellm/test_redis.py @@ -0,0 +1,109 @@ +from litellm._redis import get_redis_url_from_environment +import os +import pytest + +def test_get_redis_url_from_environment_single_url(monkeypatch): + """Test when REDIS_URL is directly provided""" + # Set the environment variable + monkeypatch.setenv("REDIS_URL", "redis://redis-server:6379/0") + + # Call the function to get the Redis URL + redis_url = get_redis_url_from_environment() + + # Assert that the returned URL matches the expected value + assert redis_url == "redis://redis-server:6379/0" + +def test_get_redis_url_from_environment_host_port(monkeypatch): + """Test when REDIS_HOST and REDIS_PORT are provided""" + # Set the environment variables + monkeypatch.setenv("REDIS_HOST", "redis-server") + monkeypatch.setenv("REDIS_PORT", "6379") + + # Call the function to get the Redis URL + redis_url = get_redis_url_from_environment() + + # Assert that the returned URL matches the expected value + assert redis_url == "redis://redis-server:6379" + +def test_get_redis_url_from_environment_with_ssl(monkeypatch): + """Test when SSL is enabled""" + # Set the environment variables + monkeypatch.setenv("REDIS_HOST", "redis-server") + monkeypatch.setenv("REDIS_PORT", "6379") + monkeypatch.setenv("REDIS_SSL", "true") + + # Call the function to get the Redis URL + redis_url = get_redis_url_from_environment() + + # Assert that the returned URL uses rediss:// protocol + assert redis_url == "rediss://redis-server:6379" + +def test_get_redis_url_from_environment_with_username_password(monkeypatch): + """Test when username and password are provided""" + # Set the environment variables + monkeypatch.setenv("REDIS_HOST", "redis-server") + monkeypatch.setenv("REDIS_PORT", "6379") + monkeypatch.setenv("REDIS_USERNAME", "user") + monkeypatch.setenv("REDIS_PASSWORD", "password") + + # Call the function to get the Redis URL + redis_url = get_redis_url_from_environment() + + # Assert that the returned URL includes username:password@ + assert redis_url == "redis://user:password@redis-server:6379" + +def test_get_redis_url_from_environment_with_password_only(monkeypatch): + """Test when only password is provided""" + # Set the environment variables + monkeypatch.setenv("REDIS_HOST", "redis-server") + monkeypatch.setenv("REDIS_PORT", "6379") + monkeypatch.setenv("REDIS_PASSWORD", "password") + + # Call the function to get the Redis URL + redis_url = get_redis_url_from_environment() + + # Assert that the returned URL includes :password@ + assert redis_url == "redis://password@redis-server:6379" + +def test_get_redis_url_from_environment_with_all_options(monkeypatch): + """Test when all options are provided""" + # Set the environment variables + monkeypatch.setenv("REDIS_HOST", "redis-server") + monkeypatch.setenv("REDIS_PORT", "6379") + monkeypatch.setenv("REDIS_USERNAME", "user") + monkeypatch.setenv("REDIS_PASSWORD", "password") + monkeypatch.setenv("REDIS_SSL", "true") + + # Call the function to get the Redis URL + redis_url = get_redis_url_from_environment() + + # Assert that the returned URL includes all components + assert redis_url == "rediss://user:password@redis-server:6379" + +def test_get_redis_url_from_environment_missing_host_port(monkeypatch): + """Test error when required variables are missing""" + # Make sure these environment variables don't exist + monkeypatch.delenv("REDIS_URL", raising=False) + monkeypatch.delenv("REDIS_HOST", raising=False) + monkeypatch.delenv("REDIS_PORT", raising=False) + + # Call the function and expect a ValueError + with pytest.raises(ValueError) as excinfo: + get_redis_url_from_environment() + + # Check the error message + assert "Either 'REDIS_URL' or both 'REDIS_HOST' and 'REDIS_PORT' must be specified" in str(excinfo.value) + +def test_get_redis_url_from_environment_missing_port(monkeypatch): + """Test error when only REDIS_HOST is provided but REDIS_PORT is missing""" + # Make sure REDIS_URL doesn't exist and set only REDIS_HOST + monkeypatch.delenv("REDIS_URL", raising=False) + monkeypatch.delenv("REDIS_PORT", raising=False) + monkeypatch.setenv("REDIS_HOST", "redis-server") + + # Call the function and expect a ValueError + with pytest.raises(ValueError) as excinfo: + get_redis_url_from_environment() + + # Check the error message + assert "Either 'REDIS_URL' or both 'REDIS_HOST' and 'REDIS_PORT' must be specified" in str(excinfo.value)