Add support for set-variable in operation-switch (#282)
diff --git a/scripts/lua/lib/utils.lua b/scripts/lua/lib/utils.lua
index 2b3cb37..e9c2977 100644
--- a/scripts/lua/lib/utils.lua
+++ b/scripts/lua/lib/utils.lua
@@ -117,4 +117,28 @@
return resty_str.to_hex(digest)
end
+--- Return the length of the table
+-- @param table
+function _Utils.tableLength(table)
+ local count = 0
+ for _ in pairs(table) do
+ count = count + 1
+ end
+ return count
+end
+
+--- Create a deep clone of the given table
+-- @param table table to clone
+function _Utils.deepCloneTable(table)
+ local tblRes = {}
+ if type(table) == "table" then
+ for k,v in pairs(table) do
+ tblRes[k] = _Utils.deepCloneTable(v)
+ end
+ else
+ tblRes = table
+ end
+ return tblRes
+end
+
return _Utils
diff --git a/scripts/lua/management/lib/swagger.lua b/scripts/lua/management/lib/swagger.lua
index 5d5c737..4a63ab6 100644
--- a/scripts/lua/management/lib/swagger.lua
+++ b/scripts/lua/management/lib/swagger.lua
@@ -19,6 +19,7 @@
-- Module for parsing swagger file
local _M = {}
+local utils = require "lib/utils"
-- Convert passed-in swagger body to valid lua table
-- @param swagger swagger file to parse
@@ -38,16 +39,34 @@
for verb, value in pairs(verbObj) do
decoded.resources[path].operations[verb] = {}
local verbObj = decoded.resources[path].operations[verb]
+ verbObj.policies = utils.deepCloneTable(policies) or {}
+ verbObj.security = security
if backends ~= nil then
local backend = (backends["all"] ~= nil) and backends["all"] or backends[value.operationId]
verbObj.backendUrl = backend.backendUrl
verbObj.backendMethod = (backend.backendMethod == 'keep') and verb or backend.backendMethod
+ if backend.policy ~= nil then
+ local globalReqMappingPolicy = nil;
+ for _, policy in pairs(verbObj.policies) do
+ if policy.type == 'reqMapping' then
+ globalReqMappingPolicy = policy;
+ end
+ end
+ if globalReqMappingPolicy ~= nil then
+ for _, v in pairs(backend.policy.value) do
+ globalReqMappingPolicy.value[#globalReqMappingPolicy.value+1] = v
+ end
+ else
+ verbObj.policies[#verbObj.policies+1] = {
+ type = 'reqMapping',
+ value = backend.policy.value
+ }
+ end
+ end
else
verbObj.backendUrl = ''
verbObj.backendMethod = verb
end
- verbObj.policies = policies
- verbObj.security = security
end
end
return decoded
@@ -66,10 +85,18 @@
local caseObj = v.case
for _, case in pairs(caseObj) do
for _, op in pairs(case.operations) do
- res[op] = {
- backendUrl = case.execute[1]["invoke"]["target-url"],
- backendMethod = case.execute[1]["invoke"].verb
- }
+ res[op] = {}
+ for _, opPolicy in pairs(case.execute) do
+ if opPolicy.invoke ~= nil then
+ res[op].backendUrl = opPolicy.invoke["target-url"]
+ res[op].backendMethod = opPolicy.invoke.verb
+ elseif opPolicy["set-variable"] ~= nil then
+ local reqMappingPolicy = parseRequestMapping(case)
+ if reqMappingPolicy ~= nil then
+ res[op].policy = reqMappingPolicy
+ end
+ end
+ end
end
end
return res
@@ -91,17 +118,27 @@
function parsePolicies(swagger)
local policies = {}
-- parse rate limit
- policies = parseRateLimit(swagger, policies)
- policies = parseRequestMapping(swagger, policies)
+ local rlObj = swagger["x-gateway-rate-limit"]
+ rlObj = (rlObj == nil) and swagger["x-ibm-rate-limit"] or rlObj
+ local rateLimitPolicy = parseRateLimit(rlObj)
+ if rateLimitPolicy ~= nil then
+ policies[#policies+1] = rateLimitPolicy
+ end
+ -- parse set-variable
+ local configObj = swagger["x-gateway-configuration"]
+ configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj
+ if configObj ~= nil then
+ local reqMappingPolicy = parseRequestMapping(configObj.assembly)
+ if reqMappingPolicy ~= nil then
+ policies[#policies+1] = reqMappingPolicy
+ end
+ end
return policies
end
--- Parse rate limit
-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
+function parseRateLimit(rlObj)
+ if rlObj ~= nil and rlObj[1] ~= nil then
rlObj = rlObj[1]
if rlObj.unit == "second" then
unit = 1
@@ -114,7 +151,7 @@
else
unit = 60 -- default to minute
end
- policies[#policies+1] = {
+ return {
type = "rateLimit",
value = {
interval = unit * rlObj.units,
@@ -124,14 +161,14 @@
}
}
end
- return policies
+ return nil
end
--- Parse request mapping
-function parseRequestMapping(swagger, policies)
+function parseRequestMapping(configObj)
local valueList = {}
- if swagger["x-ibm-configuration"] ~= nil then
- for _, obj in pairs(swagger["x-ibm-configuration"].assembly.execute) do
+ if configObj ~= nil then
+ for _, obj in pairs(configObj.execute) do
for policy, v in pairs(obj) do
if policy == "set-variable" then
for _, actionObj in pairs(v.actions) do
@@ -156,12 +193,13 @@
end
end
if next(valueList) ~= nil then
- policies[#policies+1] ={
+ return {
type = "reqMapping",
value = valueList
}
+ else
+ return nil
end
- return policies
end
--- Parse security in swagger
@@ -170,19 +208,34 @@
local security = {}
if swagger["securityDefinitions"] ~= nil then
local secObject = swagger["securityDefinitions"]
- for key, sec in pairs(secObject) do
- if sec.type == 'apiKey' then
- security[#security+1] = {
- type = sec.type,
- scope = "api",
- header = sec.name
- }
- elseif sec.type == 'oauth2' then
- security[#security+1] = {
- type = sec.type,
- scope = "api",
- provider = key
- }
+ if utils.tableLength(secObject) == 2 then
+ secObj = {
+ type = 'clientSecret',
+ scope = 'api'
+ }
+ for key, sec in pairs(secObject) do
+ if key == 'client_id' then
+ secObj.idFieldName = sec.name
+ elseif key == 'client_secret' then
+ secObj.secretFieldName = sec.name
+ end
+ end
+ security[#security+1] = secObj
+ else
+ for key, sec in pairs(secObject) do
+ if sec.type == 'apiKey' then
+ security[#security+1] = {
+ type = sec.type,
+ scope = "api",
+ header = sec.name
+ }
+ elseif sec.type == 'oauth2' then
+ security[#security+1] = {
+ type = sec.type,
+ scope = "api",
+ provider = key
+ }
+ end
end
end
end
diff --git a/tests/scripts/lua/management/examples/example2.json b/tests/scripts/lua/management/examples/example2.json
index 47794c6..db02482 100644
--- a/tests/scripts/lua/management/examples/example2.json
+++ b/tests/scripts/lua/management/examples/example2.json
@@ -62,7 +62,7 @@
"rate": 100
}
],
- "x-ibm-configuration": {
+ "x-gateway-configuration": {
"assembly": {
"execute": [
{
@@ -84,6 +84,16 @@
],
"execute": [
{
+ "set-variable": {
+ "actions": [
+ {
+ "set": "message.headers.foo",
+ "value": "bar"
+ }
+ ]
+ }
+ },
+ {
"invoke": {
"target-url": "https://openwhisk.ng.bluemix.net/api/some/action/path.http",
"verb": "keep"
diff --git a/tests/scripts/lua/management/examples/example3.json b/tests/scripts/lua/management/examples/example3.json
new file mode 100644
index 0000000..bd3b344
--- /dev/null
+++ b/tests/scripts/lua/management/examples/example3.json
@@ -0,0 +1,102 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "version": "1.0",
+ "title": "Hello World API"
+ },
+ "basePath": "/whisk2",
+ "schemes": [
+ "https"
+ ],
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "paths": {
+ "/bye": {
+ "get": {
+ "operationId": "getBye",
+ "description": "Returns a greeting to the user!",
+ "responses": {
+ "200": {
+ "description": "Returns the greeting.",
+ "schema": {
+ "type": "string"
+ }
+ },
+ "400": {
+ "description": "Invalid characters in \"user\" were provided."
+ }
+ }
+ },
+ "post": {
+ "operationId": "postBye",
+ "description": null
+ }
+ }
+ },
+ "securityDefinitions": {},
+ "security": [],
+ "x-ibm-rate-limit": [],
+ "x-gateway-configuration": {
+ "assembly": {
+ "execute": [
+ {
+ "operation-switch": {
+ "case": [
+ {
+ "operations": [
+ "getBye"
+ ],
+ "execute": [
+ {
+ "set-variable": {
+ "actions": [
+ {
+ "set": "message.headers.foo",
+ "value": "bar"
+ }
+ ]
+ }
+ },
+ {
+ "set-variable": {
+ "actions": [
+ {
+ "set": "message.headers.hello",
+ "value": "world"
+ }
+ ]
+ }
+ },
+ {
+ "invoke": {
+ "target-url": "https://openwhisk.ng.bluemix.net/api/some/action/path.http",
+ "verb": "keep"
+ }
+ }
+ ]
+ },
+ {
+ "operations": [
+ "postBye"
+ ],
+ "execute": [
+ {
+ "invoke": {
+ "target-url": "https://openwhisk.ng.bluemix.net/api/user@us.ibm.com/demo/createuser",
+ "verb": "keep"
+ }
+ }
+ ]
+ }
+ ],
+ "otherwise": []
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/scripts/lua/management/lib/swagger.lua b/tests/scripts/lua/management/lib/swagger.lua
index cf9a565..0860667 100644
--- a/tests/scripts/lua/management/lib/swagger.lua
+++ b/tests/scripts/lua/management/lib/swagger.lua
@@ -80,7 +80,7 @@
"type": "rateLimit",
"value": {
"scope": "api",
- "subscription": "true",
+ "subscription": true,
"interval": 180,
"rate": 100
}
@@ -116,35 +116,43 @@
"type": "rateLimit",
"value": {
"scope": "api",
- "subscription": "true",
+ "subscription": true,
"interval": 180,
"rate": 100
}
},
{
"type": "reqMapping",
- "value": [{
- "from": {
- "value": "Basic xxx"
+ "value": [
+ {
+ "from": {
+ "value": "Basic xxx"
+ },
+ "to": {
+ "name": "Authorization",
+ "location": "header"
+ },
+ "action": "insert"
},
- "to": {
- "name": "Authorization",
- "location": "header"
- },
- "action": "insert"
- }]
+ {
+ "from": {
+ "value": "bar"
+ },
+ "to": {
+ "name": "foo",
+ "location": "header"
+ },
+ "action": "insert"
+ }
+ ]
}
],
"security": [
{
- "type": "oauth2",
- "provider": "google",
- "scope": "api"
- },
- {
- "type": "apiKey",
- "header": "X-Api-Key",
- "scope": "api"
+ "type": "clientSecret",
+ "scope": "api",
+ "idFieldName":"X-Api-Key",
+ "secretFieldName":"X-Api-Secret"
}
],
"backendMethod": "get"
@@ -157,7 +165,64 @@
local jsonPath = exampleBasePath .. 'example2.json'
local jsonTable = loadJsonTable(jsonPath)
local actual = swagger.parseSwagger(jsonTable)
- assert.are.same(expected.resources["/hello"].operations.post.policies[2].value, actual.resources["/hello"].operations.post.policies[2].value)
+ assert.are.same(expected, actual)
+ end)
+
+ it('should parse set-variable policy within operation-switch correctly', function()
+ local expected = cjson.decode([[
+ {
+ "basePath": "/whisk2",
+ "name": "Hello World API",
+ "resources": {
+ "/bye": {
+ "operations": {
+ "post": {
+ "backendUrl": "https://openwhisk.ng.bluemix.net/api/user@us.ibm.com/demo/createuser",
+ "policies": [],
+ "security": [],
+ "backendMethod": "post"
+ },
+ "get": {
+ "backendUrl": "https://openwhisk.ng.bluemix.net/api/some/action/path.http",
+ "policies": [
+ {
+ "type": "reqMapping",
+ "value": [
+ {
+ "from": {
+ "value": "bar"
+ },
+ "to": {
+ "name": "foo",
+ "location": "header"
+ },
+ "action": "insert"
+ },
+ {
+ "from": {
+ "value": "world"
+ },
+ "to": {
+ "name": "hello",
+ "location": "header"
+ },
+ "action": "insert"
+ }
+ ]
+ }
+ ],
+ "security": [],
+ "backendMethod": "get"
+ }
+ }
+ }
+ }
+ }
+ ]])
+ local jsonPath = exampleBasePath .. 'example3.json'
+ local jsonTable = loadJsonTable(jsonPath)
+ local actual = swagger.parseSwagger(jsonTable)
+ assert.are.same(expected, actual)
end)
end)