Skip to content

Commit

Permalink
feat(aws-lambda) Add support for setting the unhandled response code
Browse files Browse the repository at this point in the history
Adds a new `unhandled_status` configuration option for the aws-lambda
plugin. If set the response status will be overridden if the
`X-Amzn-Function-Error` lambda invoke respoonse header was set to
`Unhandled`.

This gives a new feature to users of the plugin allowing their API to
return non 20x codes. The previous functionality of responding with
Amazon's Lambda Invoke unhandled response status of 200 (RequestResponse),
202 (Event), or 204 (DryRun) remains.
  • Loading branch information
erran committed Jun 1, 2017
1 parent 64eef14 commit 52779f2
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 1 deletion.
9 changes: 8 additions & 1 deletion kong/plugins/aws-lambda/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,14 @@ function AWSLambdaHandler:access(conf)
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
end

ngx.status = res.status
if conf.unhandled_status
and headers["X-Amzn-Function-Error"] == "Unhandled"
then
ngx.status = conf.unhandled_status

else
ngx.status = res.status
end

-- Send response to client
for k, v in pairs(headers) do
Expand Down
9 changes: 9 additions & 0 deletions kong/plugins/aws-lambda/schema.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
local function check_status(status)
if status and (status < 100 or status > 999) then
return false, "unhandled_status must be within 100 - 999."
end

return true
end

return {
fields = {
timeout = {type = "number", default = 60000, required = true },
Expand All @@ -14,5 +22,6 @@ return {
log_type = {type = "string", required = true, default = "Tail",
enum = {"Tail", "None"}},
port = { type = "number", default = 443 },
unhandled_status = { type = "number", func = check_status },
}
}
120 changes: 120 additions & 0 deletions spec/03-plugins/23-aws-lambda/01-access_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ describe("Plugin: AWS Lambda (access)", function()
upstream_url = "http://httpbin.org"
})

local api5 = assert(helpers.dao.apis:insert {
name = "lambda5.com",
hosts = { "lambda5.com" },
upstream_url = "http://httpbin.org"
})

local api6 = assert(helpers.dao.apis:insert {
name = "lambda6.com",
hosts = { "lambda6.com" },
upstream_url = "http://httpbin.org"
})

local api7 = assert(helpers.dao.apis:insert {
name = "lambda7.com",
hosts = { "lambda7.com" },
upstream_url = "http://httpbin.org"
})

local api8 = assert(helpers.dao.apis:insert {
name = "lambda8.com",
hosts = { "lambda8.com" },
upstream_url = "http://httpbin.org"
})

assert(helpers.dao.plugins:insert {
name = "aws-lambda",
api_id = api1.id,
Expand Down Expand Up @@ -79,6 +103,57 @@ describe("Plugin: AWS Lambda (access)", function()
}
})

assert(helpers.dao.plugins:insert {
name = "aws-lambda",
api_id = api5.id,
config = {
port = 10001,
aws_key = "mock-key",
aws_secret = "mock-secret",
aws_region = "us-east-1",
function_name = "functionWithUnhandledError",
}
})

assert(helpers.dao.plugins:insert {
name = "aws-lambda",
api_id = api6.id,
config = {
port = 10001,
aws_key = "mock-key",
aws_secret = "mock-secret",
aws_region = "us-east-1",
function_name = "functionWithUnhandledError",
invocation_type = "Event",
}
})

assert(helpers.dao.plugins:insert {
name = "aws-lambda",
api_id = api7.id,
config = {
port = 10001,
aws_key = "mock-key",
aws_secret = "mock-secret",
aws_region = "us-east-1",
function_name = "functionWithUnhandledError",
invocation_type = "DryRun",
}
})

assert(helpers.dao.plugins:insert {
name = "aws-lambda",
api_id = api8.id,
config = {
port = 10001,
aws_key = "mock-key",
aws_secret = "mock-secret",
aws_region = "us-east-1",
function_name = "functionWithUnhandledError",
unhandled_status = 412,
}
})

