Fix rate limit interval
diff --git a/doc/v2/management_interface_v2.md b/doc/v2/management_interface_v2.md
index b72f8f8..eee51ae 100644
--- a/doc/v2/management_interface_v2.md
+++ b/doc/v2/management_interface_v2.md
@@ -89,16 +89,6 @@
"assembly": {
"execute": [
{
- "set-variable": {
- "actions": [
- {
- "set": "message.headers.Authorization",
- "value": "Basic xxx"
- }
- ]
- }
- },
- {
"operation-switch": {
"case": [
{
diff --git a/scripts/lua/management/lib/swagger.lua b/scripts/lua/management/lib/swagger.lua
index 83b9741..7184d42 100644
--- a/scripts/lua/management/lib/swagger.lua
+++ b/scripts/lua/management/lib/swagger.lua
@@ -98,23 +98,24 @@
function parseRateLimit(swagger, policies)
local rlObj = swagger["x-gateway-rate-limit"]
rlObj = (rlObj == nil) and swagger["x-ibm-rate-limit"] or rlObj
+ local unit
if rlObj ~= nil then
rlObj = rlObj[1]
if rlObj.unit == "second" then
- rlObj.unit = 1
+ unit = 1
elseif rlObj.unit == "minute" then
- rlObj.unit = 60
+ unit = 60
elseif rlObj.unit == "hour" then
- rlObj.unit = 3600
+ unit = 3600
elseif rlObj.unit == "day" then
- rlObj.unit = 86400
+ unit = 86400
else
- rlObj.unit = 60 -- default to minute
+ unit = 60 -- default to minute
end
policies[#policies+1] = {
type = "rateLimit",
value = {
- interval = rlObj.unit * rlObj.units,
+ interval = unit * rlObj.units,
rate = rlObj.rate,
scope = "api",
subscription = true
diff --git a/scripts/lua/policies/rateLimit.lua b/scripts/lua/policies/rateLimit.lua
index 207a4fa..22005c5 100644
--- a/scripts/lua/policies/rateLimit.lua
+++ b/scripts/lua/policies/rateLimit.lua
@@ -19,56 +19,38 @@
-- DEALINGS IN THE SOFTWARE.
--- @module rateLimit
--- Process a rateLimit object, setting the rate and interval to the request
--- @author David Green (greend), Alex Song (songs)
-local REDIS_HOST = os.getenv("REDIS_HOST")
-local REDIS_PORT = os.getenv("REDIS_PORT")
-local REDIS_PASS = os.getenv("REDIS_PASS")
-local req = require "lib/resty/limit/req"
local utils = require "lib/utils"
-local logger = require "lib/logger"
local request = require "lib/request"
-local redis = require "lib/redis"
local _M = {}
--- Limit a resource/api/tenant, based on the passed in rateLimit object
+-- @param red redis client instance
-- @param obj rateLimit object containing interval, rate, scope, subscription fields
--- @param apiKey optional api key to use if subscription set to true
-function limit(obj, apiKey)
- local i = 60 / obj.interval
- local r = i * obj.rate
- r = utils.concatStrings({tostring(r), 'r/m'})
+-- @param apiKey optional api key to use if subscription is set to true
+function limit(red, obj, apiKey)
+ local rate = obj.interval / obj.rate
local tenantId = ngx.var.tenant
local gatewayPath = ngx.var.gatewayPath
local k
-- Check scope
- if obj.scope == 'tenant' then
- k = utils.concatStrings({"tenant:", tenantId})
- elseif obj.scope == 'api' then
+ if obj.scope == "tenant" then
+ k = utils.concatStrings({"ratelimit:tenant:", tenantId})
+ elseif obj.scope == "api" then
local apiId = ngx.var.apiId
- k = utils.concatStrings({"tenant:", tenantId, ":api:", apiId})
- elseif obj.scope == 'resource' then
- k = utils.concatStrings({"tenant:", tenantId, ":resource:", gatewayPath})
+ k = utils.concatStrings({"ratelimit:tenant:", tenantId, ":api:", apiId})
+ elseif obj.scope == "resource" then
+ k = utils.concatStrings({"ratelimit:tenant:", tenantId, ":resource:", gatewayPath})
end
-- Check subscription
if obj.subscription ~= nil and obj.subscription == true and apiKey ~= nil then
- k = utils.concatStrings({k, ':subscription:', apiKey})
+ k = utils.concatStrings({k, ":subscription:", apiKey})
end
- -- Perform rate limiting
- local config = {
- key = k,
- zone = 'rateLimiting',
- rate = r,
- interval = obj.interval,
- log_level = ngx.NOTICE,
- rds = {host = REDIS_HOST, port = REDIS_PORT, pass = REDIS_PASS}
- }
- local ok = req.limit(config)
- if not ok then
- logger.err('Rate limit exceeded. Sending 429')
- request.err(429, 'Rate limit exceeded.')
+ if red:get(k) == ngx.null then
+ red:set(k, "", "PX", math.floor(rate*1000))
+ else
+ return request.err(429, 'Rate limit exceeded')
end
end
diff --git a/scripts/lua/routing.lua b/scripts/lua/routing.lua
index 4098af6..fdb576c 100644
--- a/scripts/lua/routing.lua
+++ b/scripts/lua/routing.lua
@@ -57,7 +57,6 @@
end
local obj = cjson.decode(redis.getResource(red, redisKey, "resources"))
cors.processCall(obj)
- redis.close(red)
ngx.var.tenantNamespace = obj.tenantNamespace
ngx.var.tenantInstance = obj.tenantInstance
ngx.var.apiId = obj.apiId
@@ -68,8 +67,8 @@
if (opFields.security) then
for _, sec in ipairs(opFields.security) do
local result = security.process(sec)
- if key == nil then
- key = result -- use the key from the first policy.
+ if key == nil and sec.type ~= "oauth2" then
+ key = result -- use key from either apiKey or clientSecret security policy
end
end
end
@@ -81,12 +80,13 @@
backendRouting.setRoute(opFields.backendUrl)
-- Parse policies
if opFields.policies ~= nil then
- parsePolicies(opFields.policies, key)
+ parsePolicies(red, opFields.policies, key)
end
-- Log updated request headers/body info to access logs
if ngx.req.get_headers()["x-debug-mode"] == "true" then
setRequestLogs()
end
+ redis.close(red)
return
end
end
@@ -182,14 +182,15 @@
end
--- Function to read the list of policies and send implementation to the correct backend
+-- @param red redis client instance
-- @param obj List of policies containing a type and value field. This function reads the type field and routes it appropriately.
-- @param apiKey optional subscription api key
-function parsePolicies(obj, apiKey)
+function parsePolicies(red, obj, apiKey)
for k, v in pairs (obj) do
if v.type == 'reqMapping' then
mapping.processMap(v.value)
elseif v.type == 'rateLimit' then
- rateLimit.limit(v.value, apiKey)
+ rateLimit.limit(red, v.value, apiKey)
elseif v.type == 'backendRouting' then
backendRouting.setDynamicRoute(v.value)
end