Skip to content

Commit e4f1fe7

Browse files
committed
# refactored the way to obtain the redis host to only use upstream {...} configs by leveraging lua-upstream-nginx-module module
1 parent e32f844 commit e4f1fe7

File tree

13 files changed

+75
-97
lines changed

13 files changed

+75
-97
lines changed

src/lua/api-gateway/redis/redisHealthCheck.lua

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -101,20 +101,25 @@ local function getHealthCheckForUpstream(upstreamName)
101101
return bits
102102
end
103103

104-
local function getHealthyRedisNodeFromCache(dict_name)
104+
local function getHealthyRedisNodeFromCache(dict_name, upstream_name)
105105
local dict = ngx.shared[dict_name];
106106
local upstreamRedis
107107
if ( nil ~= dict ) then
108-
upstreamRedis = dict:get("healthy_redis_upstream")
108+
upstreamRedis = dict:get("healthy_redis_upstream:" .. tostring(upstream_name) )
109109
end
110110
return upstreamRedis
111111
end
112112

113-
local function updateHealthyRedisNodeInCache(dict_name, upstreamRedis)
113+
local function updateHealthyRedisNodeInCache(dict_name, upstream_name, healthy_redis_host)
114114
local dict = ngx.shared[dict_name];
115115
if ( nil ~= dict ) then
116-
dict:set("healthy_redis_upstream", upstreamRedis, 5)
116+
ngx.log(ngx.DEBUG, "Saving a healthy redis host:", healthy_redis_host, " in cache:", dict_name, " for upstream:", upstream_name)
117+
local exp_time_in_seconds = 5
118+
dict:set("healthy_redis_upstream:" .. tostring(upstream_name), healthy_redis_host, exp_time_in_seconds)
119+
return
117120
end
121+
122+
ngx.log(ngx.WARN, "Dictionary ", dict_name, " doesn't seem to be set. Did you define one ? ")
118123
end
119124

120125
local function getHostAndPortInUpstream(upstreamRedis)
@@ -132,29 +137,32 @@ end
132137
-- Get the redis node to use for read.
133138
-- Returns 3 values: <upstreamName , host, port >
134139
-- The difference between upstream and <host,port> is that the upstream may be just a string containing host:port
135-
function HealthCheck:getHealthyRedisNodeForRead()
140+
function HealthCheck:getHealthyRedisNode(upstream_name)
136141

137142
-- get the Redis host and port from the local cache first
138-
local redisToUse = getHealthyRedisNodeFromCache(self.shared_dict)
139-
if ( nil ~= redisToUse) then
140-
local host, port = getHostAndPortInUpstream(redisToUse)
141-
return redisToUse, host, port
143+
local healthy_redis_host = getHealthyRedisNodeFromCache(self.shared_dict, upstream_name)
144+
if ( nil ~= healthy_redis_host) then
145+
local host, port = getHostAndPortInUpstream(healthy_redis_host)
146+
return healthy_redis_host, host, port
142147
end
143148

149+
ngx.log(ngx.DEBUG, "Looking up for a healthy redis node in upstream:", upstream_name)
144150
-- if the Redis host is not in the local cache get it from the upstream configuration
145-
local redisUpstreamHealthResult = self:getRedisUpstreamHealthStatus()
151+
local redisUpstreamHealthResult = getHealthCheckForUpstream(upstream_name)
146152

147153
if(redisUpstreamHealthResult == nil) then
148154
ngx.log(ngx.ERR, "\n No upstream results found for redis!!! ")
149155
return nil
150156
end
151157

