scripts/lua/management/lib/swagger.lua (221 lines of code) (raw):

-- -- Licensed to the Apache Software Foundation (ASF) under one or more -- contributor license agreements. See the NOTICE file distributed with -- this work for additional information regarding copyright ownership. -- The ASF licenses this file to You under the Apache License, Version 2.0 -- (the "License"); you may not use this file except in compliance with -- the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- --- @module swagger -- Module for parsing swagger file local utils = require "lib/utils" local _M = {} --- Parse request mapping local function parseRequestMapping(configObj) local valueList = {} 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 local fromValue = actionObj.value local toParsedArray = {string.match(actionObj.set, "([^.]+).([^.]+).([^.]+)") } local toName = toParsedArray[3] local toLocation = toParsedArray[2] toLocation = toLocation == "headers" and "header" or toLocation valueList[#valueList+1] = { action = "insert", from = { value = fromValue }, to = { name = toName, location = toLocation } } end end end end end if next(valueList) ~= nil then return { type = "reqMapping", value = valueList } else return nil end end --- Parse backendUrl and backendMethod -- @param swagger swagger file to parse local function parseBackends(swagger) local configObj = swagger["x-gateway-configuration"] configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj if configObj ~= nil then for _, obj in pairs(configObj.assembly.execute) do for policy, v in pairs(obj) do local res = {} if policy == "operation-switch" then local caseObj = v.case for _, case in pairs(caseObj) do for _, op in pairs(case.operations) do 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 end if policy == "invoke" then res["all"] = { backendUrl = v["target-url"], backendMethod = v.verb } return res end end end end end --- Parse rate limit local function parseRateLimit(rlObj) if rlObj ~= nil and rlObj[1] ~= nil then local unit rlObj = rlObj[1] if rlObj.unit == "second" then unit = 1 elseif rlObj.unit == "minute" then unit = 60 elseif rlObj.unit == "hour" then unit = 3600 elseif rlObj.unit == "day" then unit = 86400 else unit = 60 -- default to minute end return { type = "rateLimit", value = { interval = unit * rlObj.units, rate = rlObj.rate, scope = "api", subscription = true } } end return nil end --- Parse policies in swagger -- @param swagger swagger file to parse local function parsePolicies(swagger) local policies = {} -- parse rate limit 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 security in swagger -- @param swagger swagger file to parse local function parseSecurity(swagger) local security = {} if swagger["securityDefinitions"] ~= nil then local secObject = swagger["securityDefinitions"] if utils.tableLength(secObject) == 2 then local 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 return security end local function parseCors(swagger) local cors = { origin = nil, methods = nil } local configObj = swagger["x-gateway-configuration"] configObj = (configObj == nil) and swagger["x-ibm-configuration"] or configObj if configObj.cors ~= nil then if configObj.cors.enabled == true then cors.origin = "true" elseif configObj.cors.enabled == false then cors.origin = "false" end return cors end return nil end -- Convert passed-in swagger body to valid lua table -- @param swagger swagger file to parse function _M.parseSwagger(swagger) local backends = parseBackends(swagger) local policies = parsePolicies(swagger) local security = parseSecurity(swagger) local corsObj = parseCors(swagger) local decoded = { name = swagger.info.title, basePath = swagger.basePath, resources = {} } for path, verbObj in pairs(swagger.paths) do decoded.resources[path] = { operations = {} } decoded.resources[path].cors = corsObj 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 end end return decoded end return _M