Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[redis] allow configuration via REDIS_URL #303

Merged
merged 3 commits into from
Mar 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Backend HTTP client that uses cosockets [PR #295](https://github.com/3scale/apicast/pull/295)
- Ability to customize main section of nginx configuration (and expose more env variables) [PR #292](https://github.com/3scale/apicast/pull/292)
- Ability to lock service to specific configuration version [PR #293](https://github.com/3scale/apicast/pull/292)
- Ability to use Redis DB and password via `REDIS_URL` [PR #303](https://github.com/3scale/apicast/pull/303)

### Removed

Expand Down
1 change: 1 addition & 0 deletions apicast/conf/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
env REDIS_HOST;
env REDIS_PORT;
env REDIS_URL;
env RESOLVER;
env BACKEND_ENDPOINT_OVERRIDE;

Expand Down
8 changes: 6 additions & 2 deletions apicast/src/resty/url.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ function _M.default_port(scheme)
end
end

function _M.split(url)
function _M.split(url, protocol)
if not url then
return nil, 'missing endpoint'
end

local m = re_match(url, "^(https?):\\/\\/(?:(.+)@)?([^\\/\\s]+?)(?::(\\d+))?(\\/.*)?$", 'oj')
if not protocol then
protocol = 'https?'
end

local m = re_match(url, "^(" .. protocol .. "):\\/\\/(?:(.+)@)?([^\\/\\s]+?)(?::(\\d+))?(\\/.*)?$", 'oj')

if not m then
return nil, 'invalid endpoint' -- TODO: maybe improve the error message?
Expand Down
62 changes: 54 additions & 8 deletions apicast/src/threescale_utils.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
local sub = string.sub
local tonumber = tonumber

local redis = require 'resty.redis'
local env = require 'resty.env'

local resty_resolver = require 'resty.resolver'
local resty_balancer = require 'resty.balancer'

local resty_url = require 'resty.url'

local _M = {} -- public interface

-- private
Expand Down Expand Up @@ -110,23 +114,65 @@ function _M.resolve(host, port)
return ip, port
end

function _M.connect_redis(host, port)
local h = host or env.get('REDIS_HOST') or "127.0.0.1"
local p = port or env.get('REDIS_PORT') or 6379
function _M.connect_redis(options)
local opts = {}

local url = options and options.url or env.get('REDIS_URL')


if url then
url = resty_url.split(url, 'redis')
if url then
opts.host = url[4]
opts.port = url[5]
opts.db = url[6] and tonumber(sub(url[6], 2))
opts.password = url[3] or url[2]
end
elseif options then
opts.host = options.host
opts.port = options.port
opts.db = options.db
opts.password = options.password
end

local host = opts.host or env.get('REDIS_HOST') or "127.0.0.1"
local port = opts.prot or env.get('REDIS_PORT') or 6379

local red = redis:new()

local ok, err = red:connect(_M.resolve(h, p))
local ok, err = red:connect(_M.resolve(host, port))
if not ok then
return nil, _M.error("failed to connect to redis on " .. h .. ":" .. p .. ":", err)
return nil, _M.error("failed to connect to redis on " .. host .. ":" .. port .. ":", err)
end

if opts.password then
ok = red:auth(opts.password)

if not ok then
return nil, _M.error("failed to auth on redis " .. host .. ":" .. port)
end
end

if opts.db then
ok = red:select(opts.db)

if not ok then
return nil, _M.error("failed to select db " .. opts.db .. " on redis " .. host .. ":" .. port)
end
end

return red
end

-- error and exist
function _M.error(...)
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(...)
ngx.exit(ngx.status)
if ngx.get_phase() == 'timer' then
return ...
else
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(...)
ngx.exit(ngx.status)
end
end

function _M.missing_args(text)
Expand Down
6 changes: 6 additions & 0 deletions doc/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ APIcast requires a running Redis instance for OAuth 2.0 flow. `REDIS_HOST` param

APIcast requires a running Redis instance for OAuth 2.0 flow. `REDIS_PORT` parameter can be used to set the port of the Redis instance.

### `REDIS_URL`

**Default:** no value

APIcast requires a running Redis instance for OAuth 2.0 flow. `REDIS_URL` parameter can be used to set the full URI as DSN format like: `redis://PASSWORD@HOST:PORT/DB`. Takes precedence over `REDIS_PORT` and `REDIS_URL`.

### `RESOLVER`

Allows to specify a custom DNS resolver that will be used by OpenResty. If the `RESOLVER` parameter is empty, the DNS resolver will be autodiscovered.
Expand Down
3 changes: 3 additions & 0 deletions script/redis
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env sh

exec resty -I apicast/src script/redis.lua "$@"
35 changes: 35 additions & 0 deletions script/redis.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env resty -I apicast/src

local cmd = arg[1]
local args = {}

for i=2, #arg do
table.insert(args, arg[i])
end

if not cmd then
print('missing command')
print('usage: ' .. arg[0] .. ' cmd [arg [arg ...]]')
os.exit(1)
end

local inspect = require 'inspect'
local ts = require 'threescale_utils'

local red, err = ts.connect_redis()

if not red and err then
print('could not connect to redis: ', err)
os.exit(1)
end

local fn = red[cmd]
local res, err = fn(red, unpack(args))

if err then
print('error: ', err)
print(inspect(r))
os.exit(1)
end

print(inspect(res))
4 changes: 4 additions & 0 deletions spec/resty/url_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ describe('resty.url', function()
it('removes the trailing slash', function()
assert.same({'http', false, false, 'api.twitter.com', false }, split('http://api.twitter.com/'))
end)

it('works with redis DSN', function()
assert.same({'redis', 'user', 'pass', 'localhost', '6379', '/42' }, split('redis://user:pass@localhost:6379/42', 'redis'))
end)
end)


Expand Down