152158
for key,value in ipairs(redisUpstreamHealthResult) do
159+
-- return the first node found to be up.
160+
-- TODO: save all the nodes that are up and return them using round-robin alg
153161
if(value == " up\n") then
154-
redisToUse = redisUpstreamHealthResult[key-1]
155-
updateHealthyRedisNodeInCache(self.shared_dict, redisToUse)
156-
local host, port = getHostAndPortInUpstream(redisToUse)
157-
return redisToUse, host, port
162+
healthy_redis_host = redisUpstreamHealthResult[key-1]
163+
updateHealthyRedisNodeInCache(self.shared_dict, upstream_name, healthy_redis_host)
164+
local host, port = getHostAndPortInUpstream(healthy_redis_host)
165+
return healthy_redis_host, host, port
158166
end
159167
if(value == " DOWN\n" and redisUpstreamHealthResult[key-1] ~= nil ) then
160168
ngx.log(ngx.WARN, "\n Redis node " .. tostring(redisUpstreamHealthResult[key-1]) .. " is down! Checking for backup nodes. ")
@@ -165,15 +173,4 @@ function HealthCheck:getHealthyRedisNodeForRead()
165173
return nil -- No redis nodes are up
166174
end
167175

168-
-- To get the health check results on all the nodes defined in the redis upstream.
169-
-- The health check is performed by a worker using "resty.upstream.healthcheck" module.
170-
-- The name of the redis read only upstream is used here.
171-
function HealthCheck:getRedisUpstreamHealthStatus()
172-
-- TODO: make the name of the upstream configurable for reuse
173-
local redisUpstreamStatus = getHealthCheckForUpstream("cache_read_only_backend")
174-
return redisUpstreamStatus;
175-
end
176-
177-
178-
179176
return HealthCheck

src/lua/api-gateway/validation/key/redisApiKeyValidator.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
-- Dependencies:
2727
-- 1. ngx.var.key needs to be set
2828
-- 2. ngx.var.service_id needs to be set
29-
-- 3. ngx.var.redis_backend needs to be set
3029
--
3130
-- User: ddascal
3231
-- Date: 11/22/13

src/lua/api-gateway/validation/oauth2/oauthTokenValidator.lua

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@
2929
-- Dependencies:
3030
-- 1. ngx.var.oauth_host needs to be set
3131
-- 2. ngx.var.authtoken needs to be set
32-
-- 3. ngx.var.redis_backend needs to be set
33-
-- 4. location /validate-token defined
34-
-- 5. lua_shared_dict cachedOauthTokens 50m;
32+
-- 3. location /validate-token defined
33+
-- 4. lua_shared_dict cachedOauthTokens 50m;
3534
--
3635
-- Properties that can be set:
3736
-- 1. oauth_token_scope
@@ -41,7 +40,6 @@
4140

4241
local BaseValidator = require "api-gateway.validation.validator"
4342
local cjson = require "cjson"
44-
local redis = require "resty.redis"
4543

4644
local _M = BaseValidator:new()
4745

src/lua/api-gateway/validation/oauth2/userProfileValidator.lua

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
-- Dependencies:
2727
-- 1. ngx.var.oauth_host - optional var
2828
-- 2. ngx.var.authtoken - required to be set
29-
-- 3. ngx.var.redis_backend - required
30-
-- 4. lua_shared_dict cachedOauthTokens 50m; - required. The local shared dict to cache user profiles
31-
-- 5. ngx.ctx.oauth_token_expires_at - optional. This is usually set by the oauthTokenValidator
29+
-- 3. lua_shared_dict cachedOauthTokens 50m; - required. The local shared dict to cache user profiles
30+
-- 4. ngx.ctx.oauth_token_expires_at - optional. This is usually set by the oauthTokenValidator
3231
--
3332
-- Properties that can be set by this validator:
3433
-- 1. user_email

src/lua/api-gateway/validation/validator.lua

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
-- Time: 18:01
2828
--
2929
-- Dependencies:
30-
-- 1. ngx.var.redis_backend needs to be set
31-
-- 2. ngx.var.redis_backend_rw needs to be set
32-
-- 2. ngx.var.disable_redis_replica_healthchecks OPTIONAL - it disables redis healthchecks
30+
-- 1. api-gateway-redis upstream needs to be set
31+
-- 2. api-gateway-redis-replica needs to be set
3332
--
3433
local base = require "api-gateway.validation.base"
3534
local redis = require "resty.redis"
@@ -38,39 +37,15 @@ local cjson = require "cjson"
3837
local debug_mode = ngx.config.debug
3938