assert(helpers.start_kong{
nginx_conf = "spec/fixtures/custom_nginx.template",
})
Expand Down Expand Up @@ -109,6 +184,7 @@ describe("Plugin: AWS Lambda (access)", function()
local body = assert.res_status(200, res)
assert.is_string(res.headers["x-amzn-RequestId"])
assert.equal([["some_value1"]], body)
assert.is_nil(res.headers["X-Amzn-Function-Error"])
end)
it("invokes a Lambda function with POST params", function()
local res = assert(client:send {
Expand Down Expand Up @@ -208,4 +284,48 @@ describe("Plugin: AWS Lambda (access)", function()
assert.res_status(500, res)
end)

it("invokes a Lambda function with an unhandled function error (and no unhandled_status set)", function()
local res = assert(client:send {
method = "GET",
path = "/get?key1=some_value1&key2=some_value2&key3=some_value3",
headers = {
["Host"] = "lambda5.com"
}
})
assert.res_status(200, res)
assert.equal("Unhandled", res.headers["X-Amzn-Function-Error"])
end)
it("invokes a Lambda function with an unhandled function error with Event invocation type", function()
local res = assert(client:send {
method = "GET",
path = "/get?key1=some_value1&key2=some_value2&key3=some_value3",
headers = {
["Host"] = "lambda6.com"
}
})
assert.res_status(202, res)
assert.equal("Unhandled", res.headers["X-Amzn-Function-Error"])
end)
it("invokes a Lambda function with an unhandled function error with DryRun invocation type", function()
local res = assert(client:send {
method = "GET",
path = "/get?key1=some_value1&key2=some_value2&key3=some_value3",
headers = {
["Host"] = "lambda7.com"
}
})
assert.res_status(204, res)
assert.equal("Unhandled", res.headers["X-Amzn-Function-Error"])
end)
it("invokes a Lambda function with an unhandled function error", function()
local res = assert(client:send {
method = "GET",
path = "/get?key1=some_value1&key2=some_value2&key3=some_value3",
headers = {
["Host"] = "lambda8.com"
}
})
assert.res_status(412, res)
assert.equal("Unhandled", res.headers["X-Amzn-Function-Error"])
end)
end)
46 changes: 46 additions & 0 deletions spec/03-plugins/23-aws-lambda/02-schema_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
local aws_lambda_schema = require "kong.plugins.aws-lambda.schema"
local schemas = require "kong.dao.schemas_validation"
local utils = require "kong.tools.utils"
local validate_entity = schemas.validate_entity

describe("Plugin: AWS Lambda (schema)", function()
local DEFAULTS = {
timeout = 60000,
keepalive = 60000,
aws_key = "my-key",
aws_secret = "my-secret",
aws_region = "us-east-1",
function_name = "my-function",
invocation_type = "RequestResponse",
log_type = "Tail",
port = 443,
}

it("accepts nil Unhandled Response Status Code", function()
local entity = utils.table_merge(DEFAULTS, { unhandled_status = nil })
local ok, err = validate_entity(entity, aws_lambda_schema)
assert.is_nil(err)
assert.True(ok)
end)

it("accepts correct Unhandled Response Status Code", function()
local entity = utils.table_merge(DEFAULTS, { unhandled_status = 412 })
local ok, err = validate_entity(entity, aws_lambda_schema)
assert.is_nil(err)
assert.True(ok)
end)

it("errors with Unhandled Response Status Code less than 100", function()
local entity = utils.table_merge(DEFAULTS, { unhandled_status = 99 })
local ok, err = validate_entity(entity, aws_lambda_schema)
assert.equal("unhandled_status must be within 100 - 999.", err.unhandled_status)
assert.False(ok)
end)

it("errors with Unhandled Response Status Code greater than 999", function()
local entity = utils.table_merge(DEFAULTS, { unhandled_status = 1000 })
local ok, err = validate_entity(entity, aws_lambda_schema)
assert.equal("unhandled_status must be within 100 - 999.", err.unhandled_status)
assert.False(ok)
end)
end)
3 changes: 3 additions & 0 deletions spec/fixtures/custom_nginx.template
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ http {
content_by_lua_block {
local function say(res, status)
ngx.header["x-amzn-RequestId"] = "foo"
if string.match(ngx.var.uri, "functionWithUnhandledError") then
ngx.header["X-Amzn-Function-Error"] = "Unhandled"
end
ngx.status = status

if type(res) == 'string' then
Expand Down

0 comments on commit 52779f2

Please sign in to comment.