4039
-- redis endpoints are assumed to be global per GW node and therefore are read here
41-
local redis_RO_backend = "none"
42-
local redis_RW_backend = "none"
43-
local disable_redis_replica_healthchecks = "none"
40+
local redis_RO_upstream = "api-gateway-redis-replica"
41+
local redis_RW_upstream = "api-gateway-redis"
4442

4543
-- class to be used as a base class for all api-gateway validators --
4644
local BaseValidator = {}
4745
local redisHealthCheck = RedisHealthCheck:new({
4846
shared_dict = "cachedkeys"
4947
})
5048

51-
local function get_redis_RO_backend()
52-
if ( redis_RO_backend == "none" ) then
53-
redis_RO_backend = ngx.var.redis_backend
54-
55-
end
56-
return redis_RO_backend
57-
end
58-
59-
local function get_redis_RW_backend()
60-
if ( redis_RW_backend == "none" ) then
61-
redis_RW_backend = ngx.var.redis_backend_rw
62-
end
63-
return redis_RW_backend
64-
end
65-
66-
local function get_disable_redis_replica_healthchecks()
67-
if ( disable_redis_replica_healthchecks == "none" ) then
68-
disable_redis_replica_healthchecks = ngx.var.disable_redis_replica_healthchecks
69-
end
70-
return disable_redis_replica_healthchecks
71-
end
72-
73-
7449
function BaseValidator:new(o)
7550
local o = o or {}
7651
setmetatable(o, self)
@@ -103,26 +78,24 @@ function BaseValidator:setKeyInLocalCache(key, string_value, exptime, dict_name)
10378
end
10479
end
10580

106-
function BaseValidator:getRedisUpstream()
107-
if (get_disable_redis_replica_healthchecks() == "on") then
108-
return get_redis_RO_backend(), 6379
109-
end
110-
local upstream, host, port = redisHealthCheck:getHealthyRedisNodeForRead()
111-
ngx.log(ngx.DEBUG, "REDIS HOST:" .. tostring(host) .. ":" .. tostring(port))
81+
function BaseValidator:getRedisUpstream(upstream_name)
82+
local n = upstream_name or redis_RO_upstream
83+
local upstream, host, port = redisHealthCheck:getHealthyRedisNode(n)
84+
ngx.log(ngx.DEBUG, "Obtained Redis Host:" .. tostring(host) .. ":" .. tostring(port), " from upstream:", n)
11285
if (nil ~= host and nil ~= port) then
11386
return host, port
11487
end
11588

116-
ngx.log(ngx.ERR, "Could not find a Redis upstream. Using default upstream: [" .. get_redis_RO_backend() .. ":6379]")
117-
return get_redis_RO_backend(), 6379
89+
ngx.log(ngx.ERR, "Could not find a Redis upstream.")
90+
return nil,nil
11891
end
11992

12093
-- retrieves a saved information from the Redis cache --
12194
-- the method uses HGET redis command --
12295
-- it returns the value of the key, when found in the cache, nil otherwise --
12396
function BaseValidator:getKeyFromRedis(key, hash_name)
12497
local redisread = redis:new()
125-
local redis_host, redis_port = self:getRedisUpstream()
98+
local redis_host, redis_port = self:getRedisUpstream(redis_RO_upstream)
12699
local ok, err = redisread:connect(redis_host, redis_port)
127100
if ok then
128101
local redis_key, selecterror = redisread:hget(key, hash_name)
@@ -132,7 +105,7 @@ function BaseValidator:getKeyFromRedis(key, hash_name)
132105
return redis_key
133106
end
134107
else
135-
ngx.log(ngx.WARN, "Failed to read key " .. key .. " from Redis cache:", redis_host, ":", redis_port, ".Error:", err)
108+
ngx.log(ngx.WARN, "Failed to read key " .. tostring(key) .. " from Redis cache:[", redis_host, ":", redis_port, "]. Error:", err)
136109
end
137110
return nil;
138111
end
@@ -142,7 +115,8 @@ end
142115
-- it retuns true if the information is saved in the cache, false otherwise --
143116
function BaseValidator:setKeyInRedis(key, hash_name, keyexpires, value)
144117
local rediss = redis:new()
145-
local ok, err = rediss:connect(get_redis_RW_backend(), 6379)
118+
local redis_host, redis_port = self:getRedisUpstream(redis_RW_upstream)
119+
local ok, err = rediss:connect(redis_host, redis_port)
146120
if ok then
147121
--ngx.log(ngx.DEBUG, "WRITING IN REDIS JSON OBJ key=" .. key .. "=" .. value .. ",expiring in:" .. (keyexpires - (os.time() * 1000)) )
148122
rediss:init_pipeline()
@@ -157,7 +131,7 @@ function BaseValidator:setKeyInRedis(key, hash_name, keyexpires, value)
157131
ngx.log(ngx.WARN, "Failed to write the key [", key, "] in Redis. Error:", commit_err)
158132
end
159133
else
160-
ngx.log(ngx.WARN, "Failed to save key:" .. key .. " into cache: ", get_redis_RW_backend(), ".Error:", err)
134+
ngx.log(ngx.WARN, "Failed to save key:" .. tostring(key) .. " into cache: [", tostring(redis_host) .. ":" .. tostring(redis_port), "]. Error:", err)
161135
end
162136
return false;
163137
end

test/perl/api-gateway/validation/key/api_key.t

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use Cwd qw(cwd);
3131

3232
repeat_each(2);
3333

34-
plan tests => repeat_each() * (blocks() * 4) + 10;
34+
plan tests => repeat_each() * (blocks() * 4) + 14;
3535

3636
my $pwd = cwd();
3737

@@ -47,11 +47,11 @@ our $HttpConfig = <<_EOC_;
4747
ngx.apiGateway = ngx.apiGateway or {}
4848
ngx.apiGateway.validation = require "api-gateway.validation.factory"
4949
';
50-
include "$pwd/conf.d/http.d/*.conf";
51-
upstream cache_rw_backend {
50+
lua_shared_dict cachedkeys 50m; # caches api-keys
51+
upstream api-gateway-redis {
5252
server 127.0.0.1:6379;
5353
}
54-
upstream cache_read_only_backend { # Default config for redis health check test
54+
upstream api-gateway-redis-replica { # Default config for redis health check test
5555
server 127.0.0.1:6379;
5656
}
5757
_EOC_
@@ -66,6 +66,8 @@ __DATA__
6666
--- http_config eval: $::HttpConfig
6767
--- config
6868
include ../../api-gateway/api_key_service.conf;
69+
error_log ../test-logs/api_key_test1_error.log debug;
70+
6971
--- more_headers
7072
X-Test: test
7173
--- request
@@ -81,6 +83,7 @@ POST /cache/api_key?key=k-123&service_id=s-123
8183
--- config
8284
include ../../api-gateway/api_key_service.conf;
8385
include ../../api-gateway/default_validators.conf;
86+
error_log ../test-logs/api_key_test2_error.log debug;
8487
8588
location /test-api-key {
8689
set $service_id s-123;
@@ -105,6 +108,8 @@ GET /test-api-key
105108
--- config
106109
include ../../api-gateway/api_key_service.conf;
107110
include ../../api-gateway/default_validators.conf;
111+
error_log ../test-logs/api_key_test3_error.log debug;
112+
108113
location /test-api-key {
109114
set $service_id s-123;
110115
@@ -128,6 +133,7 @@ GET /test-api-key?api_key=ab123
128133
--- config
129134
include ../../api-gateway/api_key_service.conf;
130135
include ../../api-gateway/default_validators.conf;
136+
error_log ../test-logs/api_key_test4_error.log debug;
131137
132138
location /test-api-key {
133139
set $service_id s-123;
@@ -142,10 +148,13 @@ GET /test-api-key?api_key=ab123
142148
}
143149
--- pipelined_requests eval
144150
["POST /cache/api_key?key=test-key-1234&service_id=s-123",
151+
"GET /test-api-key?api_key=test-key-1234",
145152
"GET /test-api-key?api_key=test-key-1234"]
146153
--- response_body eval
147154
["+OK\r\n",
148-
"api-key is valid.\n"]
155+
"api-key is valid.\n",
156+
"api-key is valid.\n"
157+
]
149158
--- no_error_log
150159
151160
@@ -155,6 +164,7 @@ GET /test-api-key?api_key=ab123
155164
include ../../api-gateway/api_key_service.conf;
156165
include ../../api-gateway/default_validators.conf;
157166
error_log ../test-logs/api_key_test5_error.log debug;
167+
158168
location /test-api-key-5 {
159169
set $service_id s-123;
160170
@@ -184,6 +194,8 @@ GET /test-api-key?api_key=ab123
184194
--- config
185195
include ../../api-gateway/api_key_service.conf;
186196
include ../../api-gateway/default_validators.conf;
197+
error_log ../test-logs/api_key_test6_error.log debug;
198+
187199
location /test-api-key {
188200
set $service_id s-123;
189201
@@ -210,11 +222,13 @@ GET /test-api-key?api_key=ab123
210222
[error]
211223
212224
213-
=== TEST 6: test api-key related field starting with capital H
225+
=== TEST 7: test api-key related field starting with capital H
214226
--- http_config eval: $::HttpConfig
215227
--- config
216228
include ../../api-gateway/api_key_service.conf;
217229
include ../../api-gateway/default_validators.conf;
230+
error_log ../test-logs/api_key_test7_error.log debug;
231+
218232
location /test-api-key {
219233
set $service_id hH-123;
220234

test/perl/api-gateway/validation/oauth2/oauthTokenValidator.t

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ our $HttpConfig = <<_EOC_;
4848
ngx.apiGateway = ngx.apiGateway or {}
4949
ngx.apiGateway.validation = require "api-gateway.validation.factory"
5050
';
51-
51+
lua_shared_dict cachedkeys 50m; # caches api-keys
5252
# dict used by OAuth validator to cache valid tokens
5353
lua_shared_dict cachedOauthTokens 50m;
5454
55-
upstream cache_rw_backend {
55+
upstream api-gateway-redis {
5656
server 127.0.0.1:6379;
5757
}
58-
upstream cache_read_only_backend { # Default config for redis health check test
58+
upstream api-gateway-redis-replica { # Default config for redis health check test
5959
server 127.0.0.1:6379;
6060
}
6161
_EOC_

test/perl/api-gateway/validation/oauth2/userProfileValidator.t

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ our $HttpConfig = <<_EOC_;
4848
ngx.apiGateway = ngx.apiGateway or {}
4949
ngx.apiGateway.validation = require "api-gateway.validation.factory"
5050
';
51-
51+
lua_shared_dict cachedkeys 50m; # caches api-keys
5252
# dict used by OAuth validator to cache valid tokens
5353
lua_shared_dict cachedOauthTokens 50m;
5454
# dict used by User Profile validator to cache valid profiles
5555
lua_shared_dict cachedUserProfiles 50m;
5656
57-
upstream cache_rw_backend {
58-
server 127.0.0.1:6379;
57+
upstream api-gateway-redis {
58+
server 127.0.0.1:6379;
5959
}
60-
upstream cache_read_only_backend { # Default config for redis health check test
60+
upstream api-gateway-redis-replica { # Default config for redis health check test
6161
server 127.0.0.1:6379;
6262
}
6363
_EOC_

0 commit comments

Comments
 (0)